| File: FrameworkFork\System.ServiceModel\System\ServiceModel\Channels\HttpTransportBindingElement.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.Contracts; using System.Net; using System.Net.Security; using System.Runtime; using System.Security.Authentication.ExtendedProtection; using System.ServiceModel.Description; using Microsoft.Xml; namespace System.ServiceModel.Channels { public class HttpTransportBindingElement : TransportBindingElement, ITransportPolicyImport { private bool _allowCookies; private AuthenticationSchemes _authenticationScheme; private bool _decompressionEnabled; private HostNameComparisonMode _hostNameComparisonMode; private bool _keepAliveEnabled; private bool _inheritBaseAddressSettings; private int _maxBufferSize; private bool _maxBufferSizeInitialized; private string _method; private string _realm; private TimeSpan _requestInitializationTimeout; private TransferMode _transferMode; private bool _unsafeConnectionNtlmAuthentication; private bool _useDefaultWebProxy; private WebSocketTransportSettings _webSocketSettings; #if !FEATURE_NETNATIVE private ExtendedProtectionPolicy _extendedProtectionPolicy; #endif // !FEATURE_NETNATIVE private HttpMessageHandlerFactory _httpMessageHandlerFactory; private int _maxPendingAccepts; public HttpTransportBindingElement() : base() { _allowCookies = HttpTransportDefaults.AllowCookies; _authenticationScheme = HttpTransportDefaults.AuthenticationScheme; _decompressionEnabled = HttpTransportDefaults.DecompressionEnabled; _hostNameComparisonMode = HttpTransportDefaults.HostNameComparisonMode; _keepAliveEnabled = HttpTransportDefaults.KeepAliveEnabled; _maxBufferSize = TransportDefaults.MaxBufferSize; _maxPendingAccepts = HttpTransportDefaults.DefaultMaxPendingAccepts; _method = string.Empty; _realm = HttpTransportDefaults.Realm; _requestInitializationTimeout = HttpTransportDefaults.RequestInitializationTimeout; _transferMode = HttpTransportDefaults.TransferMode; _unsafeConnectionNtlmAuthentication = HttpTransportDefaults.UnsafeConnectionNtlmAuthentication; _useDefaultWebProxy = HttpTransportDefaults.UseDefaultWebProxy; _webSocketSettings = HttpTransportDefaults.GetDefaultWebSocketTransportSettings(); _extendedProtectionPolicy = ChannelBindingUtility.DefaultPolicy; } protected HttpTransportBindingElement(HttpTransportBindingElement elementToBeCloned) : base(elementToBeCloned) { _allowCookies = elementToBeCloned._allowCookies; _authenticationScheme = elementToBeCloned._authenticationScheme; _decompressionEnabled = elementToBeCloned._decompressionEnabled; _hostNameComparisonMode = elementToBeCloned._hostNameComparisonMode; _inheritBaseAddressSettings = elementToBeCloned.InheritBaseAddressSettings; _keepAliveEnabled = elementToBeCloned._keepAliveEnabled; _maxBufferSize = elementToBeCloned._maxBufferSize; _maxBufferSizeInitialized = elementToBeCloned._maxBufferSizeInitialized; _maxPendingAccepts = elementToBeCloned._maxPendingAccepts; _method = elementToBeCloned._method; _realm = elementToBeCloned._realm; _requestInitializationTimeout = elementToBeCloned._requestInitializationTimeout; _transferMode = elementToBeCloned._transferMode; _unsafeConnectionNtlmAuthentication = elementToBeCloned._unsafeConnectionNtlmAuthentication; _useDefaultWebProxy = elementToBeCloned._useDefaultWebProxy; _webSocketSettings = elementToBeCloned._webSocketSettings.Clone(); #if !FEATURE_NETNATIVE _extendedProtectionPolicy = elementToBeCloned.ExtendedProtectionPolicy; #endif // !FEATURE_NETNATIVE this.MessageHandlerFactory = elementToBeCloned.MessageHandlerFactory; } [DefaultValue(HttpTransportDefaults.AllowCookies)] public bool AllowCookies { get { return _allowCookies; } set { _allowCookies = value; } } [DefaultValue(HttpTransportDefaults.AuthenticationScheme)] public AuthenticationSchemes AuthenticationScheme { get { return _authenticationScheme; } set { _authenticationScheme = value; } } [DefaultValue(HttpTransportDefaults.DecompressionEnabled)] public bool DecompressionEnabled { get { return _decompressionEnabled; } set { _decompressionEnabled = value; } } [DefaultValue(HttpTransportDefaults.HostNameComparisonMode)] public HostNameComparisonMode HostNameComparisonMode { get { return _hostNameComparisonMode; } set { HostNameComparisonModeHelper.Validate(value); _hostNameComparisonMode = value; } } public HttpMessageHandlerFactory MessageHandlerFactory { get { return _httpMessageHandlerFactory; } set { _httpMessageHandlerFactory = value; } } #if !FEATURE_NETNATIVE public ExtendedProtectionPolicy ExtendedProtectionPolicy { get { return _extendedProtectionPolicy; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } if (value.PolicyEnforcement == PolicyEnforcement.Always && !System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy.OSSupportsExtendedProtection) { ExceptionHelper.PlatformNotSupported(SRServiceModel.ExtendedProtectionNotSupported); } _extendedProtectionPolicy = value; } } #endif // !FEATURE_NETNATIVE // MB#26970: used by MEX to ensure that we don't conflict on base-address scoped settings internal bool InheritBaseAddressSettings { get { return _inheritBaseAddressSettings; } set { _inheritBaseAddressSettings = value; } } [DefaultValue(HttpTransportDefaults.KeepAliveEnabled)] public bool KeepAliveEnabled { get { return _keepAliveEnabled; } set { _keepAliveEnabled = value; } } // client // server [DefaultValue(TransportDefaults.MaxBufferSize)] public int MaxBufferSize { get { if (_maxBufferSizeInitialized || TransferMode != TransferMode.Buffered) return _maxBufferSize; long maxReceivedMessageSize = MaxReceivedMessageSize; if (maxReceivedMessageSize > int.MaxValue) return int.MaxValue; else return (int)maxReceivedMessageSize; } set { if (value <= 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SRServiceModel.ValueMustBePositive)); } _maxBufferSizeInitialized = true; _maxBufferSize = value; } } // server [DefaultValue(HttpTransportDefaults.DefaultMaxPendingAccepts)] public int MaxPendingAccepts { get { return _maxPendingAccepts; } set { if (value < 0) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SRServiceModel.ValueMustBeNonNegative)); } if (value > HttpTransportDefaults.MaxPendingAcceptsUpperLimit) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, string.Format(SRServiceModel.HttpMaxPendingAcceptsTooLargeError, HttpTransportDefaults.MaxPendingAcceptsUpperLimit))); } _maxPendingAccepts = value; } } // string.Empty == wildcard internal string Method { get { return _method; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } _method = value; } } [DefaultValue(HttpTransportDefaults.Realm)] public string Realm { get { return _realm; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } _realm = value; } } [DefaultValue(typeof(TimeSpan), HttpTransportDefaults.RequestInitializationTimeoutString)] public TimeSpan RequestInitializationTimeout { get { return _requestInitializationTimeout; } set { if (value < TimeSpan.Zero) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SRServiceModel.SFxTimeoutOutOfRange0)); } if (TimeoutHelper.IsTooLarge(value)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value, SRServiceModel.SFxTimeoutOutOfRangeTooBig)); } _requestInitializationTimeout = value; } } public override string Scheme { get { return "http"; } } // client // server [DefaultValue(HttpTransportDefaults.TransferMode)] public TransferMode TransferMode { get { return _transferMode; } set { TransferModeHelper.Validate(value); _transferMode = value; } } public WebSocketTransportSettings WebSocketSettings { get { return _webSocketSettings; } set { if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } _webSocketSettings = value; } } internal virtual bool GetSupportsClientAuthenticationImpl(AuthenticationSchemes effectiveAuthenticationSchemes) { return effectiveAuthenticationSchemes != AuthenticationSchemes.None && effectiveAuthenticationSchemes.IsNotSet(AuthenticationSchemes.Anonymous); } internal virtual bool GetSupportsClientWindowsIdentityImpl(AuthenticationSchemes effectiveAuthenticationSchemes) { return effectiveAuthenticationSchemes != AuthenticationSchemes.None && effectiveAuthenticationSchemes.IsNotSet(AuthenticationSchemes.Anonymous); } [DefaultValue(HttpTransportDefaults.UnsafeConnectionNtlmAuthentication)] public bool UnsafeConnectionNtlmAuthentication { get { return _unsafeConnectionNtlmAuthentication; } set { _unsafeConnectionNtlmAuthentication = value; } } public bool UseDefaultWebProxy { get { return _useDefaultWebProxy; } } internal string GetWsdlTransportUri(bool useWebSocketTransport) { if (useWebSocketTransport) { return TransportPolicyConstants.WebSocketTransportUri; } return TransportPolicyConstants.HttpTransportUri; } public override BindingElement Clone() { return new HttpTransportBindingElement(this); } public override T GetProperty<T>(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } if (typeof(T) == typeof(ISecurityCapabilities)) { AuthenticationSchemes effectiveAuthenticationSchemes = this.AuthenticationScheme; // Desktop: HttpTransportBindingElement.GetEffectiveAuthenticationSchemes(this.AuthenticationScheme, context.BindingParameters); return (T)(object)new SecurityCapabilities(this.GetSupportsClientAuthenticationImpl(effectiveAuthenticationSchemes), effectiveAuthenticationSchemes == AuthenticationSchemes.Negotiate, this.GetSupportsClientWindowsIdentityImpl(effectiveAuthenticationSchemes), ProtectionLevel.None, ProtectionLevel.None); } else if (typeof(T) == typeof(IBindingDeliveryCapabilities)) { return (T)(object)new BindingDeliveryCapabilitiesHelper(); } else if (typeof(T) == typeof(TransferMode)) { return (T)(object)this.TransferMode; } #if !FEATURE_NETNATIVE else if (typeof(T) == typeof(ExtendedProtectionPolicy)) { return (T)(object)this.ExtendedProtectionPolicy; } #endif //!FEATURE_NETNATIVE else if (typeof(T) == typeof(ITransportCompressionSupport)) { return (T)(object)new TransportCompressionSupportHelper(); } else { Contract.Assert(context.BindingParameters != null); if (context.BindingParameters.Find<MessageEncodingBindingElement>() == null) { context.BindingParameters.Add(new TextMessageEncodingBindingElement()); } return base.GetProperty<T>(context); } } public override bool CanBuildChannelFactory<TChannel>(BindingContext context) { if (typeof(TChannel) == typeof(IRequestChannel)) { return this.WebSocketSettings.TransportUsage != WebSocketTransportUsage.Always; } else if (typeof(TChannel) == typeof(IDuplexSessionChannel)) { return this.WebSocketSettings.TransportUsage != WebSocketTransportUsage.Never; } return false; } public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context) { if (context == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context"); } if (this.MessageHandlerFactory != null) { throw FxTrace.Exception.AsError(new InvalidOperationException(string.Format(SRServiceModel.HttpPipelineNotSupportedOnClientSide, "MessageHandlerFactory"))); } if (!this.CanBuildChannelFactory<TChannel>(context)) { Contract.Assert(context.Binding != null); throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", string.Format(SRServiceModel.CouldnTCreateChannelForChannelType2, context.Binding.Name, typeof(TChannel))); } if (_authenticationScheme == AuthenticationSchemes.None) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", string.Format(SRServiceModel.HttpAuthSchemeCannotBeNone, _authenticationScheme)); } else if (!_authenticationScheme.IsSingleton()) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("value", string.Format(SRServiceModel.HttpRequiresSingleAuthScheme, _authenticationScheme)); } return (IChannelFactory<TChannel>)(object)new HttpChannelFactory<TChannel>(this, context); } internal virtual void OnImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext) { } void ITransportPolicyImport.ImportPolicy(MetadataImporter importer, PolicyConversionContext policyContext) { ICollection<XmlElement> bindingAssertions = policyContext.GetBindingAssertions(); List<XmlElement> httpAuthAssertions = new List<XmlElement>(); bool foundAssertion = false; foreach (XmlElement assertion in bindingAssertions) { if (assertion.NamespaceURI != TransportPolicyConstants.HttpTransportNamespace) { continue; } switch (assertion.LocalName) { case TransportPolicyConstants.BasicHttpAuthenticationName: this.AuthenticationScheme = AuthenticationSchemes.Basic; break; case TransportPolicyConstants.DigestHttpAuthenticationName: this.AuthenticationScheme = AuthenticationSchemes.Digest; break; case TransportPolicyConstants.NegotiateHttpAuthenticationName: this.AuthenticationScheme = AuthenticationSchemes.Negotiate; break; case TransportPolicyConstants.NtlmHttpAuthenticationName: this.AuthenticationScheme = AuthenticationSchemes.Ntlm; break; default: continue; } if (foundAssertion) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException( string.Format(SRServiceModel.HttpTransportCannotHaveMultipleAuthenticationSchemes, policyContext.Contract.Namespace, policyContext.Contract.Name))); } foundAssertion = true; httpAuthAssertions.Add(assertion); } httpAuthAssertions.ForEach(delegate (XmlElement element) { bindingAssertions.Remove(element); }); // This code is being used when we are generating the client configration. Before that, we should already set TransportUsage as Always if the server // is using WebSocket. if (this.WebSocketSettings.TransportUsage == WebSocketTransportUsage.Always) { foreach (XmlElement assertion in bindingAssertions) { if (assertion.NamespaceURI != TransportPolicyConstants.WebSocketPolicyNamespace) { continue; } string transferMode = assertion.LocalName; TransferMode result; if (!Enum.TryParse<TransferMode>(transferMode, true, out result) || !TransferModeHelper.IsDefined(result) || result == TransferMode.Buffered) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(string.Format( SRServiceModel.WebSocketTransportPolicyAssertionInvalid, policyContext.Contract.Namespace, policyContext.Contract.Name, transferMode, TransferMode.Streamed, TransferMode.StreamedRequest, TransferMode.StreamedResponse))); } this.TransferMode = result; bindingAssertions.Remove(assertion); break; } } OnImportPolicy(importer, policyContext); } internal override bool IsMatch(BindingElement b) { if (!base.IsMatch(b)) return false; HttpTransportBindingElement http = b as HttpTransportBindingElement; if (http == null) return false; if (_allowCookies != http._allowCookies) return false; if (_authenticationScheme != http._authenticationScheme) return false; if (_decompressionEnabled != http._decompressionEnabled) return false; if (_hostNameComparisonMode != http._hostNameComparisonMode) return false; if (_inheritBaseAddressSettings != http._inheritBaseAddressSettings) return false; if (_keepAliveEnabled != http._keepAliveEnabled) return false; if (_maxBufferSize != http._maxBufferSize) return false; if (_method != http._method) return false; if (_realm != http._realm) return false; if (_transferMode != http._transferMode) return false; if (_unsafeConnectionNtlmAuthentication != http._unsafeConnectionNtlmAuthentication) return false; if (_useDefaultWebProxy != http._useDefaultWebProxy) return false; if (!this.WebSocketSettings.Equals(http.WebSocketSettings)) return false; return true; } private MessageEncodingBindingElement FindMessageEncodingBindingElement(BindingElementCollection bindingElements, out bool createdNew) { createdNew = false; MessageEncodingBindingElement encodingBindingElement = bindingElements.Find<MessageEncodingBindingElement>(); if (encodingBindingElement == null) { createdNew = true; encodingBindingElement = new TextMessageEncodingBindingElement(); } return encodingBindingElement; } private class BindingDeliveryCapabilitiesHelper : IBindingDeliveryCapabilities { internal BindingDeliveryCapabilitiesHelper() { } bool IBindingDeliveryCapabilities.AssuresOrderedDelivery { get { return false; } } bool IBindingDeliveryCapabilities.QueuedDelivery { get { return false; } } } private class TransportCompressionSupportHelper : ITransportCompressionSupport { public bool IsCompressionFormatSupported(CompressionFormat compressionFormat) { return true; } } } }