Skip to content

Commit b4c2e35

Browse files
committed
Core - Improve IRequestContext.SetProxy extension Method
- Add tests - Add better validation Issue #3235
1 parent b0ee2f2 commit b4c2e35

File tree

4 files changed

+116
-14
lines changed

4 files changed

+116
-14
lines changed

CefSharp.Core.RefAssembly/CefSharp.Core.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public static void EnableWaitForBrowsersToClose() { }
7777
public static string GetMimeType(string extension) { throw null; }
7878
public static System.Threading.Tasks.Task<System.Collections.Generic.List<CefSharp.WebPluginInfo>> GetPlugins() { throw null; }
7979
public static bool Initialize(CefSharp.CefSettingsBase cefSettings) { throw null; }
80+
public static bool Initialize(CefSharp.CefSettingsBase cefSettings, bool performDependencyCheck) { throw null; }
8081
public static bool Initialize(CefSharp.CefSettingsBase cefSettings, bool performDependencyCheck, CefSharp.IApp cefApp) { throw null; }
8182
public static bool Initialize(CefSharp.CefSettingsBase cefSettings, bool performDependencyCheck, CefSharp.IBrowserProcessHandler browserProcessHandler) { throw null; }
8283
public static void PreShutdown() { }

CefSharp.Test/CefSharp.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
<Compile Include="Framework\LegacyCamelCaseJavascriptNameConverterFacts.cs" />
134134
<Compile Include="Framework\MimeTypeMappingFacts.cs" />
135135
<Compile Include="Framework\PathCheckFacts.cs" />
136+
<Compile Include="Framework\RequestContextExtensionFacts.cs" />
136137
<Compile Include="Framework\TestMemberInfo.cs" />
137138
<Compile Include="JavascriptBinding\IntegrationTestFacts.cs" />
138139
<Compile Include="OffScreen\OffScreenBrowserBasicFacts.cs" />
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright © 2020 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using Moq;
8+
using Xunit;
9+
using Xunit.Abstractions;
10+
11+
namespace CefSharp.Test.Framework
12+
{
13+
public class RequestContextExtensionFacts
14+
{
15+
private const string ProxyPreferenceKey = "proxy";
16+
17+
private readonly ITestOutputHelper output;
18+
19+
private delegate void SetPreferenceDelegate(string name, object value, out string errorMessage);
20+
21+
public RequestContextExtensionFacts(ITestOutputHelper output)
22+
{
23+
this.output = output;
24+
}
25+
26+
[Theory]
27+
[InlineData("http", "localhost", 8080, "http://localhost:8080")]
28+
[InlineData("socks", "localhost", null, "socks://localhost")]
29+
[InlineData(null, "localhost", null, "http://localhost")]
30+
public void CanSetProxyWithSchemeHostAndPort(string scheme, string host, int? port, string expected)
31+
{
32+
string preferenceName = "";
33+
object preferenceValue = null;
34+
var mockRequestContext = new Mock<IRequestContext>();
35+
36+
mockRequestContext.Setup(x => x.SetPreference(ProxyPreferenceKey, It.IsAny<IDictionary<string, object>>(), out It.Ref<string>.IsAny))
37+
.Callback(new SetPreferenceDelegate((string name, object value, out string errorMessage) =>
38+
{
39+
preferenceName = name;
40+
preferenceValue = value;
41+
errorMessage = "OK";
42+
}))
43+
.Returns(true);
44+
45+
string msg;
46+
47+
var result = mockRequestContext.Object.SetProxy(scheme, host, port, out msg);
48+
var dict = (Dictionary<string, object>)preferenceValue;
49+
50+
Assert.True(result);
51+
Assert.Equal("OK", msg);
52+
Assert.Equal(ProxyPreferenceKey, preferenceName);
53+
Assert.Equal(2, dict.Count);
54+
Assert.Equal("fixed_servers", dict["mode"]);
55+
Assert.Equal(expected, dict["server"]);
56+
}
57+
58+
[Fact]
59+
public void SetProxyThrowsExceptionOnInvalidScheme()
60+
{
61+
var mockRequestContext = new Mock<IRequestContext>();
62+
63+
mockRequestContext.Setup(x => x.SetPreference(ProxyPreferenceKey, It.IsAny<IDictionary<string, object>>(), out It.Ref<string>.IsAny)) .Returns(true);
64+
65+
Assert.Throws<ArgumentException>(() =>
66+
{
67+
string msg;
68+
mockRequestContext.Object.SetProxy("myscheme", "localhost", 0, out msg);
69+
});
70+
}
71+
}
72+
}

CefSharp/RequestContextExtensions.cs

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using System;
66
using System.Collections.Generic;
77
using System.IO;
8+
using System.Linq;
9+
using System.Net;
810
using System.Threading.Tasks;
911

