Skip to content

Commit 04a4868

Browse files
committed
Adding proxy support to HTTP
1 parent f6ba5e2 commit 04a4868

File tree

13 files changed

+493
-88
lines changed

13 files changed

+493
-88
lines changed

src/Common/test-runtime/project.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"xunit.console.netcore": "1.0.3-prerelease-00925-01",
1313
"Microsoft.xunit.netcore.extensions": "1.0.1-prerelease-01001-04",
1414
"System.Reflection.DispatchProxy": "4.4.0-preview2-25309-01",
15+
"System.Net.Http.WinHttpHandler": "4.4.0-preview2-25309-01",
1516
"System.ServiceModel.Duplex": "4.4.0-preview1-25302-01",
1617
"System.ServiceModel.Http": "4.4.0-preview1-25302-01",
1718
"System.ServiceModel.NetTcp": "4.4.0-preview1-25302-01",
@@ -38,6 +39,7 @@
3839
"System.Linq.Parallel": "4.4.0-beta-24911-02",
3940
"System.Linq.Queryable": "4.4.0-beta-24911-02",
4041
"System.Net.Http": "4.4.0-preview1-25218-03",
42+
"System.Net.Http.WinHttpHandler": "4.4.0-preview2-25309-01",
4143
"System.Net.WebHeaderCollection": "4.4.0-beta-24911-02",
4244
"System.Net.WebSockets.Client": "4.4.0-beta-24911-02",
4345
"System.Reflection.DispatchProxy": "4.4.0-preview2-25309-01",
@@ -73,6 +75,7 @@
7375
"System.Linq.Parallel": "4.4.0-beta-24911-02",
7476
"System.Linq.Queryable": "4.4.0-beta-24911-02",
7577
"System.Net.Http": "4.4.0-preview1-25218-03",
78+
"System.Net.Http.WinHttpHandler": "4.4.0-preview2-25309-01",
7679
"System.Net.WebHeaderCollection": "4.4.0-beta-24911-02",
7780
"System.Net.WebSockets.Client": "4.4.0-beta-24911-02",
7881
"System.Reflection.DispatchProxy": "4.4.0-preview2-25309-01",
@@ -99,6 +102,7 @@
99102
"Microsoft.DotNet.BuildTools.TestSuite": "1.0.1-prerelease-01001-04",
100103
"xunit.console.netcore": "1.0.3-prerelease-00925-01",
101104
"Microsoft.xunit.netcore.extensions": "1.0.1-prerelease-01001-04",
105+
"System.Net.Http.WinHttpHandler": "4.4.0-preview2-25309-01",
102106
"System.ServiceModel.Duplex": "4.4.0-preview1-25302-01",
103107
"System.ServiceModel.Http": "4.4.0-preview1-25302-01",
104108
"System.ServiceModel.NetTcp": "4.4.0-preview1-25302-01",

src/System.Private.ServiceModel/src/Resources/Strings.resx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,18 @@
606606
<data name="RequestChannelWaitForReplyTimedOut" xml:space="preserve">
607607
<value>The request channel timed out while waiting for a reply after {0}. Increase the timeout value passed to the call to Request or increase the SendTimeout value on the Binding. The time allotted to this operation may have been a portion of a longer timeout.</value>
608608
</data>
609+
<data name="HttpProxyRequiresSingleAuthScheme" xml:space="preserve">
610+
<value>The '{0}' authentication scheme has been specified for the proxy on the HTTP factory. However, the factory only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous.</value>
611+
</data>
612+
<data name="UseDefaultWebProxyCantBeUsedWithExplicitProxyAddress" xml:space="preserve">
613+
<value>You cannot specify an explicit Proxy Address as well as UseDefaultWebProxy=true in your HTTP Transport Binding Element.</value>
614+
</data>
615+
<data name="ProxyImpersonationLevelMismatch" xml:space="preserve">
616+
<value>The HTTP proxy authentication credential specified an impersonation level restriction ({0}) that is stricter than the restriction for target server authentication ({1}).</value>
617+
</data>
618+
<data name="ProxyAuthenticationLevelMismatch" xml:space="preserve">
619+
<value>The HTTP proxy authentication credential specified an mutual authentication requirement ({0}) that is stricter than the requirement for target server authentication ({1}).</value>
620+
</data>
609621
<data name="HttpIfModifiedSinceParseError" xml:space="preserve">
610622
<value>The value specified, '{0}', for the If-Modified-Since header does not parse into a valid date. Check the property value and ensure that it is of the proper format.</value>
611623
</data>

