-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRequestContextExtensions.cs
309 lines (271 loc) · 15.3 KB
/
RequestContextExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
// 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
{
/// <summary>
/// RequestContext extensions.
/// </summary>
public static class RequestContextExtensions
{
/// <summary>
/// Array of valid proxy schemes
/// </summary>
private static string[] ProxySchemes = new string[] { "http", "socks", "socks4", "socks5" };
/// <summary>
/// Load an extension from the given directory. To load a crx file you must unzip it first.
/// For further details see <seealso cref="IRequestContext.LoadExtension(string, string, IExtensionHandler)"/>
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="rootDirectory">absolute path to the directory that contains the extension to be loaded.</param>
/// <param name="handler">handle events related to browser extensions</param>
public static void LoadExtensionFromDirectory(this IRequestContext requestContext, string rootDirectory, IExtensionHandler handler)
{
requestContext.LoadExtension(Path.GetFullPath(rootDirectory), null, handler);
}
/// <summary>
/// Load extension(s) from the given directory. This methods obtains all the sub directories of <paramref name="rootDirectory"/>
/// and calls <see cref="IRequestContext.LoadExtension(string, string, IExtensionHandler)"/> if manifest.json
/// is found in the sub folder. To load crx file(s) you must unzip them first.
/// For further details see <seealso cref="IRequestContext.LoadExtension(string, string, IExtensionHandler)"/>
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="rootDirectory">absolute path to the directory that contains the extension(s) to be loaded.</param>
/// <param name="handler">handle events related to browser extensions</param>
public static void LoadExtensionsFromDirectory(this IRequestContext requestContext, string rootDirectory, IExtensionHandler handler)
{
var fullPath = Path.GetFullPath(rootDirectory);
foreach (var dir in Directory.GetDirectories(fullPath))
{
//Check the directory has a manifest.json, if so call load
if (File.Exists(Path.Combine(dir, "manifest.json")))
{
requestContext.LoadExtension(dir, null, handler);
}
}
}
/// <summary>
/// Gets the cookie manager associated with the <see cref="IRequestContext"/>. Once the cookie manager
/// storage has been initialized the method will return.
/// </summary>
/// <exception cref="Exception">Thrown when an exception error condition occurs.</exception>
/// <param name="requestContext">The <see cref="IRequestContext"/> instance this method extends.</param>
/// <returns>returns <see cref="ICookieManager"/> if the store was successfully loaded otherwise null. </returns>
public static async Task<ICookieManager> 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;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="name">preference key</param>
/// <param name="value">preference value</param>
/// <returns>returns <see cref="SetPreferenceResponse.Success"/> true if successfull, false otherwise.</returns>
/// <remarks>Use Cef.UIThreadTaskFactory to execute this method if required,
/// <see cref="IBrowserProcessHandler.OnContextInitialized"/> 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.</remarks>
public static Task<SetPreferenceResponse> 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<SetPreferenceResponse> 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);
}
/// <summary>
/// Sets the proxy server for the specified <see cref="IRequestContext"/>.
/// Protocol for the proxy server is http
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="host">proxy host</param>
/// <param name="port">proxy port</param>
/// <returns>returns <see cref="SetPreferenceResponse.Success"/> true if successfull, false otherwise.</returns>
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
public static Task<SetProxyResponse> SetProxyAsync(this IRequestContext requestContext, string host, int? port)
{
return requestContext.SetProxyAsync(null, host, port);
}
/// <summary>
/// Sets the proxy server for the specified <see cref="IRequestContext"/>
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="scheme">is the protocol of the proxy server, and is one of: 'http', 'socks', 'socks4', 'socks5'. Also note that 'socks' is equivalent to 'socks5'.</param>
/// <param name="host">proxy host</param>
/// <param name="port">proxy port</param>
/// <returns>returns <see cref="SetPreferenceResponse.Success"/> true if successfull, false otherwise.</returns>
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
public static Task<SetProxyResponse> 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<SetProxyResponse> 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);
}
/// <summary>
/// Sets the proxy server for the specified <see cref="IRequestContext"/>
/// MUST be called on the CEF UI Thread
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="scheme">is the protocol of the proxy server, and is one of: 'http', 'socks', 'socks4', 'socks5'. Also note that 'socks' is equivalent to 'socks5'.</param>
/// <param name="host">proxy host</param>
/// <param name="port">proxy port</param>
/// <param name="errorMessage">error message</param>
/// <returns>returns true if successfull, false otherwise.</returns>
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
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.");
}
/// <summary>
/// Sets the proxy server for the specified <see cref="IRequestContext"/>.
/// Protocol for the proxy server is http
/// MUST be called on the CEF UI Thread
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="host">proxy host</param>
/// <param name="port">proxy port</param>
/// <param name="errorMessage">error message</param>
/// <returns>returns true if successfull, false otherwise.</returns>
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
public static bool SetProxy(this IRequestContext requestContext, string host, int? port, out string errorMessage)
{
return requestContext.SetProxy(null, host, port, out errorMessage);
}
/// <summary>
/// Sets the proxy server for the specified <see cref="IRequestContext"/>.
/// Protocol for the proxy server is http
/// MUST be called on the CEF UI Thread
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="host">proxy host</param>
/// <param name="errorMessage">error message</param>
/// <returns>returns true if successfull, false otherwise.</returns>
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
public static bool SetProxy(this IRequestContext requestContext, string host, out string errorMessage)
{
return requestContext.SetProxy(null, host, null, out errorMessage);
}
/// <summary>
/// Creates a Dictionary that can be used with <see cref="IRequestContext.SetPreference(string, object, out string)"/>
/// </summary>
/// <param name="scheme">is the protocol of the proxy server, and is one of: 'http', 'socks', 'socks4', 'socks5'. Also note that 'socks' is equivalent to 'socks5'.</param>
/// <param name="host">proxy host</param>
/// <param name="port">proxy port</param>
/// <returns></returns>
public static IDictionary<string, object> 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<string, object>
{
["mode"] = "fixed_servers",
["server"] = scheme + "://" + host + (port.HasValue ? (":" + port) : "")
};
return dict;
}
/// <summary>
/// Clears all HTTP authentication credentials that were added as part of handling
/// <see cref="IRequestHandler.GetAuthCredentials(IWebBrowser, IBrowser, string, bool, string, int, string, string, IAuthCallback)"/>.
/// </summary>
/// <param name="requestContext">request context</param>
/// <returns>A task that represents the ClearHttpAuthCredentials operation.
/// Result indicates if the credentials cleared successfully.</returns>
public static Task<bool> ClearHttpAuthCredentialsAsync(this IRequestContext requestContext)
{
var handler = new TaskCompletionCallback();
requestContext.ClearHttpAuthCredentials(handler);
return handler.Task;
}
/// <summary>
/// Extension method to register a instance of the <see cref="OwinSchemeHandlerFactory"/> with the provided <paramref name="appFunc"/>
/// for the <paramref name="domainName"/>
/// </summary>
/// <param name="requestContext">request context</param>
/// <param name="schemeName">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.</param>
/// <param name="domainName">Optional domain name</param>
/// <param name="appFunc">OWIN AppFunc as defined at owin.org</param>
public static void RegisterOwinSchemeHandlerFactory(this IRequestContext requestContext, string schemeName, string domainName, Func<IDictionary<string, object>, Task> appFunc)
{
requestContext.RegisterSchemeHandlerFactory(schemeName, domainName, new OwinSchemeHandlerFactory(appFunc));
}
}
}