Imported Upstream version 5.12.0.220

Former-commit-id: c477e03582759447177c6d4bf412cd2355aad476
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-04-24 09:31:23 +00:00
parent 8bd104cef2
commit 8fc30896db
1200 changed files with 29534 additions and 26161 deletions

View File

@@ -20,14 +20,16 @@ RESX_RESOURCE_STRING = \
../../../external/corefx/src/System.Buffers/src/Resources/Strings.resx \
../../../external/corefx/src/System.Private.Uri/src/Resources/Strings.resx \
../../../external/corefx/src/System.IO.Ports/src/Resources/Strings.resx \
../../../external/corefx/src/System.Net.HttpListener/src/Resources/Strings.resx
../../../external/corefx/src/System.Net.HttpListener/src/Resources/Strings.resx \
../../../external/corefx/src/System.Net.Requests/src/Resources/Strings.resx
TEST_RESOURCES = \
Test/System/test-uri-props.txt \
Test/System/test-uri-props-manual.txt \
Test/System/test-uri-relative-props.txt
XTEST_LIB_REFS = System System.Core Facades/System.Threading.Tasks Facades/System.Runtime.InteropServices.RuntimeInformation
USE_XTEST_REMOTE_EXECUTOR = YES
XTEST_LIB_REFS = System System.Core System.Net Facades/System.Threading.Tasks Facades/System.Runtime.InteropServices.RuntimeInformation System.Net.Http
LIB_MCS_FLAGS = -d:CONFIGURATION_2_0 $(REFERENCE_SOURCES_FLAGS) -unsafe $(RESOURCE_FILES:%=-resource:%) -nowarn:436
ifndef NO_MONO_SECURITY

View File

@@ -226,45 +226,79 @@ namespace Mono.Net.Security
providerRegistration = new Dictionary<string,Tuple<Guid,string>> ();
providerCache = new Dictionary<Guid,MSI.MonoTlsProvider> ();
var appleTlsEntry = new Tuple<Guid,String> (AppleTlsId, "Mono.AppleTls.AppleTlsProvider");
#if ONLY_APPLETLS || MONOTOUCH || XAMMAC
providerRegistration.Add ("default", appleTlsEntry);
providerRegistration.Add ("apple", appleTlsEntry);
#else
var legacyEntry = new Tuple<Guid,String> (LegacyId, "Mono.Net.Security.LegacyTlsProvider");
providerRegistration.Add ("legacy", legacyEntry);
Tuple<Guid,String> btlsEntry = null;
#if MONO_FEATURE_BTLS
if (IsBtlsSupported ()) {
btlsEntry = new Tuple<Guid,String> (BtlsId, "Mono.Btls.MonoBtlsProvider");
providerRegistration.Add ("btls", btlsEntry);
}
#endif
if (Platform.IsMacOS)
providerRegistration.Add ("default", appleTlsEntry);
else if (btlsEntry != null)
providerRegistration.Add ("default", btlsEntry);
else
providerRegistration.Add ("default", legacyEntry);
providerRegistration.Add ("apple", appleTlsEntry);
#endif
PopulateProviders ();
}
}
#region Platform-Specific code
#if ONLY_APPLETLS || MONOTOUCH || XAMMAC
// TODO: Should be redundant
static void PopulateProviders ()
{
var appleTlsEntry = new Tuple<Guid,String> (AppleTlsId, typeof (Mono.AppleTls.AppleTlsProvider).FullName);
providerRegistration.Add ("default", appleTlsEntry);
providerRegistration.Add ("apple", appleTlsEntry);
}
#elif MONODROID
// TODO: Should be redundant
static void PopulateProviders ()
{
var legacyEntry = new Tuple<Guid,String> (LegacyId, typeof (Mono.Net.Security.LegacyTlsProvider).FullName);
providerRegistration.Add ("legacy", legacyEntry);
#if MONO_FEATURE_BTLS
var btlsEntry = new Tuple<Guid,String> (BtlsId, typeof (Mono.Btls.MonoBtlsProvider).FullName);
if (btlsEntry != null)
providerRegistration.Add ("default", btlsEntry);
else
#endif
providerRegistration.Add ("default", legacyEntry);
}
#else
static void PopulateProviders ()
{
#if MONO_FEATURE_APPLETLS
var appleTlsEntry = new Tuple<Guid,String> (AppleTlsId, typeof (Mono.AppleTls.AppleTlsProvider).FullName);
#endif
var legacyEntry = new Tuple<Guid,String> (LegacyId, typeof (Mono.Net.Security.LegacyTlsProvider).FullName);
providerRegistration.Add ("legacy", legacyEntry);
Tuple<Guid,String> btlsEntry = null;
#if MONO_FEATURE_BTLS
if (IsBtlsSupported ()) {
btlsEntry = new Tuple<Guid,String> (BtlsId, typeof (Mono.Btls.MonoBtlsProvider).FullName);
providerRegistration.Add ("btls", btlsEntry);
}
#endif
#if MONO_FEATURE_APPLETLS
if (Platform.IsMacOS)
providerRegistration.Add ("default", appleTlsEntry);
else
#endif
#if MONO_FEATURE_BTLS
if (btlsEntry != null)
providerRegistration.Add ("default", btlsEntry);
else
#endif
providerRegistration.Add ("default", legacyEntry);
#if MONO_FEATURE_APPLETLS
providerRegistration.Add ("apple", appleTlsEntry);
#endif
}
#endif
#if MONO_FEATURE_BTLS
[MethodImpl (MethodImplOptions.InternalCall)]
internal extern static bool IsBtlsSupported ();
#endif
#if MONODROID
static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
{
#if MONODROID
MSI.MonoTlsProvider provider = null;
var type = Environment.GetEnvironmentVariable ("XA_TLS_PROVIDER");
switch (type) {
@@ -281,24 +315,40 @@ namespace Mono.Net.Security
default:
throw new NotSupportedException (string.Format ("Invalid TLS Provider: `{0}'.", provider));
}
}
#elif ONLY_APPLETLS || MONOTOUCH || XAMMAC
static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
{
return new AppleTlsProvider ();
}
#else
static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
{
var variable = Environment.GetEnvironmentVariable ("MONO_TLS_PROVIDER");
if (string.IsNullOrEmpty (variable))
variable = "default";
var type = Environment.GetEnvironmentVariable ("MONO_TLS_PROVIDER");
if (string.IsNullOrEmpty (type))
type = "default";
return LookupProvider (variable, true);
}
switch (type) {
case "default":
#if MONO_FEATURE_APPLETLS
if (Platform.IsMacOS)
goto case "apple";
#endif
#if MONO_FEATURE_BTLS
if (IsBtlsSupported ())
goto case "btls";
#endif
goto case "legacy";
#if MONO_FEATURE_APPLETLS
case "apple":
return new AppleTlsProvider ();
#endif
#if MONO_FEATURE_BTLS
case "btls":
return new MonoBtlsProvider ();
#endif
case "legacy":
return new Mono.Net.Security.LegacyTlsProvider ();
}
#endregion
return LookupProvider (type, true);
#endif
}
#region Mono.Security visible API