src/System.Private.ServiceModel/src/System/ServiceModel/Channels/HttpChannelFactory.cs

Lines changed: 170 additions & 46 deletions
Large diffs are not rendered by default.

src/System.Private.ServiceModel/src/System/ServiceModel/Channels/HttpTransportBindingElement.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ public class HttpTransportBindingElement
1717
{
1818
private bool _allowCookies;
1919
private AuthenticationSchemes _authenticationScheme;
20+
private bool _bypassProxyOnLocal;
2021
private bool _decompressionEnabled;
2122
private HostNameComparisonMode _hostNameComparisonMode;
2223
private bool _keepAliveEnabled;
2324
private bool _inheritBaseAddressSettings;
2425
private int _maxBufferSize;
2526
private bool _maxBufferSizeInitialized;
2627
private string _method;
28+
private Uri _proxyAddress;
29+
private AuthenticationSchemes _proxyAuthenticationScheme;
2730
private string _realm;
2831
private TimeSpan _requestInitializationTimeout;
2932
private TransferMode _transferMode;
@@ -41,6 +44,7 @@ public HttpTransportBindingElement()
4144
{
4245
_allowCookies = HttpTransportDefaults.AllowCookies;
4346
_authenticationScheme = HttpTransportDefaults.AuthenticationScheme;
47+
_bypassProxyOnLocal = HttpTransportDefaults.BypassProxyOnLocal;
4448
_decompressionEnabled = HttpTransportDefaults.DecompressionEnabled;
4549
_hostNameComparisonMode = HttpTransportDefaults.HostNameComparisonMode;
4650
_keepAliveEnabled = HttpTransportDefaults.KeepAliveEnabled;
@@ -60,6 +64,7 @@ protected HttpTransportBindingElement(HttpTransportBindingElement elementToBeClo
6064
{
6165
_allowCookies = elementToBeCloned._allowCookies;
6266
_authenticationScheme = elementToBeCloned._authenticationScheme;
67+
_bypassProxyOnLocal = elementToBeCloned._bypassProxyOnLocal;
6368
_decompressionEnabled = elementToBeCloned._decompressionEnabled;
6469
_hostNameComparisonMode = elementToBeCloned._hostNameComparisonMode;
6570
_inheritBaseAddressSettings = elementToBeCloned.InheritBaseAddressSettings;
@@ -107,6 +112,19 @@ public AuthenticationSchemes AuthenticationScheme
107112
}
108113
}
109114

115+
[DefaultValue(HttpTransportDefaults.BypassProxyOnLocal)]
116+
public bool BypassProxyOnLocal
117+
{
118+
get
119+
{
120+
return _bypassProxyOnLocal;
121+
}
122+
set
123+
{
124+
_bypassProxyOnLocal = value;
125+
}
126+
}
127+
110128
[DefaultValue(HttpTransportDefaults.DecompressionEnabled)]
111129
public bool DecompressionEnabled
112130
{
@@ -271,6 +289,40 @@ internal string Method
271289
}
272290
}
273291

292+
[DefaultValue(HttpTransportDefaults.ProxyAddress)]
293+
[TypeConverter(typeof(UriTypeConverter))]
294+
public Uri ProxyAddress
295+
{
296+
get
297+
{
298+
return _proxyAddress;
299+
}
300+
set
301+
{
302+
_proxyAddress = value;
303+
}
304+
}
305+
306+
[DefaultValue(HttpTransportDefaults.ProxyAuthenticationScheme)]
307+
public AuthenticationSchemes ProxyAuthenticationScheme
308+
{
309+
get
310+
{
311+
return _proxyAuthenticationScheme;
312+
}
313+
314+
set
315+
{
316+
if (!value.IsSingleton())
317+
{
318+
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(value), SR.Format(SR.HttpProxyRequiresSingleAuthScheme,
319+
value));
320+
}
321+
322+
_proxyAuthenticationScheme = value;
323+
}
324+
}
325+
274326
[DefaultValue(HttpTransportDefaults.Realm)]
275327
public string Realm
276328
{
@@ -371,12 +423,17 @@ public bool UnsafeConnectionNtlmAuthentication
371423
}
372424
}
373425

426+
[DefaultValue(HttpTransportDefaults.UseDefaultWebProxy)]
374427
public bool UseDefaultWebProxy
375428
{
376429
get
377430
{
378431
return _useDefaultWebProxy;
379432
}
433+
set
434+
{
435+
_useDefaultWebProxy = value;
436+
}
380437
}
381438