1012
namespace CefSharp
@@ -14,6 +16,11 @@ namespace CefSharp
1416
/// </summary>
1517
public static class RequestContextExtensions
1618
{
19+
/// <summary>
20+
/// Array of valid proxy schemes
21+
/// </summary>
22+
private static string[] ProxySchemes = new string[] { "http", "socks", "socks4", "socks5" };
23+
1724
/// <summary>
1825
/// Load an extension from the given directory. To load a crx file you must unzip it first.
1926
/// For further details see <seealso cref="IRequestContext.LoadExtension(string, string, IExtensionHandler)"/>
@@ -55,34 +62,39 @@ public static void LoadExtensionsFromDirectory(this IRequestContext requestConte
5562
/// </summary>
5663
/// <param name="requestContext">request context</param>
5764
/// <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>
58-
/// <param name="host">host</param>
59-
/// <param name="port">post</param>
65+
/// <param name="host">proxy host</param>
66+
/// <param name="port">proxy port</param>
6067
/// <param name="errorMessage">error message</param>
6168
/// <returns>returns true if successfull, false otherwise.</returns>
6269
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
6370
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
64-
public static bool SetProxy(this IRequestContext requestContext, string scheme, string host, string port, out string errorMessage)
71+
public static bool SetProxy(this IRequestContext requestContext, string scheme, string host, int? port, out string errorMessage)
6572
{
66-
if (string.IsNullOrWhiteSpace(host))
73+
//Default to using http scheme if non provided
74+
if (string.IsNullOrWhiteSpace(scheme))
6775
{
68-
throw new ArgumentException("Cannot be null or empty", "host");
76+
scheme = "http";
6977
}
7078

71-
if (string.IsNullOrWhiteSpace(port))
79+
if (!ProxySchemes.Contains(scheme.ToLower()))
7280
{
73-
throw new ArgumentException("Cannot be null or empty", port);
81+
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");
7482
}
7583

76-
//Default to using http scheme if non provided
77-
if (string.IsNullOrWhiteSpace(scheme))
84+
if (string.IsNullOrWhiteSpace(host))
7885
{
79-
scheme = "http";
86+
throw new ArgumentException("Cannot be null or empty", "host");
87+
}
88+
89+
if (port.HasValue && (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort))
90+
{
91+
throw new ArgumentOutOfRangeException("port", port, "Invalid TCP Port");
8092
}
8193

8294
var v = new Dictionary<string, object>
8395
{
8496
["mode"] = "fixed_servers",
85-
["server"] = scheme + "://" + host + ":" + port
97+
["server"] = scheme + "://" + host + (port.HasValue ? (":" + port) : "")
8698
};
8799

88100
return requestContext.SetPreference("proxy", v, out errorMessage);
@@ -94,17 +106,33 @@ public static bool SetProxy(this IRequestContext requestContext, string scheme,
94106
/// MUST be called on the CEF UI Thread
95107
/// </summary>
96108
/// <param name="requestContext">request context</param>
97-
/// <param name="host">host</param>
98-
/// <param name="port">post</param>
109+
/// <param name="host">proxy host</param>
110+
/// <param name="port">proxy port</param>
99111
/// <param name="errorMessage">error message</param>
100112
/// <returns>returns true if successfull, false otherwise.</returns>
101113
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
102114
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
103-
public static bool SetProxy(this IRequestContext requestContext, string host, string port, out string errorMessage)
115+
public static bool SetProxy(this IRequestContext requestContext, string host, int? port, out string errorMessage)
104116
{
105117
return requestContext.SetProxy(null, host, port, out errorMessage);
106118
}
107119

120+
/// <summary>
121+
/// Sets the proxy server for the specified <see cref="IRequestContext"/>.
122+
/// Protocol for the proxy server is http
123+
/// MUST be called on the CEF UI Thread
124+
/// </summary>
125+
/// <param name="requestContext">request context</param>
126+
/// <param name="host">proxy host</param>
127+
/// <param name="errorMessage">error message</param>
128+
/// <returns>returns true if successfull, false otherwise.</returns>
129+
/// <remarks>Internally calls <seealso cref="IRequestContext.SetPreference(string, object, out string)"/> with
130+
/// preference 'proxy' and mode of 'fixed_servers'</remarks>
131+
public static bool SetProxy(this IRequestContext requestContext, string host, out string errorMessage)
132+
{
133+
return requestContext.SetProxy(null, host, null, out errorMessage);
134+
}
135+
108136
/// <summary>
109137
/// Clears all HTTP authentication credentials that were added as part of handling
110138
/// <see cref="IRequestHandler.GetAuthCredentials(IWebBrowser, IBrowser, string, bool, string, int, string, string, IAuthCallback)"/>.

0 commit comments

Comments
 (0)