View File

@@ -52,7 +52,7 @@ namespace Mono.Net.Security
{
class MonoTlsStream
{
#if SECURITY_DEP
#if SECURITY_DEP
readonly MonoTlsProvider provider;
readonly NetworkStream networkStream;
readonly HttpWebRequest request;
@@ -99,9 +99,11 @@ namespace Mono.Net.Security
#endif
}
internal Stream CreateStream (byte[] buffer)
internal async Task<Stream> CreateStream (WebConnectionTunnel tunnel, CancellationToken cancellationToken)
{
#if SECURITY_DEP
var socket = networkStream.InternalSocket;
WebConnection.Debug ($"MONO TLS STREAM CREATE STREAM: {socket.ID}");
sslStream = provider.CreateSslStream (networkStream, false, settings);
try {
@@ -112,16 +114,21 @@ namespace Mono.Net.Security
host = host.Substring (0, pos);
}
sslStream.AuthenticateAsClient (
await sslStream.AuthenticateAsClientAsync (
host, request.ClientCertificates,
(SslProtocols)ServicePointManager.SecurityProtocol,
ServicePointManager.CheckCertificateRevocationList);
ServicePointManager.CheckCertificateRevocationList).ConfigureAwait (false);
status = WebExceptionStatus.Success;
} catch {
status = WebExceptionStatus.SecureChannelFailure;
} catch (Exception ex) {
WebConnection.Debug ($"MONO TLS STREAM ERROR: {socket.ID} {socket.CleanedUp} {ex.Message}");
if (socket.CleanedUp)
status = WebExceptionStatus.RequestCanceled;
else
status = WebExceptionStatus.SecureChannelFailure;
throw;
} finally {
WebConnection.Debug ($"MONO TLS STREAM CREATE STREAM DONE: {socket.ID} {socket.CleanedUp}");
if (CertificateValidationFailed)
status = WebExceptionStatus.TrustFailure;
@@ -134,8 +141,8 @@ namespace Mono.Net.Security
}
try {
if (buffer != null)
sslStream.Write (buffer, 0, buffer.Length);
if (tunnel?.Data != null)
await sslStream.WriteAsync (tunnel.Data, 0, tunnel.Data.Length, cancellationToken).ConfigureAwait (false);
} catch {
status = WebExceptionStatus.SendFailure;
sslStream = null;

View File

@@ -1 +1 @@
5f6a3e96a03fd839708cd965990030483ed1179d
4c1d88b51c1ca6902aa3ee4c56a4bbf6c7ac20c6

View File

@@ -14,7 +14,18 @@ namespace System.Net
if (secureString == null || secureString.Length == 0)
return String.Empty;
#if MONO
try
{
bstr = Marshal.SecureStringToGlobalAllocUnicode(secureString);
plainString = Marshal.PtrToStringUni(bstr);
}
finally
{
if (bstr != IntPtr.Zero)
Marshal.ZeroFreeGlobalAllocUnicode(bstr);
}
#else
try
{
bstr = Marshal.SecureStringToBSTR(secureString);
@@ -25,6 +36,7 @@ namespace System.Net
if (bstr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(bstr);
}
#endif
return plainString;
}

View File

@@ -39,7 +39,7 @@ namespace System.CodeDom.Compiler
[ConfigurationCollection (typeof (Compiler), AddItemName = "compiler", CollectionType = ConfigurationElementCollectionType.BasicMap)]
internal sealed class CompilerCollection : ConfigurationElementCollection
{
static readonly string defaultCompilerVersion = "3.5";
static readonly string defaultCompilerVersion = "4.0";
static ConfigurationPropertyCollection properties;
static List <CompilerInfo> compiler_infos;
static Dictionary <string, CompilerInfo> compiler_languages;
@@ -50,30 +50,15 @@ namespace System.CodeDom.Compiler
properties = new ConfigurationPropertyCollection ();
compiler_infos = new List <CompilerInfo> ();
compiler_languages = new Dictionary <string, CompilerInfo> (16, StringComparer.OrdinalIgnoreCase);
compiler_extensions = new Dictionary <string, CompilerInfo> (6, StringComparer.OrdinalIgnoreCase);
compiler_extensions = new Dictionary <string, CompilerInfo> (4, StringComparer.OrdinalIgnoreCase);
CompilerInfo compiler = new CompilerInfo (null, "Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
new [] { ".cs" }, new [] { "c#", "cs", "csharp" });
CompilerInfo compiler = new CompilerInfo (null, "Microsoft.CSharp.CSharpCodeProvider, " + Consts.AssemblySystem,
new [] { "c#", "cs", "csharp" }, new [] { ".cs" });
compiler.ProviderOptions ["CompilerVersion"] = defaultCompilerVersion;
AddCompilerInfo (compiler);
compiler = new CompilerInfo (null, "Microsoft.VisualBasic.VBCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089",
new [] { ".vb" }, new [] { "vb", "vbs", "visualbasic", "vbscript" });
compiler.ProviderOptions ["CompilerVersion"] = defaultCompilerVersion;
AddCompilerInfo (compiler);
compiler = new CompilerInfo (null, "Microsoft.JScript.JScriptCodeProvider, Microsoft.JScript, Version=8.0.1100.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
new [] { ".js" }, new [] { "js", "jscript", "javascript" });
compiler.ProviderOptions ["CompilerVersion"] = defaultCompilerVersion;
AddCompilerInfo (compiler);
compiler = new CompilerInfo (null, "Microsoft.VJSharp.VJSharpCodeProvider, VJSharpCodeProvider, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
new [] { ".jsl", ".java" }, new [] { "vj#", "vjs", "vjsharp" });
compiler.ProviderOptions ["CompilerVersion"] = defaultCompilerVersion;
AddCompilerInfo (compiler);
compiler = new CompilerInfo (null, "Microsoft.VisualC.CppCodeProvider, CppCodeProvider, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
new [] { ".h" }, new [] { "c++", "mc", "cpp" });
compiler = new CompilerInfo (null, "Microsoft.VisualBasic.VBCodeProvider, " + Consts.AssemblySystem,
new [] { "vb", "vbs", "visualbasic", "vbscript" }, new [] { ".vb" });
compiler.ProviderOptions ["CompilerVersion"] = defaultCompilerVersion;
AddCompilerInfo (compiler);
}

View File

@@ -78,9 +78,13 @@ namespace System.Configuration {
public void Reload ()
{
#if (CONFIGURATION_DEP)
foreach (SettingsProvider provider in Providers) {
// IApplicationSettingsProvider iasp = provider as IApplicationSettingsProvider;
CacheValuesByProvider(provider);
/* Clear out the old property values so they will be reloaded on request */
if (PropertyValues != null) {
PropertyValues.Clear();
}
foreach(SettingsProperty prop in Properties) {
/* emit PropertyChanged for every property */
OnPropertyChanged(this, new PropertyChangedEventArgs(prop.Name));
}
#endif
}
@@ -88,13 +92,31 @@ namespace System.Configuration {
public void Reset()
{
#if (CONFIGURATION_DEP)
if (Properties != null) {
foreach (SettingsProvider provider in Providers) {
IApplicationSettingsProvider iasp = provider as IApplicationSettingsProvider;
if (iasp != null)
iasp.Reset (Context);
}
InternalSave ();
}
Reload ();
foreach (SettingsPropertyValue pv in PropertyValues)
pv.PropertyValue = pv.Reset();
#endif
}
public override void Save()
public override void Save ()
{
var e = new CancelEventArgs ();
OnSettingsSaving (this, e);
if (e.Cancel)
return;
InternalSave ();
}
void InternalSave ()
{
#if (CONFIGURATION_DEP)
Context.CurrentSettings = this;
@@ -111,13 +133,42 @@ namespace System.Configuration {
provider.SetPropertyValues (Context, cache);
}
Context.CurrentSettings = null;
#else
throw new NotImplementedException("No useful Save implemented.");
#endif
}
public virtual void Upgrade()
public virtual void Upgrade ()
{
#if (CONFIGURATION_DEP)
// if there is a current property, then for each settings
// provider in the providers collection, upgrade(ssp)
if (Properties != null) {
foreach (SettingsProvider provider in Providers) {
var appSettingsProvider = provider as IApplicationSettingsProvider;
if(appSettingsProvider != null) {
appSettingsProvider.Upgrade (Context, GetPropertiesForProvider (provider));
}
}
}
Reload ();
#else
throw new NotImplementedException ("No useful Upgrade implemented");
#endif
}
private SettingsPropertyCollection GetPropertiesForProvider (SettingsProvider provider)
{
SettingsPropertyCollection properties = new SettingsPropertyCollection ();
foreach (SettingsProperty sp in Properties) {
if (sp.Provider == provider) {
properties.Add(sp);
}
}
return properties;
}
protected virtual void OnPropertyChanged (object sender,
PropertyChangedEventArgs e)
{
@@ -310,7 +361,17 @@ namespace System.Configuration {
foreach (Attribute a in prop.GetCustomAttributes (false)) {
/* the attributes we handle natively here */
if (a is SettingsProviderAttribute) {
Type provider_type = Type.GetType (((SettingsProviderAttribute)a).ProviderTypeName);
var providerTypeName = ((SettingsProviderAttribute)a).ProviderTypeName;
Type provider_type = Type.GetType (providerTypeName);
if(provider_type == null) { // Type failed to find the type by name
var typeNameParts = providerTypeName.Split('.');
if(typeNameParts.Length > 1) { //Load the assembly that providerTypeName claims
var assy = Assembly.Load(typeNameParts[0]);
if(assy != null) {
provider_type = assy.GetType(providerTypeName); //try to get the type from that Assembly
}
}
}
provider = (SettingsProvider) Activator.CreateInstance (provider_type);
provider.Initialize (null, null);
}

View File

@@ -819,6 +819,11 @@ namespace System.Configuration
public void Reset (SettingsContext context)
{
if (values == null) {
SettingsPropertyCollection coll = new SettingsPropertyCollection ();
GetPropertyValues (context, coll);
}
if (values != null) {
foreach (SettingsPropertyValue propertyValue in values) {
// Can't use propertyValue.Property.DefaultValue

View File

@@ -45,6 +45,7 @@ namespace System.Configuration
{
this.property = property;
needPropertyValue = true;
needSerializedValue = true;
}
public bool Deserialized {
@@ -83,6 +84,8 @@ namespace System.Configuration
propertyValue = GetDeserializedValue (serializedValue);
if (propertyValue == null) {
propertyValue = GetDeserializedDefaultValue ();
serializedValue = null;
needSerializedValue = true;
defaulted = true;
}
needPropertyValue = false;
@@ -107,9 +110,7 @@ namespace System.Configuration
public object SerializedValue {
get {
if (needSerializedValue) {
needSerializedValue = false;
if ((needSerializedValue || IsDirty) && !UsingDefaultValue) {
switch (property.SerializeAs)
{
case SettingsSerializeAs.String:
@@ -143,6 +144,8 @@ namespace System.Configuration
break;
}
needSerializedValue = false;
dirty = false;
}
return serializedValue;
@@ -150,6 +153,7 @@ namespace System.Configuration
set {
serializedValue = value;
needPropertyValue = true;
needSerializedValue = false;
}
}
@@ -165,6 +169,7 @@ namespace System.Configuration
dirty = true;
defaulted = true;
needPropertyValue = true;
needSerializedValue = true;
return propertyValue;
}

View File

@@ -127,7 +127,7 @@ namespace System.Diagnostics {
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern IntPtr GetImpl (string category, string counter,
string instance, string machine, out PerformanceCounterType ctype, out bool custom);
string instance, out PerformanceCounterType ctype, out bool custom);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern bool GetSample (IntPtr impl, bool only_value, out CounterSample sample);
@@ -138,6 +138,11 @@ namespace System.Diagnostics {
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern void FreeData (IntPtr impl);
static bool IsValidMachine (string machine)
{ // no support for counters on other machines
return machine == ".";
}
/* the perf counter has changed, ensure it's valid and setup it to
* be able to collect/update data
*/
@@ -146,7 +151,9 @@ namespace System.Diagnostics {
// need to free the previous info
if (impl != IntPtr.Zero)
Close ();
impl = GetImpl (categoryName, counterName, instanceName, machineName, out type, out is_custom);
if (IsValidMachine (machineName))
impl = GetImpl (categoryName, counterName, instanceName, out type, out is_custom);
// system counters are always readonly
if (!is_custom)
readOnly = true;

View File

@@ -44,27 +44,27 @@ namespace System.Diagnostics
static extern bool CategoryDelete (string name);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern string CategoryHelpInternal (string category, string machine);
static extern string CategoryHelpInternal (string category);
/* this icall allows a null counter and it will just search for the category */
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern bool CounterCategoryExists (string counter, string category, string machine);
static extern bool CounterCategoryExists (string counter, string category);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern bool Create (string categoryName, string categoryHelp,
PerformanceCounterCategoryType categoryType, CounterCreationData[] items);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern int InstanceExistsInternal (string instance, string category, string machine);
static extern bool InstanceExistsInternal (string instance, string category);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern string[] GetCategoryNames (string machine);
static extern string[] GetCategoryNames ();
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern string[] GetCounterNames (string category, string machine);
static extern string[] GetCounterNames (string category);
[MethodImplAttribute (MethodImplOptions.InternalCall)]
static extern string[] GetInstanceNames (string category, string machine);
static extern string[] GetInstanceNames (string category);
static void CheckCategory (string categoryName) {
if (categoryName == null)
@@ -95,10 +95,17 @@ namespace System.Diagnostics
this.machineName = machineName;
}
static bool IsValidMachine (string machine)
{ // no support for counters on other machines
return machine == ".";
}
// may throw InvalidOperationException, Win32Exception
public string CategoryHelp {
get {
string res = CategoryHelpInternal (categoryName, machineName);
string res = null;
if (IsValidMachine (machineName))
res = CategoryHelpInternal (categoryName);
if (res != null)
return res;
throw new InvalidOperationException ();
@@ -154,7 +161,8 @@ namespace System.Diagnostics
CheckCategory (categoryName);
if (machineName == null)
throw new ArgumentNullException ("machineName");
return CounterCategoryExists (counterName, categoryName, machineName);
return IsValidMachine (machineName)
&& CounterCategoryExists (counterName, categoryName);
}
[Obsolete ("Use another overload that uses PerformanceCounterCategoryType instead")]
@@ -227,7 +235,8 @@ namespace System.Diagnostics
public static bool Exists (string categoryName, string machineName)
{
CheckCategory (categoryName);
return CounterCategoryExists (null, categoryName, machineName);
return IsValidMachine (machineName) &&
CounterCategoryExists (null, categoryName);
}
public static PerformanceCounterCategory[] GetCategories ()
@@ -239,7 +248,11 @@ namespace System.Diagnostics
{
if (machineName == null)
throw new ArgumentNullException ("machineName");
string[] catnames = GetCategoryNames (machineName);
if (!IsValidMachine (machineName))
return Array.Empty<PerformanceCounterCategory>();
string[] catnames = GetCategoryNames ();
PerformanceCounterCategory[] cats = new PerformanceCounterCategory [catnames.Length];
for (int i = 0; i < catnames.Length; ++i)
cats [i] = new PerformanceCounterCategory (catnames [i], machineName);
@@ -253,7 +266,9 @@ namespace System.Diagnostics
public PerformanceCounter[] GetCounters (string instanceName)
{
string[] countnames = GetCounterNames (categoryName, machineName);
if (!IsValidMachine (machineName))
return Array.Empty<PerformanceCounter>();
string[] countnames = GetCounterNames (categoryName);
PerformanceCounter[] counters = new PerformanceCounter [countnames.Length];
for (int i = 0; i < countnames.Length; ++i) {
counters [i] = new PerformanceCounter (categoryName, countnames [i], instanceName, machineName);
@@ -263,7 +278,9 @@ namespace System.Diagnostics
public string[] GetInstanceNames ()
{
return GetInstanceNames (categoryName, machineName);
if (!IsValidMachine (machineName))
return Array.Empty<string>();
return GetInstanceNames (categoryName);
}
public bool InstanceExists (string instanceName)
@@ -283,12 +300,12 @@ namespace System.Diagnostics
CheckCategory (categoryName);
if (machineName == null)
throw new ArgumentNullException ("machineName");
int val = InstanceExistsInternal (instanceName, categoryName, machineName);
if (val == 0)
return false;
if (val == 1)
return true;
throw new InvalidOperationException ();
//?FIXME: machine appears to be wrong
//if (!IsValidMachine (machineName))
//return false;
return InstanceExistsInternal (instanceName, categoryName);
}
[MonoTODO]

View File

@@ -47,7 +47,7 @@ using System.Text;
using System.Timers;
using System.Net.NetworkInformation;
namespace System.Net.Sockets
namespace System.Net.Sockets
{
public partial class Socket : IDisposable
{
@@ -91,7 +91,14 @@ namespace System.Net.Sockets
int m_IntCleanedUp;
internal bool connect_in_progress;
#region Constructors
#if MONO_WEB_DEBUG
static int nextId;
internal readonly int ID = ++nextId;
#else
internal readonly int ID;
#endif
#region Constructors
public Socket (SocketInformation socketInformation)

File diff suppressed because it is too large Load Diff

View File

@@ -39,6 +39,8 @@ using System.IO;
using System.IO.Compression;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Text;
namespace System.Net
@@ -60,16 +62,28 @@ namespace System.Net
Stream stream;
// Constructors
internal HttpWebResponse (Uri uri, string method, WebConnectionData data, CookieContainer container)
internal HttpWebResponse (Uri uri, string method, HttpStatusCode status, WebHeaderCollection headers)
{
this.uri = uri;
this.method = method;
webHeaders = data.Headers;
version = data.Version;
statusCode = (HttpStatusCode) data.StatusCode;
statusDescription = data.StatusDescription;
stream = data.stream;
this.statusCode = status;
this.statusDescription = HttpStatusDescription.Get (status);
this.webHeaders = headers;
version = HttpVersion.Version10;
contentLength = -1;
}
internal HttpWebResponse (Uri uri, string method, WebResponseStream stream, CookieContainer container)
{
this.uri = uri;
this.method = method;
this.stream = stream;
webHeaders = stream.Headers ?? new WebHeaderCollection ();
version = stream.Version;
statusCode = stream.StatusCode;
statusDescription = stream.StatusDescription ?? HttpStatusDescription.Get (statusCode);
contentLength = -1;
try {
@@ -86,12 +100,12 @@ namespace System.Net
}
string content_encoding = webHeaders ["Content-Encoding"];
if (content_encoding == "gzip" && (data.request.AutomaticDecompression & DecompressionMethods.GZip) != 0) {
stream = new GZipStream (stream, CompressionMode.Decompress);
if (content_encoding == "gzip" && (stream.Request.AutomaticDecompression & DecompressionMethods.GZip) != 0) {
this.stream = new GZipStream (stream, CompressionMode.Decompress);
webHeaders.Remove (HttpRequestHeader.ContentEncoding);
}
else if (content_encoding == "deflate" && (data.request.AutomaticDecompression & DecompressionMethods.Deflate) != 0) {
stream = new DeflateStream (stream, CompressionMode.Decompress);
else if (content_encoding == "deflate" && (stream.Request.AutomaticDecompression & DecompressionMethods.Deflate) != 0) {
this.stream = new DeflateStream (stream, CompressionMode.Decompress);
webHeaders.Remove (HttpRequestHeader.ContentEncoding);
}
}
@@ -154,6 +168,8 @@ namespace System.Net
if (contentType == null)
contentType = webHeaders ["Content-Type"];
if (contentType == null)
contentType = string.Empty;
return contentType;
}
@@ -263,17 +279,6 @@ namespace System.Net
return (value != null) ? value : "";
}
internal void ReadAll ()
{
WebConnectionStream wce = stream as WebConnectionStream;
if (wce == null)
return;
try {
wce.ReadAll ();
} catch {}
}
public override Stream GetResponseStream ()
{
CheckDisposed ();
@@ -310,12 +315,9 @@ namespace System.Net
public override void Close ()
{
if (stream != null) {
Stream st = stream;
stream = null;
if (st != null)
st.Close ();
}
var st = Interlocked.Exchange (ref stream, null);
if (st != null)
st.Close ();
}
void IDisposable.Dispose ()

View File

@@ -1,52 +0,0 @@
//
// IWebConnectionState.cs
//
// Author:
// Martin Baulig <martin.baulig@xamarin.com>
//
// Copyright (c) 2014 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Threading;
namespace System.Net
{
interface IWebConnectionState {
WebConnectionGroup Group {
get;
}
ServicePoint ServicePoint {
get;
}
bool Busy {
get;
}
DateTime IdleSince {
get;
}
bool TrySetBusy ();
void SetIdle ();
}
}

View File

@@ -38,20 +38,15 @@ using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
namespace System.Net
namespace System.Net
{
public class ServicePoint
{
readonly Uri uri;
int connectionLimit;
int maxIdleTime;
int currentConnections;
DateTime idleSince;
DateTime lastDnsResolve;
Version protocolVersion;
IPHostEntry host;
bool usesProxy;
Dictionary<string,WebConnectionGroup> groups;
bool sendContinue = true;
bool useConnect;
object hostE = new object ();
@@ -60,21 +55,22 @@ namespace System.Net
bool tcp_keepalive;
int tcp_keepalive_time;
int tcp_keepalive_interval;
Timer idleTimer;
// Constructors
internal ServicePoint (Uri uri, int connectionLimit, int maxIdleTime)
{
this.uri = uri;
this.connectionLimit = connectionLimit;
this.maxIdleTime = maxIdleTime;
this.currentConnections = 0;
this.idleSince = DateTime.UtcNow;
this.uri = uri;
Scheduler = new ServicePointScheduler (this, connectionLimit, maxIdleTime);
}
internal ServicePointScheduler Scheduler {
get;
}
// Properties
public Uri Address {
get { return uri; }
}
@@ -84,15 +80,13 @@ namespace System.Net
return new NotImplementedException ();
}
public BindIPEndPoint BindIPEndPointDelegate
{
public BindIPEndPoint BindIPEndPointDelegate {
get { return endPointCallback; }
set { endPointCallback = value; }
}
[MonoTODO]
public int ConnectionLeaseTimeout
{
public int ConnectionLeaseTimeout {
get {
throw GetMustImplement ();
}
@@ -100,54 +94,39 @@ namespace System.Net
throw GetMustImplement ();
}
}
public int ConnectionLimit {
get { return connectionLimit; }
set {
if (value <= 0)
throw new ArgumentOutOfRangeException ();
connectionLimit = value;
}
public int ConnectionLimit {
get { return Scheduler.ConnectionLimit; }
set { Scheduler.ConnectionLimit = value; }
}
public string ConnectionName {
get { return uri.Scheme; }
}
public int CurrentConnections {
get {
return currentConnections;
return Scheduler.CurrentConnections;
}
}
public DateTime IdleSince {
get {
return idleSince.ToLocalTime ();
return Scheduler.IdleSince.ToLocalTime ();
}
}
public int MaxIdleTime {
get { return maxIdleTime; }
set {
if (value < Timeout.Infinite || value > Int32.MaxValue)
throw new ArgumentOutOfRangeException ();
lock (this) {
maxIdleTime = value;
if (idleTimer != null)
idleTimer.Change (maxIdleTime, maxIdleTime);
}
}
get { return Scheduler.MaxIdleTime; }
set { Scheduler.MaxIdleTime = value; }
}
public virtual Version ProtocolVersion {
get { return protocolVersion; }
}
[MonoTODO]
public int ReceiveBufferSize
{
public int ReceiveBufferSize {
get {
throw GetMustImplement ();
}
@@ -155,7 +134,7 @@ namespace System.Net
throw GetMustImplement ();
}
}
public bool SupportsPipelining {
get { return HttpVersion.Version11.Equals (protocolVersion); }
}
@@ -172,8 +151,10 @@ namespace System.Net
}
internal bool SendContinue {
get { return sendContinue &&
(protocolVersion == null || protocolVersion == HttpVersion.Version11); }
get {
return sendContinue &&
(protocolVersion == null || protocolVersion == HttpVersion.Version11);
}
set { sendContinue = value; }
}
// Methods
@@ -197,25 +178,25 @@ namespace System.Net
if (!tcp_keepalive)
return;
byte [] bytes = new byte [12];
PutBytes (bytes, (uint) (tcp_keepalive ? 1 : 0), 0);
PutBytes (bytes, (uint) tcp_keepalive_time, 4);
PutBytes (bytes, (uint) tcp_keepalive_interval, 8);
byte[] bytes = new byte[12];
PutBytes (bytes, (uint)(tcp_keepalive ? 1 : 0), 0);
PutBytes (bytes, (uint)tcp_keepalive_time, 4);
PutBytes (bytes, (uint)tcp_keepalive_interval, 8);
socket.IOControl (IOControlCode.KeepAliveValues, bytes, null);
}
static void PutBytes (byte [] bytes, uint v, int offset)
static void PutBytes (byte[] bytes, uint v, int offset)
{
if (BitConverter.IsLittleEndian) {
bytes [offset] = (byte) (v & 0x000000ff);
bytes [offset + 1] = (byte) ((v & 0x0000ff00) >> 8);
bytes [offset + 2] = (byte) ((v & 0x00ff0000) >> 16);
bytes [offset + 3] = (byte) ((v & 0xff000000) >> 24);
bytes[offset] = (byte)(v & 0x000000ff);
bytes[offset + 1] = (byte)((v & 0x0000ff00) >> 8);
bytes[offset + 2] = (byte)((v & 0x00ff0000) >> 16);
bytes[offset + 3] = (byte)((v & 0xff000000) >> 24);
} else {
bytes [offset + 3] = (byte) (v & 0x000000ff);
bytes [offset + 2] = (byte) ((v & 0x0000ff00) >> 8);
bytes [offset + 1] = (byte) ((v & 0x00ff0000) >> 16);
bytes [offset] = (byte) ((v & 0xff000000) >> 24);
bytes[offset + 3] = (byte)(v & 0x000000ff);
bytes[offset + 2] = (byte)((v & 0x0000ff00) >> 8);
bytes[offset + 1] = (byte)((v & 0x00ff0000) >> 16);
bytes[offset] = (byte)((v & 0xff000000) >> 24);
}
}
@@ -231,107 +212,7 @@ namespace System.Net
set { useConnect = value; }
}
WebConnectionGroup GetConnectionGroup (string name)
{
if (name == null)
name = "";
/*
* Optimization:
*
* In the vast majority of cases, we only have one single WebConnectionGroup per ServicePoint, so we
* don't need to allocate a dictionary.
*
*/
WebConnectionGroup group;
if (groups != null && groups.TryGetValue (name, out group))
return group;
group = new WebConnectionGroup (this, name);
group.ConnectionClosed += (s, e) => currentConnections--;
if (groups == null)
groups = new Dictionary<string, WebConnectionGroup> ();
groups.Add (name, group);
return group;
}
void RemoveConnectionGroup (WebConnectionGroup group)
{
if (groups == null || groups.Count == 0)
throw new InvalidOperationException ();
groups.Remove (group.Name);
}
bool CheckAvailableForRecycling (out DateTime outIdleSince)
{
outIdleSince = DateTime.MinValue;
TimeSpan idleTimeSpan;
List<WebConnectionGroup> groupList = null, removeList = null;
lock (this) {
if (groups == null || groups.Count == 0) {
idleSince = DateTime.MinValue;
return true;
}
idleTimeSpan = TimeSpan.FromMilliseconds (maxIdleTime);
/*
* WebConnectionGroup.TryRecycle() must run outside the lock, so we need to
* copy the group dictionary if it exists.
*
* In most cases, we only have a single connection group, so we can simply store
* that in a local variable instead of copying a collection.
*
*/
groupList = new List<WebConnectionGroup> (groups.Values);
}
foreach (var group in groupList) {
if (!group.TryRecycle (idleTimeSpan, ref outIdleSince))
continue;
if (removeList == null)
removeList = new List<WebConnectionGroup> ();
removeList.Add (group);
}
lock (this) {
idleSince = outIdleSince;
if (removeList != null && groups != null) {
foreach (var group in removeList)
if (groups.ContainsKey (group.Name))
RemoveConnectionGroup (group);
}
if (groups != null && groups.Count == 0)
groups = null;
if (groups == null) {
if (idleTimer != null) {
idleTimer.Dispose ();
idleTimer = null;
}
return true;
}
return false;
}
}
void IdleTimerCallback (object obj)
{
DateTime dummy;
CheckAvailableForRecycling (out dummy);
}
private bool HasTimedOut
{
private bool HasTimedOut {
get {
int timeout = ServicePointManager.DnsRefreshTimeout;
return timeout != Timeout.Infinite &&
@@ -339,8 +220,7 @@ namespace System.Net
}
}
internal IPHostEntry HostEntry
{
internal IPHostEntry HostEntry {
get {
lock (hostE) {
string uriHost = uri.Host;
@@ -356,7 +236,7 @@ namespace System.Net
}
// Creates IPHostEntry
host = new IPHostEntry();
host = new IPHostEntry ();
host.AddressList = new IPAddress[] { IPAddress.Parse (uriHost) };
return host;
}
@@ -382,41 +262,18 @@ namespace System.Net
protocolVersion = version;
}
internal EventHandler SendRequest (HttpWebRequest request, string groupName)
internal void SendRequest (WebOperation operation, string groupName)
{
WebConnection cnc;
lock (this) {
bool created;
WebConnectionGroup cncGroup = GetConnectionGroup (groupName);
cnc = cncGroup.GetConnection (request, out created);
if (created) {
++currentConnections;
if (idleTimer == null)
idleTimer = new Timer (IdleTimerCallback, null, maxIdleTime, maxIdleTime);
}
Scheduler.SendRequest (operation, groupName);
}
return cnc.SendRequest (request);
}
public bool CloseConnectionGroup (string connectionGroupName)
{
WebConnectionGroup cncGroup = null;
lock (this) {
cncGroup = GetConnectionGroup (connectionGroupName);
if (cncGroup != null) {
RemoveConnectionGroup (cncGroup);
}
return Scheduler.CloseConnectionGroup (connectionGroupName);
}
// WebConnectionGroup.Close() must *not* be called inside the lock
if (cncGroup != null) {
cncGroup.Close ();
return true;
}
return false;
}
//

File diff suppressed because it is too large Load Diff

View File

@@ -1,232 +0,0 @@
//
// SimpleAsyncResult.cs
//
// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
// Martin Baulig (martin.baulig@xamarin.com)
//
// (C) 2003 Ximian, Inc (http://www.ximian.com)
// Copyright (c) 2014 Xamarin Inc. (http://www.xamarin.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.IO;
using System.Threading;
namespace System.Net
{
delegate void SimpleAsyncCallback (SimpleAsyncResult result);
class SimpleAsyncResult : IAsyncResult
{
ManualResetEvent handle;
bool synch;
bool isCompleted;
readonly SimpleAsyncCallback cb;
object state;
bool callbackDone;
Exception exc;
object locker = new object ();
SimpleAsyncResult (SimpleAsyncCallback cb)
{
this.cb = cb;
}
protected SimpleAsyncResult (AsyncCallback cb, object state)
{
this.state = state;
this.cb = result => {
if (cb != null)
cb (this);
};
}
public static void Run (Func<SimpleAsyncResult, bool> func, SimpleAsyncCallback callback)
{
var result = new SimpleAsyncResult (callback);
try {
if (!func (result))
result.SetCompleted (true);
} catch (Exception ex) {
result.SetCompleted (true, ex);
}
}
public static void RunWithLock (object locker, Func<SimpleAsyncResult, bool> func, SimpleAsyncCallback callback)
{
Run (inner => {
bool running = func (inner);
if (running)
Monitor.Exit (locker);
return running;
}, inner => {
if (inner.GotException) {
if (inner.synch)
Monitor.Exit (locker);
callback (inner);
return;
}
try {
if (!inner.synch)
Monitor.Enter (locker);
callback (inner);
} finally {
Monitor.Exit (locker);
}
});
}
protected void Reset_internal ()
{
callbackDone = false;
exc = null;
lock (locker) {
isCompleted = false;
if (handle != null)
handle.Reset ();
}
}
internal void SetCompleted (bool synch, Exception e)
{
SetCompleted_internal (synch, e);
DoCallback_private ();
}
internal void SetCompleted (bool synch)
{
SetCompleted_internal (synch);
DoCallback_private ();
}
void SetCompleted_internal (bool synch, Exception e)
{
this.synch = synch;
exc = e;
lock (locker) {
isCompleted = true;
if (handle != null)
handle.Set ();
}
}
protected void SetCompleted_internal (bool synch)
{
SetCompleted_internal (synch, null);
}
void DoCallback_private ()
{
if (callbackDone)
return;
callbackDone = true;
if (cb == null)
return;
cb (this);
}
protected void DoCallback_internal ()
{
if (!callbackDone && cb != null) {
callbackDone = true;
cb (this);
}
}
internal void WaitUntilComplete ()
{
if (IsCompleted)
return;
AsyncWaitHandle.WaitOne ();
}
internal bool WaitUntilComplete (int timeout, bool exitContext)
{
if (IsCompleted)
return true;
return AsyncWaitHandle.WaitOne (timeout, exitContext);
}
public object AsyncState {
get { return state; }
}
public WaitHandle AsyncWaitHandle {
get {
lock (locker) {
if (handle == null)
handle = new ManualResetEvent (isCompleted);
}
return handle;
}
}
bool? user_read_synch;
public bool CompletedSynchronously {
get {
//
// CompletedSynchronously (for System.Net networking stack) means "was the operation completed before the first time
// that somebody asked if it was completed synchronously"? They do this because some of their asynchronous operations
// (particularly those in the Socket class) will avoid the cost of capturing and transferring the ExecutionContext
// to the callback thread by checking CompletedSynchronously, and calling the callback from within BeginXxx instead of
// on the completion port thread if the native winsock call completes quickly.
//
// TODO: racy
if (user_read_synch != null)
return user_read_synch.Value;
user_read_synch = synch;
return user_read_synch.Value;
}
}
internal bool CompletedSynchronouslyPeek {
get {
return synch;
}
}
public bool IsCompleted {
get {
lock (locker) {
return isCompleted;
}
}
}
internal bool GotException {
get { return (exc != null); }
}
internal Exception Exception {
get { return exc; }
}
}
}

View File

@@ -1,132 +0,0 @@
//
// System.Net.WebAsyncResult
//
// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
// (C) 2003 Ximian, Inc (http://www.ximian.com)
//
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System.IO;
using System.Threading;
namespace System.Net
{
class WebAsyncResult : SimpleAsyncResult
{
int nbytes;
IAsyncResult innerAsyncResult;
HttpWebResponse response;
Stream writeStream;
byte [] buffer;
int offset;
int size;
public bool EndCalled;
public bool AsyncWriteAll;
public HttpWebRequest AsyncObject;
public WebAsyncResult (AsyncCallback cb, object state)
: base (cb, state)
{
}
public WebAsyncResult (HttpWebRequest request, AsyncCallback cb, object state)
: base (cb, state)
{
this.AsyncObject = request;
}
public WebAsyncResult (AsyncCallback cb, object state, byte [] buffer, int offset, int size)
: base (cb, state)
{
this.buffer = buffer;
this.offset = offset;
this.size = size;
}
internal void Reset ()
{
this.nbytes = 0;
this.response = null;
this.buffer = null;
this.offset = 0;
this.size = 0;
Reset_internal ();
}
internal void SetCompleted (bool synch, int nbytes)
{
this.nbytes = nbytes;
SetCompleted_internal (synch);
}
internal void SetCompleted (bool synch, Stream writeStream)
{
this.writeStream = writeStream;
SetCompleted_internal (synch);
}
internal void SetCompleted (bool synch, HttpWebResponse response)
{
this.response = response;
SetCompleted_internal (synch);
}
internal void DoCallback ()
{
DoCallback_internal ();
}
internal int NBytes {
get { return nbytes; }
set { nbytes = value; }
}
internal IAsyncResult InnerAsyncResult {
get { return innerAsyncResult; }
set { innerAsyncResult = value; }
}
internal Stream WriteStream {
get { return writeStream; }
}
internal HttpWebResponse Response {
get { return response; }
}
internal byte [] Buffer {
get { return buffer; }
}
internal int Offset {
get { return offset; }
}
internal int Size {
get { return size; }
}
}
}

View File

@@ -0,0 +1,155 @@
//
// WebCompletionSource.cs
//
// Author:
// Martin Baulig <mabaul@microsoft.com>
//
// Copyright (c) 2018 Xamarin Inc. (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.ExceptionServices;
namespace System.Net
{
class WebCompletionSource<T>
{
TaskCompletionSource<Result> completion;
Result currentResult;
public WebCompletionSource (bool runAsync = true)
{
completion = new TaskCompletionSource<Result> (
runAsync ?
TaskCreationOptions.RunContinuationsAsynchronously :
TaskCreationOptions.None);
}
/*
* Provide a non-blocking way of getting the current status.
*
* We are using `TaskCreationOptions.RunContinuationsAsynchronously`
* to prevent any user continuations from being run during the
* `TrySet*()` methods - to make these safe to be called while holding
* internal locks.
*
*/
internal Result CurrentResult => currentResult;
internal Status CurrentStatus => currentResult?.Status ?? Status.Running;
internal Task Task => completion.Task;
public bool TrySetCompleted (T argument)
{
var result = new Result (argument);
if (Interlocked.CompareExchange (ref currentResult, result, null) != null)
return false;
return completion.TrySetResult (result);
}
public bool TrySetCompleted ()
{
var result = new Result (Status.Completed, null);
if (Interlocked.CompareExchange (ref currentResult, result, null) != null)
return false;
return completion.TrySetResult (result);
}
public bool TrySetCanceled ()
{
return TrySetCanceled (new OperationCanceledException ());
}
public bool TrySetCanceled (OperationCanceledException error)
{
var result = new Result (Status.Canceled, ExceptionDispatchInfo.Capture (error));
if (Interlocked.CompareExchange (ref currentResult, result, null) != null)
return false;
return completion.TrySetResult (result);
}
public bool TrySetException (Exception error)
{
var result = new Result (Status.Faulted, ExceptionDispatchInfo.Capture (error));
if (Interlocked.CompareExchange (ref currentResult, result, null) != null)
return false;
return completion.TrySetResult (result);
}
public void ThrowOnError ()
{
if (!completion.Task.IsCompleted)
return;
completion.Task.Result.Error?.Throw ();
}
public async Task<T> WaitForCompletion ()
{
var result = await completion.Task.ConfigureAwait (false);
if (result.Status == Status.Completed)
return (T)result.Argument;
// This will always throw once we get here.
result.Error.Throw ();
throw new InvalidOperationException ("Should never happen.");
}
internal enum Status : int {
Running,
Completed,
Canceled,
Faulted
}
internal class Result
{
public Status Status {
get;
}
public bool Success => Status == Status.Completed;
public ExceptionDispatchInfo Error {
get;
}
public T Argument {
get;
}
public Result (T argument)
{
Status = Status.Completed;
Argument = argument;
}
public Result (Status state, ExceptionDispatchInfo error)
{
Status = state;
Error = error;
}
}
}
class WebCompletionSource : WebCompletionSource<object>
{
}
}

Some files were not shown because too many files have changed in this diff Show More