382439
internal string GetWsdlTransportUri(bool useWebSocketTransport)

src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceModelHttpMessageHandler.CoreClr.cs renamed to src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceModelHttpMessageHandler.CoreClr.Unix.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
namespace System.ServiceModel.Channels
1212
{
13-
#if FEATURE_CORECLR
13+
#if FEATURE_CORECLR && !TARGETS_WINDOWS
1414
public partial class ServiceModelHttpMessageHandler
1515
{
1616
private readonly HttpClientHandler _innerHandler;
@@ -68,6 +68,12 @@ public bool SupportsProxy
6868
get { return _innerHandler.SupportsProxy; }
6969
}
7070

71+
public IWebProxy Proxy
72+
{
73+
get { return null; }
74+
set { throw new PlatformNotSupportedException(); }
75+
}
76+
7177
public bool SupportsClientCertificates
7278
{
7379
get { return true; }
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
6+
using System.Net;
7+
using System.Net.Http;
8+
using System.Net.Security;
9+
using System.Security.Cryptography.X509Certificates;
10+
11+
namespace System.ServiceModel.Channels
12+
{
13+
#if FEATURE_CORECLR && TARGETS_WINDOWS
14+
public partial class ServiceModelHttpMessageHandler
15+
{
16+
private readonly WinHttpHandler _innerHandler;
17+
18+
public ServiceModelHttpMessageHandler()
19+
{
20+
_innerHandler = new WinHttpHandler();
21+
InnerHandler = _innerHandler;
22+
}
23+
24+
public ICredentials Credentials
25+
{
26+
get { return _innerHandler.ServerCredentials; }
27+
set { _innerHandler.ServerCredentials = value; }
28+
}
29+
30+
public bool UseCookies
31+
{
32+
get { return (_innerHandler.CookieUsePolicy == CookieUsePolicy.UseSpecifiedCookieContainer); }
33+
set { _innerHandler.CookieUsePolicy = value ? CookieUsePolicy.UseSpecifiedCookieContainer : CookieUsePolicy.IgnoreCookies; }
34+
}
35+
36+
public bool UseDefaultCredentials
37+
{
38+
// WinHttpHandler doesn't have a separate UseDefaultCredentials property. There
39+
// is just a ServerCredentials property. So, we need to map the behavior.
40+
//
41+
// This property only affect .ServerCredentials and not .DefaultProxyCredentials.
42+
43+
get { return (_innerHandler.ServerCredentials == CredentialCache.DefaultCredentials); }
44+
45+
set
46+
{
47+
if (value)
48+
{
49+
_innerHandler.ServerCredentials = CredentialCache.DefaultCredentials;
50+
}
51+
else
52+
{
53+
if (_innerHandler.ServerCredentials == CredentialCache.DefaultCredentials)
54+
{
55+
// Only clear out the ServerCredentials property if it was a DefaultCredentials.
56+
_innerHandler.ServerCredentials = null;
57+
}
58+
}
59+
}
60+
}
61+
62+
public bool UseProxy { get; set; }
63+
64+
public bool CheckCertificateRevocationList
65+
{
66+
get { return false; }
67+
set { throw ExceptionHelper.PlatformNotSupported("CheckCertificateRevocationList not yet support"); }
68+
}
69+
70+
public X509CertificateCollection ClientCertificates
71+
{
72+
get { return _innerHandler.ClientCertificates; }
73+
}
74+
75+
public Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool>
76+
ServerCertificateValidationCallback
77+
{
78+
get { return _innerHandler.ServerCertificateValidationCallback; }
79+
set { _innerHandler.ServerCertificateValidationCallback = value; }
80+
}
81+
82+
public bool SupportsProxy => true;
83+
84+
public IWebProxy Proxy
85+
{
86+
get { return _innerHandler.Proxy; }
87+
set { _innerHandler.Proxy = value; }
88+
}
89+
90+
public bool SupportsClientCertificates => true;
91+
92+
public bool SupportsCertificateValidationCallback => true;
93+
}
94+
#endif
95+
}

src/System.Private.ServiceModel/src/System/ServiceModel/Channels/ServiceModelHttpMessageHandler.NetNative.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ public bool SupportsProxy
7070
get { return false; /* Only uses wininet configured proxy */ }
7171
}
7272

73+
public IWebProxy Proxy
74+
{
75+
get { return null; }
76+
set { throw new PlatformNotSupportedException(); }
77+
}
78+
7379
public bool SupportsClientCertificates
7480
{
7581
get { return true; }

src/System.Private.ServiceModel/src/System/ServiceModel/Channels/TransportDefaults.cs

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -242,45 +242,36 @@ public static class ApplicationContainerSettingsDefaults
242242
public const int ServiceSession = 0;
243243
}
244244

245-
public static class HttpTransportDefaults
245+
internal static class HttpTransportDefaults
246246
{
247-
public const bool AllowCookies = false;
248-
public const AuthenticationSchemes AuthenticationScheme = AuthenticationSchemes.Anonymous;
249-
public const bool DecompressionEnabled = true;
250-
public const HostNameComparisonMode HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.StrongWildcard;
251-
public const bool KeepAliveEnabled = true;
252-
public const string Realm = "";
253-
public const TransferMode TransferMode = System.ServiceModel.TransferMode.Buffered;
254-
public const bool UnsafeConnectionNtlmAuthentication = false;
255-
public const bool UseDefaultWebProxy = true;
256-
public const string UpgradeHeader = "Upgrade";
257-
public const string ConnectionHeader = "Connection";
258-
public const HttpMessageHandlerFactory MessageHandlerFactory = null;
259-
260-
public static TimeSpan RequestInitializationTimeout { get { return TimeSpanHelper.FromMilliseconds(0, RequestInitializationTimeoutString); } }
261-
public const string RequestInitializationTimeoutString = "00:00:00";
262-
263-
// We use 0 as the default value of the MaxPendingAccepts property on HttpTransportBindingElement. In 4.5 we always
264-
// use 10 under the hood if the default value is picked. In future releases, we could adjust the underlying default
265-
// value when we have the dynamic expending pattern of BeginGetContext call implemented and the heap fragmentation issue
266-
// from NCL layer solved.
267-
private const int PendingAcceptsConstant = 10;
268-
public const int DefaultMaxPendingAccepts = 0;
269-
public const int MaxPendingAcceptsUpperLimit = 100000;
270-
public static int GetEffectiveMaxPendingAccepts(int maxPendingAccepts)
271-
{
272-
return maxPendingAccepts == HttpTransportDefaults.DefaultMaxPendingAccepts ?
273-
PendingAcceptsConstant :
274-
maxPendingAccepts;
275-
}
276-
277-
278-
public static WebSocketTransportSettings GetDefaultWebSocketTransportSettings()
247+
internal const bool AllowCookies = false;
248+
internal const AuthenticationSchemes AuthenticationScheme = AuthenticationSchemes.Anonymous;
249+
internal const bool BypassProxyOnLocal = false;
250+
internal const bool DecompressionEnabled = true;
251+
internal const HostNameComparisonMode HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.StrongWildcard;
252+
internal const bool KeepAliveEnabled = true;
253+
internal const Uri ProxyAddress = null;
254+
internal const AuthenticationSchemes ProxyAuthenticationScheme = AuthenticationSchemes.Anonymous;
255+
internal const string Realm = "";
256+
internal const TransferMode TransferMode = System.ServiceModel.TransferMode.Buffered;
257+
internal const bool UnsafeConnectionNtlmAuthentication = false;
258+
internal const bool UseDefaultWebProxy = true;
259+
internal const string UpgradeHeader = "Upgrade";
260+
internal const string ConnectionHeader = "Connection";
261+
internal const HttpMessageHandlerFactory MessageHandlerFactory = null;
262+
263+
internal static TimeSpan RequestInitializationTimeout => TimeSpanHelper.FromMilliseconds(0, RequestInitializationTimeoutString);
264+
internal const string RequestInitializationTimeoutString = "00:00:00";
265+
266+
internal const int DefaultMaxPendingAccepts = 0;
267+
internal const int MaxPendingAcceptsUpperLimit = 100000;
268+
269+
internal static WebSocketTransportSettings GetDefaultWebSocketTransportSettings()
279270
{
280271
return new WebSocketTransportSettings();
281272
}
282273

283-
public static MessageEncoderFactory GetDefaultMessageEncoderFactory()
274+
internal static MessageEncoderFactory GetDefaultMessageEncoderFactory()
284275
{
285276
return new TextMessageEncoderFactory(MessageVersion.Default, TextEncoderDefaults.Encoding, EncoderDefaults.MaxReadPoolSize, EncoderDefaults.MaxWritePoolSize, EncoderDefaults.ReaderQuotas);
286277
}

0 commit comments

Comments
 (0)