[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #43099
{
"name": "ms-test-suite",
"url": "git@github.com:xamarin/ms-test-suite.git",
- "rev": "840653918efed24f00f5e166094f06354cae7255",
+ "rev": "bcd16462b0b427c582c2b4c81846a42d7ccd527f",
"remote-branch": "origin/master",
"branch": "master",
"directory": "ms-test-suite"
}
-]
\ No newline at end of file
+]
check-ms-test-suite:
@if $(MAKE) validate-ms-test-suite RESET_VERSIONS=1; then \
- $(MAKE) -C $(MSTESTSUITE_PATH)/conformance build MCS="$(MCS) -t:library -warn:1 -r:nunit.framework" && \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/conformance build MCS="$(MCS) -debug -t:library -warn:1 -r:nunit.framework" && \
$(MAKE) -C $(MSTESTSUITE_PATH)/conformance run NUNIT-CONSOLE="$(RUNTIME) $(CLASS)/nunit-console.exe -nologo -exclude=MonoBug,BadTest" NUNIT_XML_RESULT=$(abs_top_builddir)/acceptance-tests/TestResult-ms-test-suite-conformance.xml || EXIT_CODE=1; \
$(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup build MCS="$(MCS) -debug -warn:1" && \
$(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup run MONO="$(RUNTIME)" || EXIT_CODE=1; \
exit $$EXIT_CODE; \
else \
echo "*** [ms-test-suite] Getting the repository failed, you probably don't have access to this Xamarin-internal resource. Skipping."; \
- fi
\ No newline at end of file
+ fi
-Subproject commit 7065bc89e8661cad447140752c0fce118644e06e
+Subproject commit 4bc79a6da1f0ee538560b7e4d0caff46d3c86e4f
--- /dev/null
+namespace System.Data.SqlClient
+{
+ public enum PoolBlockingPeriod
+ {
+ Auto,
+ AlwaysBlock,
+ NeverBlock
+ }
+}
\ No newline at end of file
public const string SQLCR_UnrecoverableServer = "The connection is broken and recovery is not possible. The connection is marked by the server as unrecoverable. No attempt was made to restore the connection.";
public const string SQLCR_UnrecoverableClient = "The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.";
public const string SQLCR_NoCRAckAtReconnection = "The server did not acknowledge a recovery attempt, connection recovery is not possible.";
+
+ public const string AZURESQL_GenericEndpoint = ".database.windows.net";
+ public const string AZURESQL_GermanEndpoint = ".database.cloudapi.de";
+ public const string AZURESQL_UsGovEndpoint = ".database.usgovcloudapi.net";
+ public const string AZURESQL_ChinaEndpoint = ".database.chinacloudapi.cn";
+ public const string DbConnectionString_PoolBlockingPeriod = "Defines the blocking period behavior for a connection pool.";
+ public const string SQL_Timeout_Execution = "Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.";
}
../../build/common/AssemblyRef.cs
ReferenceSources/NativeOledbWrapper.cs
+ReferenceSources/PoolBlockingPeriod.cs
ReferenceSources/Res.cs
ReferenceSources/Res.missing.cs
ReferenceSources/ResCategoryAttribute.cs
../../build/common/AssemblyRef.cs
ReferenceSources/NativeOledbWrapper.cs
+ReferenceSources/PoolBlockingPeriod.cs
ReferenceSources/Res.cs
ReferenceSources/Res.missing.cs
ReferenceSources/ResCategoryAttribute.cs
+++ /dev/null
-using System;
-using System.Runtime.InteropServices;
-
-namespace System.Runtime.Caching {
- /*
- * This class is used to retrieve the size of an object graph.
- * Although Mono has not a way of computing this.
- * Known problems:
- * - CacheMemoryMonitor does not trim the cache when it reaches its memory size limit.
- * - IMemoryCacheManager.UpdateCacheSize is called with incorrect size.
- */
- internal class SRef {
-
-// private Object _sizedRef;
-
- internal SRef (Object target) {
-// _sizedRef = target;
- }
-
- internal long ApproximateSize {
- get {
- // TODO: .net uses System.SizedReference which contains approximate size after Gen 2 collection
- return 16;
- }
- }
-
- internal void Dispose() {
-
- }
- }
-}
\ No newline at end of file
ReferenceSources/CacheExpires.cs
ReferenceSources/CacheUsage.cs
ReferenceSources/R.Designer.cs
-ReferenceSources/SRef.cs
../referencesource/System.Runtime.Caching/Resources/RH.cs
../referencesource/System.Runtime.Caching/System/Caching/CacheEntryChangeMonitor.cs
../referencesource/System.Runtime.Caching/System/Caching/CacheEntryRemovedArguments.cs
../referencesource/System.Runtime.Caching/System/Caching/SafeBitVector32.cs
../referencesource/System.Runtime.Caching/System/Caching/SafeRegistryHandle.cs
../referencesource/System.Runtime.Caching/System/Caching/SqlChangeMonitor.cs
+../referencesource/System.Runtime.Caching/System/Caching/SRef.cs
--- /dev/null
+namespace System
+{
+ static class LocalAppContextSwitches
+ {
+ public static readonly bool DoNotUseTimeZoneInfo = false;
+ }
+}
\ No newline at end of file
ReferenceSources/DiagnosticUtility.cs
ReferenceSources/FxTrace.cs
+ReferenceSources/LocalAppContextSwitches.cs
ReferenceSources/SR.cs
ReferenceSources/SR.missing.cs
ReferenceSources/XmlExceptionHelper.cs
../referencesource/System.Web/Hosting/IProcessHostSupportFunctions.cs
../referencesource/System.Web/Hosting/HTTP_COOKED_URL.cs
../referencesource/System.Web/Hosting/HostingEnvironmentException.cs
+../referencesource/System.Web/Util/Debug.cs
../referencesource/System.Web/Util/SynchronizationContextMode.cs
../referencesource/System.Web/Util/ISyncContextLock.cs
../referencesource/System.Web/Util/DoNotResetAttribute.cs
* Without this everytime a "y" or "yy" comes first in the format, it will always show as
* a 4-digit string if this is not done.
*/
- if (typeof (int).GetType ().GetType ().Name != "MonoType") {
+ if (Type.GetType ("Mono.Runtime") == null) {
// Only do this for MS, not implemented in Mono.
dt.CustomFormat = "y";
Assert.AreEqual ("2007", dt.Text, "#msbug1?");
namespace System
{
- static class LocalAppContextSwitches {
- public const bool IgnoreEmptyKeySequences = false;
- public const bool DontThrowOnInvalidSurrogatePairs = false;
- }
+ static class LocalAppContextSwitches {
+ public static readonly bool IgnoreEmptyKeySequences = false;
+ public static readonly bool DontThrowOnInvalidSurrogatePairs = false;
+ public static readonly bool IgnoreKindInUtcTimeSerialization = false;
+ }
}
\ No newline at end of file
ser.Serialize (sw, d);
string str = sw.ToString ();
- str = RemoveTZ (str, "MyTime");
- str = RemoveTZ (str, "MyTimeNullable");
-
var expected =
"<?xml version=\"1.0\" encoding=\"utf-16\"?>" + Environment.NewLine +
"<root xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + Environment.NewLine +
-" <MyTime>10:00:00.0000000$TZ$</MyTime>" + Environment.NewLine +
-" <MyTimeNullable>10:00:00.0000000$TZ$</MyTimeNullable>" + Environment.NewLine +
+" <MyTime>10:00:00.0000000Z</MyTime>" + Environment.NewLine +
+" <MyTimeNullable>10:00:00.0000000Z</MyTimeNullable>" + Environment.NewLine +
" <MyDate>2012-01-03</MyDate>" + Environment.NewLine +
" <MyDateNullable>2012-01-03</MyDateNullable>" + Environment.NewLine +
"</root>";
Assert.AreEqual (expected, str);
}
-
- static string RemoveTZ (string str, string tag)
- {
- var st = str.IndexOf ("<" + tag + ">");
- var et = str.IndexOf ("</" + tag + ">");
- if (st < 0 || et < 0)
- return str;
-
- var start = str.IndexOfAny (new [] { '+', '-' }, st, et - st);
- return str.Substring (0, start) + "$TZ$" + str.Substring (et, str.Length - et);
- }
}
}
--- /dev/null
+namespace System
+{
+ static class LocalAppContextSwitches
+ {
+ public static readonly bool MemberDescriptorEqualsReturnsFalseIfEquivalent = false;
+ }
+}
\ No newline at end of file
ValidateManual = 0x08,
NoDefaultCred = 0x10,
ValidateAuto = 0x20,
+ SendAuxRecord = 0x00200000,
UseStrongCrypto = 0x00400000
}
get { return false; }
}
+ internal static bool DisableSendAuxRecord {
+ get { return false; }
+ }
+
// Methods
public static void SetTcpKeepAlive (bool enabled, int keepAliveTime, int keepAliveInterval)
{
ReferenceSources/Internal.cs
ReferenceSources/HttpApi.cs
ReferenceSources/HttpSysSettings.cs
+ReferenceSources/LocalAppContextSwitches.cs
ReferenceSources/Logging.cs
ReferenceSources/NativeMethods.cs
ReferenceSources/RequestCacheProtocol.cs
Uri uri;
Assert.IsTrue (Uri.TryCreate (value, UriKind.Absolute, out uri));
}
+
+ [Test]
+ public void UncValidPath ()
+ {
+ var uri = new Uri ("https://_foo/bar.html");
+ Assert.AreEqual ("https", uri.Scheme);
+ }
}
}
ReferenceSources/EnvironmentHelpers.cs
ReferenceSources/HttpApi.cs
ReferenceSources/Internal.cs
+ReferenceSources/LocalAppContextSwitches.cs
ReferenceSources/HttpSysSettings.cs
ReferenceSources/Logging.cs
ReferenceSources/NativeMethods.cs
namespace System {
static class AppContextSwitches {
- public const bool ThrowExceptionIfDisposedCancellationTokenSource = true;
+ public static readonly bool ThrowExceptionIfDisposedCancellationTokenSource = true;
+ public static readonly bool SetActorAsReferenceWhenCopyingClaimsIdentity = false;
}
}
\ No newline at end of file
--- /dev/null
+namespace System.IO
+{
+ static class PathInternal
+ {
+ public static bool IsPartiallyQualified (string path)
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
{
if (s == null)
throw new ArgumentNullException ("s");
- int len = s.Length;
- IntPtr ctm = AllocCoTaskMem ((len+1) * 2 + 4);
- byte [] buffer = null;
- WriteInt32 (ctm, 0, len*2);
- try {
- buffer = s.GetBuffer ();
- for (int i = 0; i < len; i++)
- WriteInt16 (ctm, 4 + (i * 2), (short) ((buffer [(i*2)] << 8) | (buffer [i*2+1])));
- WriteInt16 (ctm, 4 + buffer.Length, 0);
- } finally {
- if (buffer != null)
- for (int i = buffer.Length; i > 0; ){
- i--;
- buffer [i] = 0;
- }
+ byte[] buffer = s.GetBuffer ();
+ int len = s.Length;
+
+ // SecureString doesn't take endian-ness into account.
+ // Therefore swap bytes here before we send it to c-side if little-endian.
+ if (BitConverter.IsLittleEndian) {
+ for (int i = 0; i < buffer.Length; i += 2) {
+ byte b = buffer[i];
+ buffer[i] = buffer[i + 1];
+ buffer[i + 1] = b;
+ }
}
- return (IntPtr) ((long)ctm + 4);
- }
+ return BufferToBSTR (buffer, len);
+ }
public static IntPtr SecureStringToCoTaskMemAnsi (SecureString s)
{
throw ex;
}
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public extern static IntPtr BufferToBSTR (Array ptr, int slen);
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern static IntPtr UnsafeAddrOfPinnedArrayElement (Array arr, int index);
oid.Add (managedSHA1, oidSHA1);
oid.Add (nameSHA1b, oidSHA1);
oid.Add (nameSHA1c, oidSHA1);
+ oid.Add (nameSHA1Cng, oidSHA1);
oid.Add (nameMD5, oidMD5);
oid.Add (nameMD5a, oidMD5);
namespace System.Security.Cryptography {
- [ComVisible (true)]
- public sealed class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm {
+ public partial class RSACryptoServiceProvider {
private const int PROV_RSA_FULL = 1; // from WinCrypt.h
private const int AT_KEYEXCHANGE = 1;
private const int AT_SIGNATURE = 2;
// no need to load - it cannot exists
var p = new CspParameters (PROV_RSA_FULL);
- if (useMachineKeyStore)
+ if (UseMachineKeyStore)
p.Flags |= CspProviderFlags.UseMachineKeyStore;
store = new KeyPairPersistence (p);
}
FromXmlString (store.KeyValue);
}
}
-
- private static bool useMachineKeyStore;
-
- public static bool UseMachineKeyStore {
- get { return useMachineKeyStore; }
- set { useMachineKeyStore = value; }
- }
~RSACryptoServiceProvider ()
{
public bool PublicOnly {
get { return rsa.PublicOnly; }
}
-
- public override string SignatureAlgorithm {
- get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; }
- }
-
+
public byte[] Decrypt (byte[] rgb, bool fOAEP)
{
if (rgb == null)
return PKCS1.Sign_v15 (this, hash, rgbHash);
}
+ byte[] SignHash(byte[] rgbHash, int calgHash)
+ {
+ return PKCS1.Sign_v15 (this, InternalHashToHashAlgorithm (calgHash), rgbHash);
+ }
+
+ static HashAlgorithm InternalHashToHashAlgorithm (int calgHash)
+ {
+ switch (calgHash) {
+ case Constants.CALG_MD5:
+ return MD5.Create ();
+ case Constants.CALG_SHA1:
+ return SHA1.Create ();
+ case Constants.CALG_SHA_256:
+ return SHA256.Create ();
+ case Constants.CALG_SHA_384:
+ return SHA384.Create ();
+ case Constants.CALG_SHA_512:
+ return SHA512.Create ();
+ }
+
+ throw new NotImplementedException (calgHash.ToString ());
+ }
+
// NOTE: this method can work with ANY configured (OID in machine.config)
// HashAlgorithm descendant
public bool VerifyData (byte[] buffer, object halg, byte[] signature)
HashAlgorithm hash = HashAlgorithm.Create (hashName);
return PKCS1.Verify_v15 (this, hash, rgbHash, rgbSignature);
}
+
+ bool VerifyHash(byte[] rgbHash, int calgHash, byte[] rgbSignature)
+ {
+ return PKCS1.Verify_v15 (this, InternalHashToHashAlgorithm (calgHash), rgbHash, rgbSignature);
+ }
protected override void Dispose (bool disposing)
{
var p = new CspParameters (PROV_RSA_FULL);
p.KeyNumber = keyBlob [5] == 0x24 ? AT_SIGNATURE : AT_KEYEXCHANGE;
- if (useMachineKeyStore)
+ if (UseMachineKeyStore)
p.Flags |= CspProviderFlags.UseMachineKeyStore;
store = new KeyPairPersistence (p);
}
{
// internal class - we cannot create one without CryptoConfig
SignatureDescription sd = (SignatureDescription) CryptoConfig.CreateFromName ("http://www.w3.org/2000/09/xmldsig#rsa-sha1");
- Assert.AreEqual ("System.Security.Cryptography.SHA1CryptoServiceProvider", sd.DigestAlgorithm);
+ Assert.AreEqual ("System.Security.Cryptography.SHA1Cng", sd.DigestAlgorithm);
Assert.AreEqual ("System.Security.Cryptography.RSAPKCS1SignatureDeformatter", sd.DeformatterAlgorithm);
Assert.AreEqual ("System.Security.Cryptography.RSAPKCS1SignatureFormatter", sd.FormatterAlgorithm);
- Assert.AreEqual ("System.Security.Cryptography.RSACryptoServiceProvider", sd.KeyAlgorithm);
+ Assert.AreEqual ("System.Security.Cryptography.RSA", sd.KeyAlgorithm);
HashAlgorithm hash = sd.CreateDigest();
- Assert.AreEqual ("System.Security.Cryptography.SHA1CryptoServiceProvider", hash.ToString ());
+ Assert.AreEqual ("System.Security.Cryptography.SHA1Cng", hash.ToString ());
- Assert.AreEqual (rsa.ToString (), sd.KeyAlgorithm);
+ Assert.AreEqual ("System.Security.Cryptography.RSA", sd.KeyAlgorithm);
AsymmetricSignatureDeformatter asd = sd.CreateDeformatter (rsa);
Assert.AreEqual ("System.Security.Cryptography.RSAPKCS1SignatureDeformatter", asd.ToString ());
Assert.IsNull (ex.InnerException, "#C3");
Assert.IsNotNull (ex.Message, "#C4");
Assert.IsNotNull (ex.ParamName, "#C5");
- Assert.AreEqual ("byteArray", ex.ParamName, "#C6");
+ Assert.AreEqual ("value", ex.ParamName, "#C6");
}
}
ReferenceSources/win32native.cs
ReferenceSources/SharedStatics.cs
ReferenceSources/SecurityContext.cs
+ReferenceSources/PathInternal.cs
../referencesource/mscorlib/system/__filters.cs
../referencesource/mscorlib/system/__hresults.cs
../referencesource/mscorlib/system/security/cryptography/ripemd160.cs
../referencesource/mscorlib/system/security/cryptography/ripemd160managed.cs
../referencesource/mscorlib/system/security/cryptography/rsa.cs
+../referencesource/mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs
../referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangedeformatter.cs
../referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangeformatter.cs
../referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangedeformatter.cs
trueLabelText = (string)virtualizingContainer.ModelItem.Properties["TrueLabel"].ComputedValue;
}
+ double pixelsPerDip = VisualTreeHelper.GetDpi(trueConnectionPoint).PixelsPerDip;
actualPoint = new Point(trueConnectionPoint.Location.X - origin.X, trueConnectionPoint.Location.Y - origin.Y);
FormattedText trueMarkerFormattedText = new FormattedText(trueLabelText, new System.Globalization.CultureInfo(textCulture),
this.FlowDirection, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize,
- new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor));
+ new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor), pixelsPerDip);
actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2;
actualPoint.X -= trueMarkerFormattedText.WidthIncludingTrailingWhitespace;
actualPoint = new Point(falseConnectionPoint.Location.X - origin.X, falseConnectionPoint.Location.Y - origin.Y);
actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2;
+ double pixelsPerDip = VisualTreeHelper.GetDpi(falseConnectionPoint).PixelsPerDip;
FormattedText falseMarkerFormattedText = new FormattedText(falseLabelText, new System.Globalization.CultureInfo(textCulture),
this.FlowDirection, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize,
- new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor));
+ new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor), pixelsPerDip);
DrawtWithTransform(
drawingContext,
using System;
using System.Activities;
using System.Activities.Debugger;
+ using System.Activities.DynamicUpdate;
using System.Activities.Presentation.View;
using System.Activities.Presentation.ViewState;
using System.Collections.Generic;
XamlDebuggerXmlReader.EndColumnName.MemberName
};
+ // These are used to discover that we have found a DynamicUpdateInfo.OriginalDefintion or OriginalActivityBuilder
+ // attached property member. We have "hardcoded" the *MemberName" here because DynamicUpdateInfo has the
+ // AttachableMemberIdentifier properties marked as private. But the DynamicUpdateInfo class itself is public,
+ // as are the Get and Set methods.
+ static readonly string DynamicUpdateOriginalDefinitionMemberName = "OriginalDefinition";
+ static readonly MethodInfo GetOriginalDefinition = typeof(DynamicUpdateInfo).GetMethod("GetOriginalDefinition");
+ static readonly MethodInfo SetOriginalDefinition = typeof(DynamicUpdateInfo).GetMethod("SetOriginalDefinition");
+
+ static readonly string DynamicUpdateOriginalActivityBuilderMemberName = "OriginalActivityBuilder";
+ static readonly MethodInfo GetOriginalActivityBuilder = typeof(DynamicUpdateInfo).GetMethod("GetOriginalActivityBuilder");
+ static readonly MethodInfo SetOriginalActivityBuilder = typeof(DynamicUpdateInfo).GetMethod("SetOriginalActivityBuilder");
+
// This method collects view state attached properties and generates a Xaml node stream
// with all view state information appearing within the ViewStateManager node.
// It is called when workflow definition is being serialized to string.
// Xaml member definition for IdRef. Used to identify existing IdRef properties in the input nodestream.
XamlMember idRefMember = new XamlMember(IdRef, GetIdRef, SetIdRef, inputReader.SchemaContext);
+ // These are used to ignore the IdRef members that are inside a DynamicUpdateInfo.OriginalDefinition/OriginalActivityBuilder attached property.
+ // We need to ignore these because if we don't, the IdRef values for the objects in the actual workflow defintion will be ignored because of the
+ // duplicate IdRef value. This causes problems with activity designers that depend on the ViewStateManager data to correctly display the workflow
+ // on the WorkflowDesigner canvas.
+ XamlMember originalDefinitionMember = new XamlMember(DynamicUpdateOriginalDefinitionMemberName, GetOriginalDefinition, SetOriginalDefinition, inputReader.SchemaContext);
+ XamlMember originalActivityBuilderMember = new XamlMember(DynamicUpdateOriginalActivityBuilderMemberName, GetOriginalActivityBuilder, SetOriginalActivityBuilder, inputReader.SchemaContext);
+
+ // insideOriginalDefintion gets set to true when we find a "StartMember" node for either of the above two attached properties.
+ // originalDefintionMemberCount gets incremented if we find any "StartMember" and insideOriginalDefinition is true.
+ // originalDefintionMemberCount gets decremented if we find any "EndMember" and insideOriginalDefintion is true.
+ // insideOriginalDefintion gets set to false when we find an "EndMember" and originalDefinitionMemberCount gets decremented to 0.
+ // If insideOriginalDefintion is true when we find an "IdRef" member, we do NOT add that IdRef to the idRefsSeen HashSet to avoid
+ // duplicates being defined by the IdRefs inside of the OriginalDefinition attached properties.
+ bool insideOriginalDefinition = false;
+ int originalDefinitionMemberCount = 0;
+
// Dictionary containing Ids and corresponding viewstate related
// attached property nodes. Populated by StripViewStateElement method.
Dictionary<string, XamlNodeList> viewStateInfo = null;
break;
case XamlNodeType.StartMember:
+ // If we find a StartMember for DynamicUpdateInfo.OriginalDefinition or OriginalActivityBuilder, remember that we are
+ // inside one of those. We don't want to "remember" IdRef values in the idRefsSeen HashSet while inside these attached properties.
+ if (workflowDefinition.Member.Equals(originalDefinitionMember) || workflowDefinition.Member.Equals(originalActivityBuilderMember))
+ {
+ insideOriginalDefinition = true;
+ }
+
+ if (insideOriginalDefinition)
+ {
+ originalDefinitionMemberCount++;
+ }
+
// Track when the reader enters IdRef. Skip writing the start
// node to the output nodelist until we check for duplicates.
- if (workflowDefinition.Member.Equals(idRefMember))
+ else if (workflowDefinition.Member.Equals(idRefMember))
{
inIdRefMember = true;
skipWritingWorkflowDefinition = true;
case XamlNodeType.Value:
if (inIdRefMember)
{
- string idRef = workflowDefinition.Value as string;
- if (!string.IsNullOrWhiteSpace(idRef))
+ // We don't want to deal with the IdRef if we are inside a DynamicUpdateInfo.OriginalDefinition/OriginalActivityBuilder
+ // attached property.
+ if (!insideOriginalDefinition)
{
- // If IdRef value is a duplicate then do not associate it with
- // the stack frame (top of stack == activity node with IdRef member on it).
- if (idRefsSeen.Contains(idRef))
- {
- stack.Peek().IdRef = null;
- }
- // If the IdRef value is unique then associate it with the
- // stack frame and also write its value into the output nodestream.
- else
+ string idRef = workflowDefinition.Value as string;
+ if (!string.IsNullOrWhiteSpace(idRef))
{
- stack.Peek().IdRef = idRef;
- idManager.UpdateMap(idRef);
- idRefsSeen.Add(idRef);
-
- if (shouldPassLineInfo)
+ // If IdRef value is a duplicate then do not associate it with
+ // the stack frame (top of stack == activity node with IdRef member on it).
+ if (idRefsSeen.Contains(idRef))
{
- lineInfoComsumer.SetLineInfo(idRefLineNumber, idRefLinePosition);
+ stack.Peek().IdRef = null;
}
+ // If the IdRef value is unique then associate it with the
+ // stack frame and also write its value into the output nodestream.
+ else
+ {
+ stack.Peek().IdRef = idRef;
+ idManager.UpdateMap(idRef);
+ idRefsSeen.Add(idRef);
- mergedNodeWriter.WriteStartMember(idRefMember);
+ if (shouldPassLineInfo)
+ {
+ lineInfoComsumer.SetLineInfo(idRefLineNumber, idRefLinePosition);
+ }
- if (shouldPassLineInfo)
- {
- lineInfoComsumer.SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition);
- }
+ mergedNodeWriter.WriteStartMember(idRefMember);
- mergedNodeWriter.WriteValue(idRef);
+ if (shouldPassLineInfo)
+ {
+ lineInfoComsumer.SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition);
+ }
- shouldWriteIdRefEndMember = true;
+ mergedNodeWriter.WriteValue(idRef);
+
+ shouldWriteIdRefEndMember = true;
+ }
}
}
// Don't need to write IdRef value into the output
break;
case XamlNodeType.EndMember:
+ // If we are inside an OriginalDefinition/OriginalActivityBuilder attached property,
+ // decrement the count and if it goes to zero, set insideOriginalDefintion to false
+ // because we just encountered the EndMember for it.
+ if (insideOriginalDefinition)
+ {
+ originalDefinitionMemberCount--;
+ if (originalDefinitionMemberCount == 0)
+ {
+ insideOriginalDefinition = false;
+ }
+ }
+
// Exit IdRef node. Skip writing the EndMember node, we would have done
// it as part of reading the IdRef value.
- if (inIdRefMember)
+ if (inIdRefMember && !insideOriginalDefinition)
{
inIdRefMember = false;
skipWritingWorkflowDefinition = true;
mergedNodeWriter.WriteEndMember();
}
}
+
break;
case XamlNodeType.EndObject:
viewStateSourceLocationMap = null;
XamlNodeList strippedNodeList = new XamlNodeList(inputReader.SchemaContext);
XamlMember viewStateManager = new XamlMember(ViewStateManager, GetViewStateManager, SetViewStateManager, inputReader.SchemaContext);
+
using (XamlWriter strippedWriter = strippedNodeList.Writer)
{
IXamlLineInfo lineInfo = inputReader as IXamlLineInfo;
return strippedNodeList.GetReader();
}
-
+
// This method reads ViewStateManager nodes from the xaml nodestream and outputs that in the
// viewStateInfo dictionary. The input reader is positioned on the ViewStateManagerNode in the nodestream.
static void ReadViewStateInfo(XamlReader inputReader, out Dictionary<string, XamlNodeList> viewStateInfo, out Dictionary<string, SourceLocation> viewStateSourceLocationMap)
}
}
}
- else if (globalMemberLevel == 1 && !IsAttachablePropertyForConvert(xamlReader))
+ // The xamlReader.ReadSubtree and subsequent while loop to get the Id member
+ // has moved the xamlReader forward to the next member. We need to check to see
+ // if it is an Attached Property that we care about. If it isn't then we need to
+ // skip it and not put it in the resulting XamlNodeList.
+ if (globalMemberLevel == 1 && !IsAttachablePropertyForConvert(xamlReader))
{
skippingUnexpectedAttachedProperty = true;
}
StackTrace abortStack;
#endif
+ static WorkflowInstance()
+ {
+ try
+ {
+ using (TelemetryEventSource eventSource = new TelemetryEventSource())
+ {
+ eventSource.V2Runtime();
+ }
+ }
+ catch
+ {
+ }
+ }
+
protected WorkflowInstance(Activity workflowDefinition)
: this(workflowDefinition, null)
{
IList<Handle> rootExecutionProperties;
IDictionary<XName, InstanceValue> instanceMetadata;
-
+
public WorkflowApplication(Activity workflowDefinition)
: this(workflowDefinition, (WorkflowIdentity)null)
{
}
public static void SetDefaultsLessOrEqual_46() {
+#pragma warning disable BCL0012 //disable warning about AppContextDefaults not following the recommended pattern
// Define the switches that should be true for 4.6 or less, false for 4.6.1+.
LocalAppContext.DefineSwitchDefault(UseLegacyRegExTimeoutString, true);
+#pragma warning restore BCL0012
}
}
}
-using System.ComponentModel.DataAnnotations.Resources;
+using System.ComponentModel.DataAnnotations.Resources;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;
/// Gets or sets the timeout to use when matching the regular expression pattern (in milliseconds)
/// (-1 means never timeout).
/// </summary>
- public int MatchTimeoutInMilliseconds { get; set; } = GetDefaultTimeout();
+ public int MatchTimeoutInMilliseconds {
+ get {
+ return _matchTimeoutInMilliseconds;
+ }
+ set {
+ _matchTimeoutInMilliseconds = value;
+ _matchTimeoutSet = true;
+ }
+ }
+
+ private int _matchTimeoutInMilliseconds;
+ private bool _matchTimeoutSet;
private Regex Regex { get; set; }
if (string.IsNullOrEmpty(this.Pattern)) {
throw new InvalidOperationException(DataAnnotationsResources.RegularExpressionAttribute_Empty_Pattern);
}
+
+ if (!_matchTimeoutSet) {
+ MatchTimeoutInMilliseconds = GetDefaultTimeout();
+ }
+
Regex = MatchTimeoutInMilliseconds == -1
? new Regex(Pattern)
: Regex = new Regex(Pattern, default(RegexOptions), TimeSpan.FromMilliseconds((double)MatchTimeoutInMilliseconds));
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
+
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
using System;
using System.Collections.Generic;
static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
}
}
+
+#pragma warning restore 436
//
// ==--==
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
// NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches
using System;
using System.Collections.Generic;
}
}
}
+
+#pragma warning restore 436
const string ClickOnceDataDirectory = "DataDirectory";
const string ConfigExtension = ".config";
const int MAX_PATH = 260;
+ const int MAX_UNICODESTRING_LEN = short.MaxValue;
+ const int ERROR_INSUFFICIENT_BUFFER = 122; //https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
const int MAX_LENGTH_TO_USE = 25;
const string FILE_URI_LOCAL = "file:///";
const string FILE_URI_UNC = "file://";
}
else {
StringBuilder sb = new StringBuilder(MAX_PATH);
- UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, IntPtr.Zero), sb, sb.Capacity);
+ int noOfTimes = 1;
+ int length = 0;
+ // Iterating by allocating chunk of memory each time we find the length is not sufficient.
+ // Performance should not be an issue for current MAX_PATH length due to this change.
+ while (((length = UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, IntPtr.Zero), sb, sb.Capacity)) == sb.Capacity)
+ && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER
+ && sb.Capacity < MAX_UNICODESTRING_LEN) {
+ noOfTimes += 2; // increasing buffer size by 520 in each iteration - perf.
+ int capacity = noOfTimes * MAX_PATH < MAX_UNICODESTRING_LEN ? noOfTimes * MAX_PATH : MAX_UNICODESTRING_LEN;
+ sb.EnsureCapacity(capacity);
+ }
+ sb.Length = length;
applicationUri = Path.GetFullPath(sb.ToString());
applicationFilename = applicationUri;
}
#pragma warning restore 618
#endif
internal sealed class SafeCapiHashHandle : SafeCapiHandleBase {
+ private static volatile SafeCapiHashHandle s_invalidHandle;
+
#if FEATURE_CORESYSTEM
[System.Security.SecurityCritical]
#endif
/// </summary>
public static SafeCapiHashHandle InvalidHandle {
get {
- SafeCapiHashHandle handle = new SafeCapiHashHandle();
- handle.SetHandle(IntPtr.Zero);
- return handle;
+ if (s_invalidHandle == null) {
+ // More than one of these might get created in parallel, but that's okay.
+ // Saving one to the field saves on GC tracking, but by SuppressingFinalize on
+ // any instance returned there's already less finalization pressure.
+ SafeCapiHashHandle handle = new SafeCapiHashHandle();
+ handle.SetHandle(IntPtr.Zero);
+ GC.SuppressFinalize(handle);
+ s_invalidHandle = handle;
+ }
+
+ return s_invalidHandle;
}
}
#pragma warning restore 618
#endif
internal sealed class SafeCapiKeyHandle : SafeCapiHandleBase {
+ private static volatile SafeCapiKeyHandle s_invalidHandle;
+
#if FEATURE_CORESYSTEM
[System.Security.SecurityCritical]
#endif
internal static SafeCapiKeyHandle InvalidHandle {
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
get {
- SafeCapiKeyHandle handle = new SafeCapiKeyHandle();
- handle.SetHandle(IntPtr.Zero);
- return handle;
+ if (s_invalidHandle == null) {
+ // More than one of these might get created in parallel, but that's okay.
+ // Saving one to the field saves on GC tracking, but by SuppressingFinalize on
+ // any instance returned there's already less finalization pressure.
+ SafeCapiKeyHandle handle = new SafeCapiKeyHandle();
+ handle.SetHandle(IntPtr.Zero);
+ GC.SuppressFinalize(handle);
+ s_invalidHandle = handle;
+ }
+
+ return s_invalidHandle;
}
}
/// </summary>
Pss = 8 // BCRYPT_PAD_PSS
}
+#if !MONO
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct BCRYPT_DSA_KEY_BLOB_V2
+ {
+ public BCryptNative.KeyBlobMagicNumber dwMagic; // BCRYPT_DSA_PUBLIC_MAGIC_V2 or BCRYPT_DSA_PRIVATE_MAGIC_V2
+ public int cbKey; // key lengths in BYTES (e.g. for a 3072-bit key, cbKey = 3072/8 = 384)
+ public HASHALGORITHM_ENUM hashAlgorithm;
+ public DSAFIPSVERSION_ENUM standardVersion;
+ public int cbSeedLength; // size (in bytes) of the seed value
+ public int cbGroupSize; // size (in bytes) of the Q value
+ public byte Count3; // # of iterations used to generate Q. In big-endian format.
+ public byte Count2;
+ public byte Count1;
+ public byte Count0;
+ }
+#endif
+ internal enum HASHALGORITHM_ENUM : int
+ {
+ DSA_HASH_ALGORITHM_SHA1 = 0,
+ DSA_HASH_ALGORITHM_SHA256 = 1,
+ DSA_HASH_ALGORITHM_SHA512 = 2,
+ }
+
+ internal enum DSAFIPSVERSION_ENUM : int
+ {
+ DSA_FIPS186_2 = 0,
+ DSA_FIPS186_3 = 1,
+ }
+
/// <summary>
/// Native interop with CNG's BCrypt layer. Native definitions can be found in bcrypt.h
/// </summary>
/// Magic numbers identifying blob types
/// </summary>
internal enum KeyBlobMagicNumber {
+ DsaPublic = 0x42505344, // BCRYPT_DSA_PUBLIC_MAGIC for key lengths <= 1024 bits
+ DsaPublicV2 = 0x32425044, // BCRYPT_DSA_PUBLIC_MAGIC_V2 for key lengths > 1024 bits
+ DsaPrivate = 0x56505344, // BCRYPT_DSA_PRIVATE_MAGIC for key lengths <= 1024 bits
+ DsaPrivateV2 = 0x32565044, // BCRYPT_DSA_PRIVATE_MAGIC_V2 for key lengths > 1024 bits
ECDHPublicP256 = 0x314B4345, // BCRYPT_ECDH_PUBLIC_P256_MAGIC
ECDHPublicP384 = 0x334B4345, // BCRYPT_ECDH_PUBLIC_P384_MAGIC
ECDHPublicP521 = 0x354B4345, // BCRYPT_ECDH_PUBLIC_P521_MAGIC
public IntPtr pbData;
}
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct CERT_DSS_PARAMETERS
+ {
+ public CRYPTOAPI_BLOB p;
+ public CRYPTOAPI_BLOB q;
+ public CRYPTOAPI_BLOB g;
+ }
+
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct PROV_ENUMALGS {
public AlgorithmId aiAlgId;
internal const uint CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY);
internal const uint CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | ALG_SID_RSA_ANY);
internal const uint CNG_RSA_PUBLIC_KEY_BLOB = 72;
+ internal const uint X509_DSS_PUBLICKEY = 38;
+ internal const uint X509_DSS_PARAMETERS = 39;
internal const uint X509_ASN_ENCODING = 0x00000001;
internal const uint PKCS_7_ASN_ENCODING = 0x00010000;
buffer.Length);
}
else {
+ if (!LocalAppContextSwitches.AesCryptoServiceProviderDontCorrectlyResetDecryptor) {
+ resetSize = buffer.Length;
+ }
CapiNative.UnsafeNativeMethods.CryptDecrypt(m_key,
SafeCapiHashHandle.InvalidHandle,
true,
//
public abstract ECDiffieHellmanPublicKey PublicKey { get; }
- public abstract byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey);
+
+ // This method must be implemented by derived classes. In order to conform to the contract, it cannot be abstract.
+ public virtual byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HASH(x) where x is the computed result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public byte[] DeriveKeyFromHash(ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm)
+ {
+ return DeriveKeyFromHash(otherPartyPublicKey, hashAlgorithm, null, null);
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HASH(secretPrepend || x || secretAppend) where x is the computed
+ /// result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <param name="secretPrepend">A value to prepend to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <param name="secretAppend">A value to append to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public virtual byte[] DeriveKeyFromHash(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HMAC(hmacKey, x) where x is the computed
+ /// result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <param name="hmacKey">The key to use in the HMAC. A <c>null</c> value indicates that the result of the EC Diffie-Hellman algorithm should be used as the HMAC key.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey)
+ {
+ return DeriveKeyFromHmac(otherPartyPublicKey, hashAlgorithm, hmacKey, null, null);
+ }
+
+ /// <summary>
+ /// Derive key material using the formula HMAC(hmacKey, secretPrepend || x || secretAppend) where x is the computed
+ /// result of the EC Diffie-Hellman algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="hashAlgorithm">The identifier for the hash algorithm to use.</param>
+ /// <param name="hmacKey">The key to use in the HMAC. A <c>null</c> value indicates that the result of the EC Diffie-Hellman algorithm should be used as the HMAC key.</param>
+ /// <param name="secretPrepend">A value to prepend to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <param name="secretAppend">A value to append to the derived secret before hashing. A <c>null</c> value is treated as an empty array.</param>
+ /// <returns>A hashed output suitable for key material</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ public virtual byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ /// <summary>
+ /// Derive key material using the TLS pseudo-random function (PRF) derivation algorithm.
+ /// </summary>
+ /// <param name="otherPartyPublicKey">The public key of the party with which to derive a mutual secret.</param>
+ /// <param name="prfLabel">The ASCII encoded PRF label.</param>
+ /// <param name="prfSeed">The 64-byte PRF seed.</param>
+ /// <returns>A 48-byte output of the TLS pseudo-random function.</returns>
+ /// <exception cref="ArgumentException"><paramref name="otherPartyPublicKey"/> is over a different curve than this key</exception>
+ /// <exception cref="ArgumentNullException"><paramref name="prfLabel"/> is null</exception>
+ /// <exception cref="ArgumentNullException"><paramref name="prfSeed"/> is null</exception>
+ /// <exception cref="CryptographicException"><paramref name="prfSeed"/> is not exactly 64 bytes in length</exception>
+ public virtual byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ private static Exception DerivedClassMustOverride()
+ {
+ return new NotImplementedException(SR.GetString(SR.NotSupported_SubclassOverride));
+ }
}
}
}
CodeAccessPermission.RevertAssert();
- KeySize = m_key.KeySize;
+ // Our LegalKeySizes value stores the values that we encoded as being the correct
+ // legal key size limitations for this algorithm, as documented on MSDN.
+ //
+ // But on a new OS version we might not question if our limit is accurate, or MSDN
+ // could have been innacurate to start with.
+ //
+ // Since the key is already loaded, we know that Windows thought it to be valid;
+ // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance
+ // check.
+ //
+ // For RSA there are known cases where this change matters. RSACryptoServiceProvider can
+ // create a 384-bit RSA key, which we consider too small to be legal. It can also create
+ // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit
+ // alignment requirement. (In both cases Windows loads it just fine)
+ KeySizeValue = m_key.KeySize;
}
/// <summary>
//
m_key = value;
- KeySize = m_key.KeySize;
+
+ // Our LegalKeySizes value stores the values that we encoded as being the correct
+ // legal key size limitations for this algorithm, as documented on MSDN.
+ //
+ // But on a new OS version we might not question if our limit is accurate, or MSDN
+ // could have been innacurate to start with.
+ //
+ // Since the key is already loaded, we know that Windows thought it to be valid;
+ // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance
+ // check.
+ //
+ // For RSA there are known cases where this change matters. RSACryptoServiceProvider can
+ // create a 384-bit RSA key, which we consider too small to be legal. It can also create
+ // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit
+ // alignment requirement. (In both cases Windows loads it just fine)
+ KeySizeValue = m_key.KeySize;
}
}
}
}
+ [SecuritySafeCritical]
+ public override byte[] DeriveKeyFromHash(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ Contract.Ensures(Contract.Result<byte[]>() != null);
+
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException("otherPartyPublicKey");
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.GetString(SR.Cryptography_HashAlgorithmNameNullOrEmpty), "hashAlgorithm");
+
+ using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey))
+ {
+ return NCryptNative.DeriveKeyMaterialHash(
+ secretAgreement,
+ hashAlgorithm.Name,
+ secretPrepend,
+ secretAppend,
+ NCryptNative.SecretAgreementFlags.None);
+ }
+ }
+
+ [SecuritySafeCritical]
+ public override byte[] DeriveKeyFromHmac(
+ ECDiffieHellmanPublicKey otherPartyPublicKey,
+ HashAlgorithmName hashAlgorithm,
+ byte[] hmacKey,
+ byte[] secretPrepend,
+ byte[] secretAppend)
+ {
+ Contract.Ensures(Contract.Result<byte[]>() != null);
+
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException("otherPartyPublicKey");
+ if (string.IsNullOrEmpty(hashAlgorithm.Name))
+ throw new ArgumentException(SR.GetString(SR.Cryptography_HashAlgorithmNameNullOrEmpty), "hashAlgorithm");
+
+ using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey))
+ {
+ NCryptNative.SecretAgreementFlags flags = hmacKey == null ?
+ NCryptNative.SecretAgreementFlags.UseSecretAsHmacKey :
+ NCryptNative.SecretAgreementFlags.None;
+
+ return NCryptNative.DeriveKeyMaterialHmac(
+ secretAgreement,
+ hashAlgorithm.Name,
+ hmacKey,
+ secretPrepend,
+ secretAppend,
+ flags);
+ }
+ }
+
+ [SecuritySafeCritical]
+ public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed)
+ {
+ Contract.Ensures(Contract.Result<byte[]>() != null);
+
+ if (otherPartyPublicKey == null)
+ throw new ArgumentNullException("otherPartyPublicKey");
+ if (prfLabel == null)
+ throw new ArgumentNullException("prfLabel");
+ if (prfSeed == null)
+ throw new ArgumentNullException("prfSeed");
+
+ using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey))
+ {
+ return NCryptNative.DeriveKeyMaterialTls(
+ secretAgreement,
+ prfLabel,
+ prfSeed,
+ NCryptNative.SecretAgreementFlags.None);
+ }
+ }
+
/// <summary>
/// Get a handle to the secret agreement generated between two parties
/// </summary>
return m_keyBlob.Clone() as byte[];
}
- public abstract string ToXmlString();
+ // This method must be implemented by derived classes. In order to conform to the contract, it cannot be abstract.
+ public virtual string ToXmlString()
+ {
+ throw new NotImplementedException(SR.GetString(SR.NotSupported_SubclassOverride));
+ }
}
}
[SecuritySafeCritical]
public ECDsaCng(CngKey key) {
Contract.Ensures(LegalKeySizesValue != null);
- Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDsa);
+ Contract.Ensures(m_key != null && IsEccAlgorithmGroup(m_key.AlgorithmGroup));
if (key == null) {
throw new ArgumentNullException("key");
}
- if (key.AlgorithmGroup != CngAlgorithmGroup.ECDsa) {
+ if (!IsEccAlgorithmGroup(key.AlgorithmGroup)) {
throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDsaRequiresECDsaKey), "key");
}
}
CodeAccessPermission.RevertAssert();
- KeySize = m_key.KeySize;
+ // Our LegalKeySizes value stores the values that we encoded as being the correct
+ // legal key size limitations for this algorithm, as documented on MSDN.
+ //
+ // But on a new OS version we might not question if our limit is accurate, or MSDN
+ // could have been innacurate to start with.
+ //
+ // Since the key is already loaded, we know that Windows thought it to be valid;
+ // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance
+ // check.
+ //
+ // For RSA there are known cases where this change matters. RSACryptoServiceProvider can
+ // create a 384-bit RSA key, which we consider too small to be legal. It can also create
+ // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit
+ // alignment requirement. (In both cases Windows loads it just fine)
+ KeySizeValue = m_key.KeySize;
}
/// <summary>
public CngKey Key {
get {
Contract.Ensures(Contract.Result<CngKey>() != null);
- Contract.Ensures(Contract.Result<CngKey>().AlgorithmGroup == CngAlgorithmGroup.ECDsa);
- Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDsa);
+ Contract.Ensures(IsEccAlgorithmGroup(Contract.Result<CngKey>().AlgorithmGroup));
+ Contract.Ensures(m_key != null && IsEccAlgorithmGroup(m_key.AlgorithmGroup));
// If the size of the key no longer matches our stored value, then we need to replace it with
// a new key of the correct size.
private set {
Contract.Requires(value != null);
- Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDsa);
+ Contract.Ensures(m_key != null && IsEccAlgorithmGroup(m_key.AlgorithmGroup));
- if (value.AlgorithmGroup != CngAlgorithmGroup.ECDsa) {
+ if (!IsEccAlgorithmGroup(value.AlgorithmGroup)) {
throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDsaRequiresECDsaKey));
}
//
m_key = value;
- KeySize = m_key.KeySize;
+
+ // Our LegalKeySizes value stores the values that we encoded as being the correct
+ // legal key size limitations for this algorithm, as documented on MSDN.
+ //
+ // But on a new OS version we might not question if our limit is accurate, or MSDN
+ // could have been innacurate to start with.
+ //
+ // Since the key is already loaded, we know that Windows thought it to be valid;
+ // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance
+ // check.
+ //
+ // For RSA there are known cases where this change matters. RSACryptoServiceProvider can
+ // create a 384-bit RSA key, which we consider too small to be legal. It can also create
+ // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit
+ // alignment requirement. (In both cases Windows loads it just fine)
+ KeySizeValue = m_key.KeySize;
}
}
return hasher.HashFinal();
}
}
- #endif
+
+ private static bool IsEccAlgorithmGroup(CngAlgorithmGroup algorithmGroup)
+ {
+ // Sometimes, when reading from certificates, ECDSA keys get identified as ECDH.
+ // Windows allows the ECDH keys to perform both key exchange (ECDH) and signing (ECDSA),
+ // so either value is acceptable for the ECDSA wrapper object.
+ //
+ // It is worth noting, however, that ECDSA-identified keys cannot be used for key exchange (ECDH) in CNG.
+ return algorithmGroup == CngAlgorithmGroup.ECDsa || algorithmGroup == CngAlgorithmGroup.ECDiffieHellman;
+ }
+#endif
}
}
signature,
signature.Length,
paddingMode);
- if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
- throw new CryptographicException((int)error);
- }
-
return error == ErrorCode.Success;
}
return signature;
}
+ /// <summary>
+ /// Sign a hash using no padding
+ /// </summary>
+ [System.Security.SecurityCritical]
+ internal static byte[] SignHash(SafeNCryptKeyHandle key, byte[] hash, int expectedSize)
+ {
+ Contract.Requires(key != null);
+ Contract.Requires(hash != null);
+ Contract.Ensures(Contract.Result<byte[]>() != null);
+
+#if DEBUG
+ expectedSize = 1;
+#endif
+
+ // Figure out how big the signature is
+ byte[] signature = new byte[expectedSize];
+ int signatureSize = 0;
+ ErrorCode error = UnsafeNativeMethods.NCryptSignHash(key,
+ IntPtr.Zero,
+ hash,
+ hash.Length,
+ signature,
+ signature.Length,
+ out signatureSize,
+ 0);
+
+ if (error == ErrorCode.BufferTooSmall)
+ {
+ signature = new byte[signatureSize];
+
+ error = UnsafeNativeMethods.NCryptSignHash(key,
+ IntPtr.Zero,
+ hash,
+ hash.Length,
+ signature,
+ signature.Length,
+ out signatureSize,
+ 0);
+ }
+
+ if (error != ErrorCode.Success)
+ {
+ throw new CryptographicException((int)error);
+ }
+
+ Array.Resize(ref signature, signatureSize);
+ return signature;
+ }
+
/// <summary>
/// Unpack a key blob in ECC public blob format into its X and Y parameters
///
signature.Length,
0);
- if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
- throw new CryptographicException((int)error);
- }
-
return error == ErrorCode.Success;
}
}
// If we don't have a key yet, we need to generate a random one now
if (_key == null)
{
- CngKeyCreationParameters creationParameters = new CngKeyCreationParameters();
+ CngKeyCreationParameters creationParameters = new CngKeyCreationParameters()
+ {
+ ExportPolicy = CngExportPolicies.AllowPlaintextExport,
+ };
+
CngProperty keySizeProperty = new CngProperty(NCryptNative.KeyPropertyName.Length,
BitConverter.GetBytes(KeySize),
CngPropertyOptions.None);
}
_key = value;
- KeySize = _key.KeySize;
+
+ // Our LegalKeySizes value stores the values that we encoded as being the correct
+ // legal key size limitations for this algorithm, as documented on MSDN.
+ //
+ // But on a new OS version we might not question if our limit is accurate, or MSDN
+ // could have been innacurate to start with.
+ //
+ // Since the key is already loaded, we know that Windows thought it to be valid;
+ // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance
+ // check.
+ //
+ // For RSA there are known cases where this change matters. RSACryptoServiceProvider can
+ // create a 384-bit RSA key, which we consider too small to be legal. It can also create
+ // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit
+ // alignment requirement. (In both cases Windows loads it just fine)
+ KeySizeValue = _key.KeySize;
}
}
throw new CryptographicException(SR.GetString(SR.Cryptography_UnsupportedPaddingMode));
}
}
+
+ /*
+ * The members
+ * DecryptValue
+ * EncryptValue
+ * get_KeyExchangeAlgorithm
+ * get_SignatureAlgorithm
+ * are all implemented on RSA as of net46.
+ *
+ * But in servicing situations, System.Core.dll can get patched onto a machine which has mscorlib < net46, meaning
+ * these abstract members have no implementation.
+ *
+ * To keep servicing simple, we'll redefine the overrides here. Since this type is sealed it only affects reflection,
+ * as there are no derived types to mis-target base.-invocations.
+ */
+ public override byte[] DecryptValue(byte[] rgb) { throw new NotSupportedException(SR.NotSupported_Method); }
+ public override byte[] EncryptValue(byte[] rgb) { throw new NotSupportedException(SR.NotSupported_Method); }
+ public override string KeyExchangeAlgorithm { get { return "RSA"; } }
+ public override string SignatureAlgorithm { get { return "RSA"; } }
#endif
}
}
{
if (privateKeyHandle == null)
{
+ if (LocalAppContextSwitches.DontReliablyClonePrivateKey)
+ return (RSA)certificate.PrivateKey;
+
// fall back to CAPI if we cannot acquire the key using CNG.
- return (RSA)certificate.PrivateKey;
+ RSACryptoServiceProvider rsaCsp = (RSACryptoServiceProvider)certificate.PrivateKey;
+ CspParameters cspParameters = DSACertificateExtensions.CopyCspParameters(rsaCsp);
+ RSACryptoServiceProvider clone = new RSACryptoServiceProvider(cspParameters);
+ return clone;
}
CngKey key = CngKey.Open(privateKeyHandle, CngKeyHandleOpenOptions.None);
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Cryptographic.Standard", "CA5350:Microsoft.Cryptographic.Standard",
Justification = "MD5CryptoServiceProvider is not used for cryptography/security purposes and we do it only for v1 and v1.1 for compatibility reasons.")]
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security.Cryptography", "CA5350:Microsoft.Cryptographic.Standard",
+ Justification = "MD5CryptoServiceProvider is not used for cryptography/security purposes and we do it only for v1 and v1.1 for compatibility reasons.")]
internal static HashAlgorithm CreateMetadataHashAlgorithm(double schemaVersion)
{
HashAlgorithm hashAlgorithm;
return schemaSet;
}
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security.Xml", "CA3060:UseXmlReaderForSchemaRead", Justification = "The schema files are embedded in the product assembly as resources")]
private static void AddXmlSchemaToSet(XmlSchemaSet schemaSet, XmlSchemaResource schemaResource, HashSet<string> schemasAlreadyAdded)
{
// loop through the children to do a depth first load
if (local3.NodeType == QilNodeType.Loop) {
QilNode local4 = local3[0];
QilNode local5 = local3[1];
- if ( NonPositional(local2, local1) ) {
- // PATTERN: [CommuteFilterLoop] (Filter $iter:(For (Loop $iter2:* $ret2:*)) $cond:* ^ (NonPositional? $cond $iter)) => (Loop $iter2 (Filter $iter3:(For $ret2) (Subs $cond $iter $iter3)))
+ if (( NonPositional(local2, local1) ) && (!( IsDocOrderDistinct(local3) ))) {
+ // PATTERN: [CommuteFilterLoop] (Filter $iter:(For $loop:(Loop $iter2:* $ret2:*)) $cond:* ^ (NonPositional? $cond $iter) ^ ~((DocOrderDistinct? $loop))) => (Loop $iter2 (Filter $iter3:(For $ret2) (Subs $cond $iter $iter3)))
if (AllowReplace(XmlILOptimization.CommuteFilterLoop, local0)) {
QilNode local6 = VisitFor(f.For(local5));
return Replace(XmlILOptimization.CommuteFilterLoop, local0, VisitLoop(f.Loop(local4, VisitFilter(f.Filter(local6, Subs(local2, local1, local6) )))));
}
}
+ #region <<PoolBlockingPeriod Utility>>
+ const string PoolBlockingPeriodAutoString = "Auto";
+ const string PoolBlockingPeriodAlwaysBlockString = "AlwaysBlock";
+ const string PoolBlockingPeriodNeverBlockString = "NeverBlock";
+
+ internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result)
+ {
+ Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
+ Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)");
+
+ if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAutoString))
+ {
+ result = PoolBlockingPeriod.Auto;
+ return true;
+ }
+ else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAlwaysBlockString))
+ {
+ result = PoolBlockingPeriod.AlwaysBlock;
+ return true;
+ }
+ else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodNeverBlockString))
+ {
+ result = PoolBlockingPeriod.NeverBlock;
+ return true;
+ }
+ else
+ {
+ result = DbConnectionStringDefaults.PoolBlockingPeriod;
+ return false;
+ }
+ }
+
+ internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value)
+ {
+ Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed");
+ return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock;
+ }
+
+ internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value)
+ {
+ Debug.Assert(IsValidPoolBlockingPeriodValue(value));
+
+ if (value == PoolBlockingPeriod.AlwaysBlock)
+ {
+ return PoolBlockingPeriodAlwaysBlockString;
+ }
+ if (value == PoolBlockingPeriod.NeverBlock)
+ {
+ return PoolBlockingPeriodNeverBlockString;
+ }
+ else
+ {
+ return PoolBlockingPeriodAutoString;
+ }
+ }
+
+ /// <summary>
+ /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is:
+ /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer
+ /// * if the value is from type PoolBlockingPeriod, it will be used as is
+ /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum
+ /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException
+ ///
+ /// in any case above, if the conerted value is out of valid range, the method raises ArgumentOutOfRangeException.
+ /// </summary>
+ /// <returns>PoolBlockingPeriod value in the valid range</returns>
+ internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value)
+ {
+ Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)");
+ string sValue = (value as string);
+ PoolBlockingPeriod result;
+ if (null != sValue)
+ {
+ // We could use Enum.TryParse<PoolBlockingPeriod> here, but it accepts value combinations like
+ // "ReadOnly, ReadWrite" which are unwelcome here
+ // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method.
+
+ if (TryConvertToPoolBlockingPeriod(sValue, out result))
+ {
+ return result;
+ }
+
+ // try again after remove leading & trailing whitespaces.
+ sValue = sValue.Trim();
+ if (TryConvertToPoolBlockingPeriod(sValue, out result))
+ {
+ return result;
+ }
+
+ // string values must be valid
+ throw ADP.InvalidConnectionOptionValue(keyword);
+ }
+ else
+ {
+ // the value is not string, try other options
+ PoolBlockingPeriod eValue;
+
+ if (value is PoolBlockingPeriod)
+ {
+ // quick path for the most common case
+ eValue = (PoolBlockingPeriod)value;
+ }
+ else if (value.GetType().IsEnum)
+ {
+ // explicitly block scenarios in which user tries to use wrong enum types, like:
+ // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process;
+ // workaround: explicitly cast non-PoolBlockingPeriod enums to int
+ throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null);
+ }
+ else
+ {
+ try
+ {
+ // Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest
+ eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value);
+ }
+ catch (ArgumentException e)
+ {
+ // to be consistent with the messages we send in case of wrong type usage, replace
+ // the error with our exception, and keep the original one as inner one for troubleshooting
+ throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e);
+ }
+ }
+
+ // ensure value is in valid range
+ if (IsValidPoolBlockingPeriodValue(eValue))
+ {
+ return eValue;
+ }
+ else
+ {
+ throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue);
+ }
+ }
+ }
+ #endregion
+
const string ApplicationIntentReadWriteString = "ReadWrite";
const string ApplicationIntentReadOnlyString = "ReadOnly";
internal const int ConnectRetryInterval = 10;
internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified;
internal static readonly SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled;
+ internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto;
}
internal static class DbConnectionOptionKeywords {
internal const string Authentication = "Authentication";
internal const string Certificate = "Certificate";
internal const string ColumnEncryptionSetting = "Column Encryption Setting";
+ internal const string PoolBlockingPeriod = "PoolBlockingPeriod";
// common keywords (OleDb, OracleClient, SqlClient)
internal const string DataSource = "Data Source";
if (stream == null)
return XmlReadMode.Auto;
- return ReadXml(new XmlTextReader(stream), false);
+ XmlTextReader xr = new XmlTextReader(stream);
+
+ // Prevent Dtd entity in dataset
+ xr.XmlResolver = null;
+
+ return ReadXml(xr, false);
}
/// <devdoc>
if (reader == null)
return XmlReadMode.Auto;
- return ReadXml(new XmlTextReader(reader), false);
+ XmlTextReader xr = new XmlTextReader(reader);
+
+ // Prevent Dtd entity in dataset
+ xr.XmlResolver = null;
+
+ return ReadXml(xr, false);
}
/// <devdoc>
public XmlReadMode ReadXml(string fileName)
{
XmlTextReader xr = new XmlTextReader(fileName);
- try {
+
+ // Prevent Dtd entity in dataset
+ xr.XmlResolver = null;
+
+ try
+ {
return ReadXml(xr, false);
}
finally {
return XmlReadMode.Auto;
XmlTextReader reader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(stream, XmlNodeType.Element, null) : new XmlTextReader(stream);
+ // Prevent Dtd entity in dataset
+ reader.XmlResolver = null;
return ReadXml(reader, mode, false);
}
return XmlReadMode.Auto;
XmlTextReader xmlreader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(reader.ReadToEnd(), XmlNodeType.Element, null) : new XmlTextReader(reader);
+ // Prevent Dtd entity in dataset
+ xmlreader.XmlResolver = null;
return ReadXml(xmlreader, mode, false);
}
}
else
xr = new XmlTextReader(fileName);
- try {
+
+ // Prevent Dtd entity in dataset
+ xr.XmlResolver = null;
+
+ try
+ {
return ReadXml(xr, mode, false);
}
finally {
if (stream == null)
return XmlReadMode.Auto;
- return ReadXml( new XmlTextReader(stream), false);
+ XmlTextReader xr = new XmlTextReader(stream);
+
+ // Prevent Dtd entity in DataTable
+ xr.XmlResolver = null;
+
+ return ReadXml(xr, false);
}
public XmlReadMode ReadXml(TextReader reader)
if (reader == null)
return XmlReadMode.Auto;
- return ReadXml( new XmlTextReader(reader), false);
+ XmlTextReader xr = new XmlTextReader(reader);
+
+ // Prevent Dtd entity in DataTable
+ xr.XmlResolver = null;
+
+ return ReadXml(xr, false);
}
[ResourceExposure(ResourceScope.Machine)]
public XmlReadMode ReadXml(string fileName)
{
XmlTextReader xr = new XmlTextReader(fileName);
- try {
+
+ // Prevent Dtd entity in DataTable
+ xr.XmlResolver = null;
+
+ try
+ {
return ReadXml( xr , false);
}
finally {
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
+ using System.Data.SqlClient;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.CompilerServices;
private Timer CreateCleanupTimer() {
return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait));
}
-
+
+ private static readonly string[] AzureSqlServerEndpoints = {Res.GetString(Res.AZURESQL_GenericEndpoint),
+ Res.GetString(Res.AZURESQL_GermanEndpoint),
+ Res.GetString(Res.AZURESQL_UsGovEndpoint),
+ Res.GetString(Res.AZURESQL_ChinaEndpoint) };
+ private static bool IsAzureSqlServerEndpoint(string dataSource)
+ {
+ // remove server port
+ var i = dataSource.LastIndexOf(',');
+ if (i >= 0)
+ {
+ dataSource = dataSource.Substring(0, i);
+ }
+
+ // check for the instance name
+ i = dataSource.LastIndexOf('\\');
+ if (i >= 0)
+ {
+ dataSource = dataSource.Substring(0, i);
+ }
+
+ // trim redundant whitespaces
+ dataSource = dataSource.Trim();
+
+ // check if servername end with any azure endpoints
+ for (i = 0; i < AzureSqlServerEndpoints.Length; i++)
+ {
+ if (dataSource.EndsWith(AzureSqlServerEndpoints[i], StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private bool IsBlockingPeriodEnabled()
+ {
+ var poolGroupConnectionOptions = _connectionPoolGroup.ConnectionOptions as SqlConnectionString;
+ if (poolGroupConnectionOptions == null)
+ {
+ return true;
+ }
+
+ var policy = poolGroupConnectionOptions.PoolBlockingPeriod;
+
+ switch (policy)
+ {
+ case PoolBlockingPeriod.Auto:
+ {
+ if (IsAzureSqlServerEndpoint(poolGroupConnectionOptions.DataSource))
+ {
+ return false; // in Azure it will be Disabled
+ }
+ else
+ {
+ return true; // in Non Azure, it will be Enabled
+ }
+ }
+ case PoolBlockingPeriod.AlwaysBlock:
+ {
+ return true; //Enabled
+ }
+ case PoolBlockingPeriod.NeverBlock:
+ {
+ return false; //Disabled
+ }
+ default:
+ {
+ //we should never get into this path.
+ Debug.Fail("Unknown PoolBlockingPeriod. Please specify explicit results in above switch case statement.");
+ return true;
+ }
+ }
+ }
+
private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection) {
DbConnectionInternal newObj = null;
// Reset the error wait:
_errorWait = ERROR_WAIT_DEFAULT;
}
- catch(Exception e) {
+ catch(Exception e) {
//
if (!ADP.IsCatchableExceptionType(e)) {
throw;
ADP.TraceExceptionForCapture(e);
+ if (!IsBlockingPeriodEnabled())
+ {
+ throw;
+ }
+
newObj = null; // set to null, so we do not return bad new object
// Failed to create instance
_resError = e;
/// Base class containing raw key bytes for symmetric key algorithms. Some encryption algorithms can use the key directly while others derive sub keys from this.
/// If an algorithm needs to derive more keys, have a derived class from this and use it in the corresponding encryption algorithm.
/// </summary>
- internal class SqlClientSymmetricKey
- {
+ internal class SqlClientSymmetricKey {
/// <summary>
- /// DPAPI protected key
+ /// The underlying key material
/// </summary>
protected readonly byte[] _rootKey;
/// Constructor that initializes the root key.
/// </summary>
/// <param name="rootKey">root key</param>
- internal SqlClientSymmetricKey(byte[] rootKey)
- {
+ internal SqlClientSymmetricKey(byte[] rootKey) {
// Key validation
if (rootKey == null || rootKey.Length == 0) {
throw SQL.NullColumnEncryptionKeySysErr();
_rootKey = rootKey;
}
+ /// <summary>
+ /// Destructor that cleans up the key material.
+ /// This is a best effort approach since there are no guarantees around GC.
+ /// </summary>
+ ~SqlClientSymmetricKey() {
+ if (_rootKey != null) {
+ for (int i = 0; i < _rootKey.Length; i++) {
+ _rootKey[i] = 0;
+ }
+ }
+ }
+
/// <summary>
/// Returns a copy of the plain text key
/// This is needed for actual encryption/decryption.
/// </summary>
- internal virtual byte[] RootKey
- {
- get
- {
+ internal virtual byte[] RootKey {
+ get {
return _rootKey;
}
}
/// Computes SHA256 value of the plain text key bytes
/// </summary>
/// <returns>A string containing SHA256 hash of the root key</returns>
- internal virtual string GetKeyHash()
- {
+ internal virtual string GetKeyHash() {
return SqlSecurityUtility.GetSHA256Hash(RootKey);
}
/// <returns>
/// Returns the length of the root key
/// </returns>
- internal virtual int Length()
- {
- // Note: DPAPI preserves the original byte length
- // so for now, this is as same as returning the length of the raw key.
+ internal virtual int Length() {
return _rootKey.Length;
}
}
/// Force the client to sleep during sp_describe_parameter_encryption after ReadDescribeEncryptionParameterResults.
/// </summary>
private static bool _sleepAfterReadDescribeEncryptionParameterResults = false;
-#endif
+
+ /// <summary>
+ /// Internal flag for testing purposes that forces all queries to internally end async calls.
+ /// </summary>
+ private static bool _forceInternalEndQuery = false;
+#endif
// devnote: Prepare
// Against 7.0 Server (Sphinx) a prepare/unprepare requires an extra roundtrip to the server.
}
}
+ /// <summary>
+ /// A flag to indicate if EndExecute was already initiated by the Begin call.
+ /// </summary>
+ private volatile bool _internalEndExecuteInitiated;
+
+ /// <summary>
+ /// A flag to indicate whether we postponed caching the query metadata for this command.
+ /// </summary>
+ internal bool CachingQueryMetadataPostponed { get; set; }
+
//
// Smi execution-specific stuff
//
try {
statistics = SqlStatistics.StartTimer(Statistics);
WriteBeginExecuteEvent();
- InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, false, CommandTimeout);
+ bool usedCache;
+ InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, false, CommandTimeout, out usedCache);
success = true;
return _rowsAffected;
}
Bid.ScopeEnter(out hscp, "<sc.SqlCommand.ExecuteToPipe|INFO> %d#", ObjectID);
try {
statistics = SqlStatistics.StartTimer(Statistics);
- InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, true, CommandTimeout);
+ bool usedCache;
+ InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, true, CommandTimeout, out usedCache);
}
finally {
SqlStatistics.StopTimer(statistics);
public IAsyncResult BeginExecuteNonQuery(AsyncCallback callback, object stateObject) {
Bid.CorrelationTrace("<sc.SqlCommand.BeginExecuteNonQuery|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
SqlConnection.ExecutePermission.Demand();
- return BeginExecuteNonQueryInternal(callback, stateObject, 0);
+ return BeginExecuteNonQueryInternal(0, callback, stateObject, 0, inRetry: false);
}
private IAsyncResult BeginExecuteNonQueryAsync(AsyncCallback callback, object stateObject) {
- return BeginExecuteNonQueryInternal(callback, stateObject, CommandTimeout, asyncWrite:true);
+ return BeginExecuteNonQueryInternal(0, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite:true);
}
- private IAsyncResult BeginExecuteNonQueryInternal(AsyncCallback callback, object stateObject, int timeout, bool asyncWrite = false) {
- // Reset _pendingCancel upon entry into any Execute - used to synchronize state
- // between entry into Execute* API and the thread obtaining the stateObject.
- _pendingCancel = false;
+ private IAsyncResult BeginExecuteNonQueryInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool inRetry, bool asyncWrite = false) {
+ TaskCompletionSource<object> globalCompletion = new TaskCompletionSource<object>(stateObject);
+ TaskCompletionSource<object> localCompletion = new TaskCompletionSource<object>(stateObject);
+
+ if (!inRetry) {
+ // Reset _pendingCancel upon entry into any Execute - used to synchronize state
+ // between entry into Execute* API and the thread obtaining the stateObject.
+ _pendingCancel = false;
+
+ ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj
+ // back into pool when we should not.
+ }
- ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj
- // back into pool when we should not.
-
SqlStatistics statistics = null;
try {
- statistics = SqlStatistics.StartTimer(Statistics);
- WriteBeginExecuteEvent();
- TaskCompletionSource<object> completion = new TaskCompletionSource<object>(stateObject);
+ if (!inRetry) {
+ statistics = SqlStatistics.StartTimer(Statistics);
+ WriteBeginExecuteEvent();
+ }
+ bool usedCache;
try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool.
- Task execNQ = InternalExecuteNonQuery(completion, ADP.BeginExecuteNonQuery, false, timeout, asyncWrite);
+ Task execNQ = InternalExecuteNonQuery(localCompletion, ADP.BeginExecuteNonQuery, false, timeout, out usedCache, asyncWrite, inRetry: inRetry);
if (execNQ != null) {
- AsyncHelper.ContinueTask(execNQ, completion, () => BeginExecuteNonQueryInternalReadStage(completion));
+ AsyncHelper.ContinueTask(execNQ, localCompletion, () => BeginExecuteNonQueryInternalReadStage(localCompletion));
}
else {
- BeginExecuteNonQueryInternalReadStage(completion);
+ BeginExecuteNonQueryInternalReadStage(localCompletion);
}
}
catch (Exception e) {
throw;
}
+ // When we use query caching for parameter encryption we need to retry on specific errors.
+ // In these cases finalize the call internally and trigger a retry when needed.
+ if (!TriggerInternalEndAndRetryIfNecessary(behavior, stateObject, timeout, ADP.EndExecuteNonQuery, usedCache, inRetry, asyncWrite, globalCompletion, localCompletion, InternalEndExecuteNonQuery, BeginExecuteNonQueryInternal)) {
+ globalCompletion = localCompletion;
+ }
+
// Add callback after work is done to avoid overlapping Begin\End methods
if (callback != null) {
- completion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default);
+ globalCompletion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default);
}
- return completion.Task;
+ return globalCompletion.Task;
}
finally {
SqlStatistics.StopTimer(statistics);
}
}
- private void VerifyEndExecuteState(Task completionTask, String endMethod) {
+ private void VerifyEndExecuteState(Task completionTask, String endMethod, bool fullCheckForColumnEncryption = false) {
if (null == completionTask) {
throw ADP.ArgumentNull("asyncResult");
}
// If transparent parameter encryption was attempted, then we need to skip other checks like those on EndMethodName
// since we want to wait for async results before checking those fields.
- if (IsColumnEncryptionEnabled) {
+ if (IsColumnEncryptionEnabled && !fullCheckForColumnEncryption) {
if (_activeConnection.State != ConnectionState.Open) {
// If the connection is not 'valid' then it was closed while we were executing
throw ADP.ClosedConnectionError();
}
}
- private void WaitForAsyncResults(IAsyncResult asyncResult) {
+ private void WaitForAsyncResults(IAsyncResult asyncResult, bool isInternal) {
Task completionTask = (Task) asyncResult;
if (!asyncResult.IsCompleted) {
asyncResult.AsyncWaitHandle.WaitOne();
}
- _stateObj._networkPacketTaskSource = null;
- _activeConnection.GetOpenTdsConnection().DecrementAsyncCount();
+
+ if (_stateObj != null) {
+ _stateObj._networkPacketTaskSource = null;
+ }
+
+ // If this is an internal command we will decrement the count when the End method is actually called by the user.
+ // If we are using Column Encryption and the previous task failed, the async count should have already been fixed up.
+ // There is a generic issue in how we handle the async count because:
+ // a) BeginExecute might or might not clean it up on failure.
+ // b) In EndExecute, we check the task state before waiting and throw if it's failed, whereas if we wait we will always adjust the count.
+ if (!isInternal && (!IsColumnEncryptionEnabled || !completionTask.IsFaulted)) {
+ _activeConnection.GetOpenTdsConnection().DecrementAsyncCount();
+ }
}
public int EndExecuteNonQuery(IAsyncResult asyncResult) {
private int EndExecuteNonQueryAsync(IAsyncResult asyncResult) {
Bid.CorrelationTrace("<sc.SqlCommand.EndExecuteNonQueryAsync|Info|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
+ Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null);
Exception asyncException = ((Task)asyncResult).Exception;
if (asyncException != null) {
else {
ThrowIfReconnectionHasBeenCanceled();
// lock on _stateObj prevents ----s with close/cancel.
- lock (_stateObj) {
+ // If we have already initiate the End call internally, we have already done that, so no point doing it again.
+ if (!_internalEndExecuteInitiated) {
+ lock (_stateObj) {
+ return EndExecuteNonQueryInternal(asyncResult);
+ }
+ }
+ else {
return EndExecuteNonQueryInternal(asyncResult);
}
}
private int EndExecuteNonQueryInternal(IAsyncResult asyncResult) {
SqlStatistics statistics = null;
+ bool success = false;
+ int? sqlExceptionNumber = null;
+ try {
+ statistics = SqlStatistics.StartTimer(Statistics);
+ int result = (int)InternalEndExecuteNonQuery(asyncResult, ADP.EndExecuteNonQuery, isInternal: false);
+ success = true;
+ return result;
+ }
+ catch (SqlException e) {
+ sqlExceptionNumber = e.Number;
+ if (cachedAsyncState != null) {
+ cachedAsyncState.ResetAsyncState();
+ };
+ // SqlException is always catchable
+ ReliablePutStateObject();
+ throw;
+ }
+ catch (Exception e) {
+ if (cachedAsyncState != null) {
+ cachedAsyncState.ResetAsyncState();
+ };
+ if (ADP.IsCatchableExceptionType(e)) {
+ ReliablePutStateObject();
+ };
+ throw;
+ }
+ finally {
+ SqlStatistics.StopTimer(statistics);
+ WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: false);
+ }
+ }
+
+ private object InternalEndExecuteNonQuery(IAsyncResult asyncResult, string endMethod, bool isInternal) {
TdsParser bestEffortCleanupTarget = null;
RuntimeHelpers.PrepareConstrainedRegions();
- bool success = false;
- int? sqlExceptionNumber = null;
+
try {
#if DEBUG
TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection();
{
#endif //DEBUG
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection);
- statistics = SqlStatistics.StartTimer(Statistics);
- VerifyEndExecuteState((Task)asyncResult, ADP.EndExecuteNonQuery);
- WaitForAsyncResults(asyncResult);
+ VerifyEndExecuteState((Task)asyncResult, endMethod);
+ WaitForAsyncResults(asyncResult, isInternal);
- // If Transparent parameter encryption was attempted, then we would have skipped the below
- // checks in VerifyEndExecuteState since we wanted to wait for WaitForAsyncResults to complete.
+ // If column encryption is enabled, also check the state after waiting for the task.
+ // It would be better to do this for all cases, but avoiding for compatibility reasons.
if (IsColumnEncryptionEnabled) {
- if (cachedAsyncState.EndMethodName == null) {
- throw ADP.MethodCalledTwice(ADP.EndExecuteNonQuery);
- }
-
- if (ADP.EndExecuteNonQuery != cachedAsyncState.EndMethodName) {
- throw ADP.MismatchedAsyncResult(cachedAsyncState.EndMethodName, ADP.EndExecuteNonQuery);
- }
-
- if (!cachedAsyncState.IsActiveConnectionValid(_activeConnection)) {
- // If the connection is not 'valid' then it was closed while we were executing
- throw ADP.ClosedConnectionError();
- }
+ VerifyEndExecuteState((Task)asyncResult, endMethod, fullCheckForColumnEncryption: true);
}
bool processFinallyBlock = true;
try {
- NotifyDependency();
+ // If this is not for internal usage, notify the dependency.
+ // If we have already initiated the end internally, the reader should be ready, so just return the rows affected.
+ if (!isInternal) {
+ NotifyDependency();
+
+ if (_internalEndExecuteInitiated) {
+ Debug.Assert(_stateObj == null);
+
+ // Reset the state since we exit early.
+ cachedAsyncState.ResetAsyncState();
+
+ return _rowsAffected;
+ }
+ }
+
CheckThrowSNIException();
// only send over SQL Batch command if we are not a stored proc and have no parameters
if (!result) { throw SQL.SynchronousCallMayNotPend(); }
}
finally {
- cachedAsyncState.ResetAsyncState();
+ // Don't reset the state for internal End. The user End will do that eventually.
+ if (!isInternal) {
+ cachedAsyncState.ResetAsyncState();
+ }
}
}
else { // otherwise, use a full-fledged execute that can handle params and stored procs
- SqlDataReader reader = CompleteAsyncExecuteReader();
+ SqlDataReader reader = CompleteAsyncExecuteReader(isInternal);
if (null != reader) {
reader.Close();
}
}
}
- catch (SqlException e) {
- sqlExceptionNumber = e.Number;
- throw;
- }
catch (Exception e) {
processFinallyBlock = ADP.IsCatchableExceptionType(e);
throw;
}
Debug.Assert(null == _stateObj, "non-null state object in EndExecuteNonQuery");
- success = true;
return _rowsAffected;
}
#if DEBUG
SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
throw;
}
- catch (Exception e) {
- if (cachedAsyncState != null) {
- cachedAsyncState.ResetAsyncState();
- };
- if (ADP.IsCatchableExceptionType(e)) {
- ReliablePutStateObject();
- };
- throw;
- }
- finally {
- SqlStatistics.StopTimer(statistics);
- WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: false);
- }
}
- private Task InternalExecuteNonQuery(TaskCompletionSource<object> completion, string methodName, bool sendToPipe, int timeout, bool asyncWrite = false) {
+ private Task InternalExecuteNonQuery(TaskCompletionSource<object> completion, string methodName, bool sendToPipe, int timeout, out bool usedCache, bool asyncWrite = false, bool inRetry = false) {
bool async = (null != completion);
+ usedCache = false;
SqlStatistics statistics = Statistics;
_rowsAffected = -1;
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection);
// @devnote: this function may throw for an invalid connection
// @devnote: returns false for empty command text
- ValidateCommand(methodName, async);
+ if (!inRetry) {
+ ValidateCommand(methodName, async);
+ }
CheckNotificationStateAndAutoEnlist(); // Only call after validate - requires non null connection!
Task task = null;
}
}
+ // We should never get here for a retry since we only have retries for parameters.
+ Debug.Assert(!inRetry);
+
task = RunExecuteNonQueryTds(methodName, async, timeout, asyncWrite);
}
else { // otherwise, use a full-fledged execute that can handle params and stored procs
Debug.Assert( !sendToPipe, "trying to send non-context command to pipe" );
Bid.Trace("<sc.SqlCommand.ExecuteNonQuery|INFO> %d#, Command executed as RPC.\n", ObjectID);
- SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, methodName, completion, timeout, out task, asyncWrite);
+ SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, methodName, completion, timeout, out task, out usedCache, asyncWrite, inRetry);
if (null!=reader) {
if (task != null) {
task = AsyncHelper.CreateContinuationTask(task, () => reader.Close());
[System.Security.Permissions.HostProtectionAttribute(ExternalThreading=true)]
public IAsyncResult BeginExecuteXmlReader(AsyncCallback callback, object stateObject) {
Bid.CorrelationTrace("<sc.SqlCommand.BeginExecuteXmlReader|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
- SqlConnection.ExecutePermission.Demand();
- return BeginExecuteXmlReaderInternal(callback, stateObject, 0);
+ SqlConnection.ExecutePermission.Demand();
+ return BeginExecuteXmlReaderInternal(CommandBehavior.SequentialAccess, callback, stateObject, 0, inRetry: false);
}
private IAsyncResult BeginExecuteXmlReaderAsync(AsyncCallback callback, object stateObject) {
- return BeginExecuteXmlReaderInternal(callback, stateObject, CommandTimeout, asyncWrite:true);
+ return BeginExecuteXmlReaderInternal(CommandBehavior.SequentialAccess, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite: true);
}
- private IAsyncResult BeginExecuteXmlReaderInternal(AsyncCallback callback, object stateObject, int timeout, bool asyncWrite = false) {
- // Reset _pendingCancel upon entry into any Execute - used to synchronize state
- // between entry into Execute* API and the thread obtaining the stateObject.
- _pendingCancel = false;
+ private IAsyncResult BeginExecuteXmlReaderInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool inRetry, bool asyncWrite = false) {
+ TaskCompletionSource<object> globalCompletion = new TaskCompletionSource<object>(stateObject);
+ TaskCompletionSource<object> localCompletion = new TaskCompletionSource<object>(stateObject);
- ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj
- // back into pool when we should not.
+ if (!inRetry) {
+ // Reset _pendingCancel upon entry into any Execute - used to synchronize state
+ // between entry into Execute* API and the thread obtaining the stateObject.
+ _pendingCancel = false;
+
+ ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj
+ // back into pool when we should not.
+ }
SqlStatistics statistics = null;
try {
- statistics = SqlStatistics.StartTimer(Statistics);
- WriteBeginExecuteEvent();
- TaskCompletionSource<object> completion = new TaskCompletionSource<object>(stateObject);
+ if (!inRetry) {
+ statistics = SqlStatistics.StartTimer(Statistics);
+ WriteBeginExecuteEvent();
+ }
+ bool usedCache;
Task writeTask;
try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool.
- RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteXmlReader, completion, timeout, out writeTask, asyncWrite);
+ RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteXmlReader, localCompletion, timeout, out writeTask, out usedCache, asyncWrite, inRetry);
}
catch (Exception e) {
if (!ADP.IsCatchableOrSecurityExceptionType(e)) {
}
if (writeTask != null) {
- AsyncHelper.ContinueTask(writeTask, completion, () => BeginExecuteXmlReaderInternalReadStage(completion));
+ AsyncHelper.ContinueTask(writeTask, localCompletion, () => BeginExecuteXmlReaderInternalReadStage(localCompletion));
}
else {
- BeginExecuteXmlReaderInternalReadStage(completion);
+ BeginExecuteXmlReaderInternalReadStage(localCompletion);
+ }
+
+ // When we use query caching for parameter encryption we need to retry on specific errors.
+ // In these cases finalize the call internally and trigger a retry when needed.
+ if (!TriggerInternalEndAndRetryIfNecessary(behavior, stateObject, timeout, ADP.EndExecuteXmlReader, usedCache, inRetry, asyncWrite, globalCompletion, localCompletion, InternalEndExecuteReader, BeginExecuteXmlReaderInternal)) {
+ globalCompletion = localCompletion;
}
// Add callback after work is done to avoid overlapping Begin\End methods
if (callback != null) {
- completion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default);
+ globalCompletion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default);
}
- return completion.Task;
+ return globalCompletion.Task;
}
finally {
SqlStatistics.StopTimer(statistics);
private XmlReader EndExecuteXmlReaderAsync(IAsyncResult asyncResult) {
Bid.CorrelationTrace("<sc.SqlCommand.EndExecuteXmlReaderAsync|Info|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
+ Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null);
Exception asyncException = ((Task)asyncResult).Exception;
if (asyncException != null) {
else {
ThrowIfReconnectionHasBeenCanceled();
// lock on _stateObj prevents ----s with close/cancel.
- lock (_stateObj) {
+ // If we have already initiate the End call internally, we have already done that, so no point doing it again.
+ if (!_internalEndExecuteInitiated) {
+ lock (_stateObj) {
+ return EndExecuteXmlReaderInternal(asyncResult);
+ }
+ }
+ else {
return EndExecuteXmlReaderInternal(asyncResult);
}
}
bool success = false;
int? sqlExceptionNumber = null;
try {
- XmlReader result = CompleteXmlReader(InternalEndExecuteReader(asyncResult, ADP.EndExecuteXmlReader));
+ XmlReader result = CompleteXmlReader(InternalEndExecuteReader(asyncResult, ADP.EndExecuteXmlReader, isInternal: false));
success = true;
return result;
}
public IAsyncResult BeginExecuteReader(AsyncCallback callback, object stateObject, CommandBehavior behavior) {
Bid.CorrelationTrace("<sc.SqlCommand.BeginExecuteReader|API|Correlation> ObjectID%d#, behavior=%d{ds.CommandBehavior}, ActivityID %ls\n", ObjectID, (int)behavior);
SqlConnection.ExecutePermission.Demand();
- return BeginExecuteReaderInternal(behavior, callback, stateObject, 0);
+ return BeginExecuteReaderInternal(behavior, callback, stateObject, 0, inRetry: false);
}
internal SqlDataReader ExecuteReader(CommandBehavior behavior, string method) {
private SqlDataReader EndExecuteReaderAsync(IAsyncResult asyncResult) {
Bid.CorrelationTrace("<sc.SqlCommand.EndExecuteReaderAsync|Info|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
+ Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null);
Exception asyncException = ((Task)asyncResult).Exception;
if (asyncException != null) {
else {
ThrowIfReconnectionHasBeenCanceled();
// lock on _stateObj prevents ----s with close/cancel.
- lock (_stateObj) {
+ // If we have already initiate the End call internally, we have already done that, so no point doing it again.
+ if (!_internalEndExecuteInitiated) {
+ lock (_stateObj) {
return EndExecuteReaderInternal(asyncResult);
+ }
+ }
+ else {
+ return EndExecuteReaderInternal(asyncResult);
}
}
}
int? sqlExceptionNumber = null;
try {
statistics = SqlStatistics.StartTimer(Statistics);
- SqlDataReader result = InternalEndExecuteReader(asyncResult, ADP.EndExecuteReader);
+ SqlDataReader result = InternalEndExecuteReader(asyncResult, ADP.EndExecuteReader, isInternal: false);
success = true;
return result;
}
}
private IAsyncResult BeginExecuteReaderAsync(CommandBehavior behavior, AsyncCallback callback, object stateObject) {
- return BeginExecuteReaderInternal(behavior, callback, stateObject, CommandTimeout, asyncWrite:true);
+ return BeginExecuteReaderInternal(behavior, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite:true);
}
- private IAsyncResult BeginExecuteReaderInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool asyncWrite = false) {
- // Reset _pendingCancel upon entry into any Execute - used to synchronize state
- // between entry into Execute* API and the thread obtaining the stateObject.
- _pendingCancel = false;
+ private IAsyncResult BeginExecuteReaderInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool inRetry, bool asyncWrite = false) {
+ TaskCompletionSource<object> globalCompletion = new TaskCompletionSource<object>(stateObject);
+ TaskCompletionSource<object> localCompletion = new TaskCompletionSource<object>(stateObject);
+
+ if (!inRetry) {
+ // Reset _pendingCancel upon entry into any Execute - used to synchronize state
+ // between entry into Execute* API and the thread obtaining the stateObject.
+ _pendingCancel = false;
+ }
SqlStatistics statistics = null;
try {
- statistics = SqlStatistics.StartTimer(Statistics);
- WriteBeginExecuteEvent();
- TaskCompletionSource<object> completion = new TaskCompletionSource<object>(stateObject);
-
- ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj
- // back into pool when we should not.
+ if (!inRetry) {
+ statistics = SqlStatistics.StartTimer(Statistics);
+ WriteBeginExecuteEvent();
+ ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj
+ // back into pool when we should not.
+ }
+
+ bool usedCache;
Task writeTask = null;
try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool.
- RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteReader, completion, timeout, out writeTask, asyncWrite);
+ RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteReader, localCompletion, timeout, out writeTask, out usedCache, asyncWrite, inRetry);
}
catch (Exception e) {
if (!ADP.IsCatchableOrSecurityExceptionType(e)) {
}
if (writeTask != null ) {
- AsyncHelper.ContinueTask(writeTask,completion,()=> BeginExecuteReaderInternalReadStage(completion));
+ AsyncHelper.ContinueTask(writeTask, localCompletion, () => BeginExecuteReaderInternalReadStage(localCompletion));
}
else {
- BeginExecuteReaderInternalReadStage(completion);
+ BeginExecuteReaderInternalReadStage(localCompletion);
+ }
+
+ // When we use query caching for parameter encryption we need to retry on specific errors.
+ // In these cases finalize the call internally and trigger a retry when needed.
+ if (!TriggerInternalEndAndRetryIfNecessary(behavior, stateObject, timeout, ADP.EndExecuteReader, usedCache, inRetry, asyncWrite, globalCompletion, localCompletion, InternalEndExecuteReader, BeginExecuteReaderInternal)) {
+ globalCompletion = localCompletion;
}
// Add callback after work is done to avoid overlapping Begin\End methods
if (callback != null) {
- completion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default);
+ globalCompletion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default);
}
- return completion.Task;
+
+ return globalCompletion.Task;
}
finally {
SqlStatistics.StopTimer(statistics);
}
}
+ private bool TriggerInternalEndAndRetryIfNecessary(CommandBehavior behavior, object stateObject, int timeout, string endMethod, bool usedCache, bool inRetry, bool asyncWrite, TaskCompletionSource<object> globalCompletion, TaskCompletionSource<object> localCompletion, Func<IAsyncResult, string, bool, object> endFunc, Func<CommandBehavior, AsyncCallback, object, int, bool, bool, IAsyncResult> retryFunc) {
+ // We shouldn't be using the cache if we are in retry.
+ Debug.Assert(!usedCache || !inRetry);
+
+ // If column ecnryption is enabled and we used the cache, we want to catch any potential exceptions that were caused by the query cache and retry if the error indicates that we should.
+ // So, try to read the result of the query before completing the overall task and trigger a retry if appropriate.
+ if ((IsColumnEncryptionEnabled && !inRetry && usedCache)
+#if DEBUG
+ || _forceInternalEndQuery
+#endif
+ ) {
+ long firstAttemptStart = ADP.TimerCurrent();
+
+ localCompletion.Task.ContinueWith(tsk => {
+ if (tsk.IsFaulted) {
+ globalCompletion.TrySetException(tsk.Exception.InnerException);
+ }
+ else if (tsk.IsCanceled) {
+ globalCompletion.TrySetCanceled();
+ }
+ else {
+ try {
+ // Mark that we initiated the internal EndExecute. This should always be false until we set it here.
+ Debug.Assert(!_internalEndExecuteInitiated);
+ _internalEndExecuteInitiated = true;
+
+ // lock on _stateObj prevents ----s with close/cancel.
+ lock (_stateObj) {
+ endFunc(tsk, endMethod, true/*inInternal*/);
+ }
+ globalCompletion.TrySetResult(tsk.Result);
+ }
+ catch (Exception e) {
+ // Put the state object back to the cache.
+ // Do not reset the async state, since this is managed by the user Begin/End and not internally.
+ if (ADP.IsCatchableExceptionType(e)) {
+ ReliablePutStateObject();
+ }
+
+ bool shouldRetry = false;
+
+ // Check if we have an error indicating that we can retry.
+ if (e is SqlException) {
+ SqlException sqlEx = e as SqlException;
+
+ for (int i = 0; i < sqlEx.Errors.Count; i++) {
+ if (sqlEx.Errors[i].Number == TdsEnums.TCE_CONVERSION_ERROR_CLIENT_RETRY) {
+ shouldRetry = true;
+ break;
+ }
+ }
+ }
+
+ if (!shouldRetry) {
+ // If we cannot retry, Reset the async state to make sure we leave a clean state.
+ if (null != _cachedAsyncState) {
+ _cachedAsyncState.ResetAsyncState();
+ }
+ _activeConnection.GetOpenTdsConnection().DecrementAsyncCount();
+
+ globalCompletion.TrySetException(e);
+ }
+ else {
+ // Remove the enrty from the cache since it was inconsistent.
+ SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this);
+
+ try {
+ // Kick off the retry.
+ _internalEndExecuteInitiated = false;
+ Task<object> retryTask = (Task<object>)retryFunc(behavior, null, stateObject, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), true/*inRetry*/, asyncWrite);
+
+ retryTask.ContinueWith(retryTsk => {
+ if (retryTsk.IsFaulted) {
+ globalCompletion.TrySetException(retryTsk.Exception.InnerException);
+ }
+ else if (retryTsk.IsCanceled) {
+ globalCompletion.TrySetCanceled();
+ }
+ else {
+ globalCompletion.TrySetResult(retryTsk.Result);
+ }
+ }, TaskScheduler.Default);
+ }
+ catch (Exception e2) {
+ globalCompletion.TrySetException(e2);
+ }
+ }
+ }
+ }
+ }, TaskScheduler.Default);
+
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+
private void BeginExecuteReaderInternalReadStage(TaskCompletionSource<object> completion) {
Debug.Assert(completion != null,"CompletionSource should not be null");
// Read SNI does not have catches for async exceptions, handle here.
}
}
- private SqlDataReader InternalEndExecuteReader(IAsyncResult asyncResult, string endMethod) {
-
- VerifyEndExecuteState((Task) asyncResult, endMethod);
- WaitForAsyncResults(asyncResult);
+ private SqlDataReader InternalEndExecuteReader(IAsyncResult asyncResult, string endMethod, bool isInternal) {
+
+ VerifyEndExecuteState((Task)asyncResult, endMethod);
+ WaitForAsyncResults(asyncResult, isInternal);
- // If Transparent parameter encryption was attempted, then we would have skipped the below
- // checks in VerifyEndExecuteState since we wanted to wait for WaitForAsyncResults to complete.
+ // If column encryption is enabled, also check the state after waiting for the task.
+ // It would be better to do this for all cases, but avoiding for compatibility reasons.
if (IsColumnEncryptionEnabled) {
- if (cachedAsyncState.EndMethodName == null) {
- throw ADP.MethodCalledTwice(endMethod);
- }
-
- if (endMethod != cachedAsyncState.EndMethodName) {
- throw ADP.MismatchedAsyncResult(cachedAsyncState.EndMethodName, endMethod);
- }
-
- if (!cachedAsyncState.IsActiveConnectionValid(_activeConnection)) {
- // If the connection is not 'valid' then it was closed while we were executing
- throw ADP.ClosedConnectionError();
- }
+ VerifyEndExecuteState((Task)asyncResult, endMethod, fullCheckForColumnEncryption: true);
}
CheckThrowSNIException();
{
#endif //DEBUG
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection);
- SqlDataReader reader = CompleteAsyncExecuteReader();
+ SqlDataReader reader = CompleteAsyncExecuteReader(isInternal);
Debug.Assert(null == _stateObj, "non-null state object in InternalEndExecuteReader");
return reader;
}
public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken) {
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteNonQueryAsync|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
- SqlConnection.ExecutePermission.Demand();
+ SqlConnection.ExecutePermission.Demand();
TaskCompletionSource<int> source = new TaskCompletionSource<int>();
}
}
}, TaskScheduler.Default);
- }
+ }
catch (Exception e) {
source.SetException(e);
}
new public Task<SqlDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) {
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteReaderAsync|API|Correlation> ObjectID%d#, behavior=%d{ds.CommandBehavior}, ActivityID %ls\n", ObjectID, (int)behavior);
- SqlConnection.ExecutePermission.Demand();
+ SqlConnection.ExecutePermission.Demand();
TaskCompletionSource<SqlDataReader> source = new TaskCompletionSource<SqlDataReader>();
}
registration = cancellationToken.Register(CancelIgnoreFailure);
}
-
+
Task<SqlDataReader> returnedTask = source.Task;
try {
RegisterForConnectionCloseNotification(ref returnedTask);
- Task<SqlDataReader>.Factory.FromAsync(BeginExecuteReaderAsync, EndExecuteReaderAsync, behavior, null).ContinueWith((t) => {
+ Task<SqlDataReader>.Factory.FromAsync(BeginExecuteReaderAsync, EndExecuteReaderAsync, behavior, null).ContinueWith((t) => {
registration.Dispose();
if (t.IsFaulted) {
Exception e = t.Exception.InnerException;
}
}
}, TaskScheduler.Default);
- }
+ }
catch (Exception e) {
source.SetException(e);
}
public Task<XmlReader> ExecuteXmlReaderAsync(CancellationToken cancellationToken) {
Bid.CorrelationTrace("<sc.SqlCommand.ExecuteXmlReaderAsync|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
- SqlConnection.ExecutePermission.Demand();
-
+ SqlConnection.ExecutePermission.Demand();
+
TaskCompletionSource<XmlReader> source = new TaskCompletionSource<XmlReader>();
CancellationTokenRegistration registration = new CancellationTokenRegistration();
}
registration = cancellationToken.Register(CancelIgnoreFailure);
}
-
+
Task<XmlReader> returnedTask = source.Task;
try {
RegisterForConnectionCloseNotification(ref returnedTask);
}
}
}, TaskScheduler.Default);
- }
+ }
catch (Exception e) {
source.SetException(e);
}
GetStateObject();
+ // Reset the encryption state in case it has been set by a previous command.
+ ResetEncryptionState();
+
// we just send over the raw text with no annotation
// no parameters are sent over
// no data reader is returned
// First reset the command level state.
ClearDescribeParameterEncryptionRequests();
+ // Reset the state for internal End execution.
+ _internalEndExecuteInitiated = false;
+
+ // Reset the state for the cache.
+ CachingQueryMetadataPostponed = false;
+
// Reset the state of each of the parameters.
if (_parameters != null) {
for (int i = 0; i < _parameters.Count; i++) {
/// <param name="task"></param>
/// <param name="asyncWrite"></param>
/// <returns></returns>
- private void PrepareForTransparentEncryption(CommandBehavior cmdBehavior, bool returnStream, bool async, int timeout, TaskCompletionSource<object> completion, out Task returnTask, bool asyncWrite)
- {
+ private void PrepareForTransparentEncryption(CommandBehavior cmdBehavior, bool returnStream, bool async, int timeout, TaskCompletionSource<object> completion, out Task returnTask, bool asyncWrite, out bool usedCache, bool inRetry) {
// Fetch reader with input params
Task fetchInputParameterEncryptionInfoTask = null;
bool describeParameterEncryptionNeeded = false;
SqlDataReader describeParameterEncryptionDataReader = null;
returnTask = null;
+ usedCache = false;
Debug.Assert(_activeConnection != null, "_activeConnection should not be null in PrepareForTransparentEncryption.");
Debug.Assert(_activeConnection.Parser != null, "_activeConnection.Parser should not be null in PrepareForTransparentEncryption.");
"ColumnEncryption setting should be enabled for input parameter encryption.");
Debug.Assert(async == (completion != null), "completion should can be null if and only if mode is async.");
+ // If we are not in Batch RPC and not already retrying, attempt to fetch the cipher MD for each parameter from the cache.
+ // If this succeeds then return immediately, otherwise just fall back to the full crypto MD discovery.
+ if (!BatchRPCMode && !inRetry && SqlQueryMetadataCache.GetInstance().GetQueryMetadataIfExists(this)) {
+ usedCache = true;
+ return;
+ }
+
// A flag to indicate if finallyblock needs to execute.
bool processFinallyBlock = true;
// A flag to indicate if we need to decrement async count on the connection in finally block.
- bool decrementAsyncCountInFinallyBlock = async;
+ bool decrementAsyncCountInFinallyBlock = false;
// Flag to indicate if exception is caught during the execution, to govern clean up.
bool exceptionCaught = false;
return;
}
+ // If we are in async execution, we need to decrement our async count on exception.
+ decrementAsyncCountInFinallyBlock = async;
+
Debug.Assert(describeParameterEncryptionDataReader != null,
"describeParameterEncryptionDataReader should not be null, as it is required to get results of describe parameter encryption.");
processFinallyBlock = false;
returnTask = AsyncHelper.CreateContinuationTask(fetchInputParameterEncryptionInfoTask, () => {
bool processFinallyBlockAsync = true;
+ bool decrementAsyncCountInFinallyBlockAsync = true;
RuntimeHelpers.PrepareConstrainedRegions();
try {
// If it is async, then TryFetchInputParameterEncryptionInfo-> RunExecuteReaderTds would have incremented the async count.
// Decrement it when we are about to complete async execute reader.
SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection();
- if (internalConnectionTds != null)
- {
+ if (internalConnectionTds != null) {
internalConnectionTds.DecrementAsyncCount();
- decrementAsyncCountInFinallyBlock = false;
+ decrementAsyncCountInFinallyBlockAsync = false;
}
// Complete executereader.
- describeParameterEncryptionDataReader = CompleteAsyncExecuteReader();
+ describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true);
Debug.Assert(null == _stateObj, "non-null state object in PrepareForTransparentEncryption.");
// Read the results of describe parameter encryption.
}
finally {
PrepareTransparentEncryptionFinallyBlock( closeDataReader: processFinallyBlockAsync,
- decrementAsyncCount: decrementAsyncCountInFinallyBlock,
+ decrementAsyncCount: decrementAsyncCountInFinallyBlockAsync,
clearDataStructures: processFinallyBlockAsync,
wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded,
describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap,
if (exception != null) {
throw exception;
}}));
+
+ decrementAsyncCountInFinallyBlock = false;
}
else {
// If it was async, ending the reader is still pending.
processFinallyBlock = false;
returnTask = Task.Run(() => {
bool processFinallyBlockAsync = true;
+ bool decrementAsyncCountInFinallyBlockAsync = true;
RuntimeHelpers.PrepareConstrainedRegions();
try {
SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection();
if (internalConnectionTds != null) {
internalConnectionTds.DecrementAsyncCount();
- decrementAsyncCountInFinallyBlock = false;
+ decrementAsyncCountInFinallyBlockAsync = false;
}
// Complete executereader.
- describeParameterEncryptionDataReader = CompleteAsyncExecuteReader();
+ describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true);
Debug.Assert(null == _stateObj, "non-null state object in PrepareForTransparentEncryption.");
// Read the results of describe parameter encryption.
}
finally {
PrepareTransparentEncryptionFinallyBlock( closeDataReader: processFinallyBlockAsync,
- decrementAsyncCount: decrementAsyncCountInFinallyBlock,
+ decrementAsyncCount: decrementAsyncCountInFinallyBlockAsync,
clearDataStructures: processFinallyBlockAsync,
wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded,
describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap,
describeParameterEncryptionDataReader: describeParameterEncryptionDataReader);
}
});
+
+ decrementAsyncCountInFinallyBlock = false;
}
else {
// For synchronous execution, read the results of describe parameter encryption here.
timeout: timeout,
task: out task,
asyncWrite: asyncWrite,
+ inRetry: false,
ds: null,
describeParameterEncryptionRequest: true);
}
SqlParameter param = originalRpcRequest.parameters[i];
paramCopy = new SqlParameter(param.ParameterName, param.SqlDbType, param.Size, param.Direction, param.Precision, param.Scale, param.SourceColumn, param.SourceVersion,
param.SourceColumnNullMapping, param.Value, param.XmlSchemaCollectionDatabase, param.XmlSchemaCollectionOwningSchema, param.XmlSchemaCollectionName);
+ paramCopy.CompareInfo = param.CompareInfo;
+ paramCopy.TypeName = param.TypeName;
+ paramCopy.UdtTypeName = param.UdtTypeName;
+ paramCopy.IsNullable = param.IsNullable;
+ paramCopy.LocaleId = param.LocaleId;
+ paramCopy.Offset = param.Offset;
+
tempCollection.Add(paramCopy);
}
}
}
}
+
+ // If we are not in Batch RPC mode, update the query cache with the encryption MD.
+ if (!BatchRPCMode) {
+ SqlQueryMetadataCache.GetInstance().AddQueryMetadata(this, ignoreQueriesWithReturnValueParams: true);
+ }
}
internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method) {
Task unused; // sync execution
- SqlDataReader reader = RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion:null, timeout:CommandTimeout, task:out unused);
+ bool usedCache;
+ SqlDataReader reader = RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion: null, timeout: CommandTimeout, task: out unused, usedCache: out usedCache);
Debug.Assert(unused == null, "returned task during synchronous execution");
return reader;
}
// task is created in case of pending asynchronous write, returned SqlDataReader should not be utilized until that task is complete
- internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method, TaskCompletionSource<object> completion, int timeout, out Task task, bool asyncWrite = false) {
+ internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method, TaskCompletionSource<object> completion, int timeout, out Task task, out bool usedCache, bool asyncWrite = false, bool inRetry = false) {
bool async = (null != completion);
+ usedCache = false;
task = null;
// @devnote: this function may throw for an invalid connection
// @devnote: returns false for empty command text
- ValidateCommand(method, async);
+ if (!inRetry) {
+ ValidateCommand(method, async);
+ }
+
CheckNotificationStateAndAutoEnlist(); // Only call after validate - requires non null connection!
TdsParser bestEffortCleanupTarget = null;
}
else if (IsColumnEncryptionEnabled) {
Task returnTask = null;
- PrepareForTransparentEncryption(cmdBehavior, returnStream, async, timeout, completion, out returnTask, asyncWrite && async);
- Debug.Assert(async == (returnTask != null), @"returnTask should be null if and only if async is false.");
+ PrepareForTransparentEncryption(cmdBehavior, returnStream, async, timeout, completion, out returnTask, asyncWrite && async, out usedCache, inRetry);
+ Debug.Assert(usedCache || (async == (returnTask != null)), @"if we didn't use the cache, returnTask should be null if and only if async is false.");
+
+ long firstAttemptStart = ADP.TimerCurrent();
- return RunExecuteReaderTdsWithTransparentParameterEncryption( cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, ds: null,
- describeParameterEncryptionRequest: false, describeParameterEncryptionTask: returnTask);
+ try {
+ return RunExecuteReaderTdsWithTransparentParameterEncryption(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry, ds: null,
+ describeParameterEncryptionRequest: false, describeParameterEncryptionTask: returnTask);
+ }
+ catch (SqlException ex) {
+ // We only want to retry once, so don't retry if we are already in retry.
+ // If we didn't use the cache, we don't want to retry.
+ // The async retried are handled separately, handle only [....] calls here.
+ if (inRetry || async || !usedCache) {
+ throw;
+ }
+
+ bool shouldRetry = false;
+
+ // Check if we have an error indicating that we can retry.
+ for (int i = 0; i < ex.Errors.Count; i++) {
+ if (ex.Errors[i].Number == TdsEnums.TCE_CONVERSION_ERROR_CLIENT_RETRY) {
+ shouldRetry = true;
+ break;
+ }
+ }
+
+ if (!shouldRetry) {
+ throw;
+ }
+ else {
+ // Retry if the command failed with appropriate error.
+ // First invalidate the entry from the cache, so that we refresh our encryption MD.
+ SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this);
+ return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, null, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true);
+ }
+ }
}
else {
- return RunExecuteReaderTds( cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async);
+ return RunExecuteReaderTds( cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry);
}
}
int timeout,
out Task task,
bool asyncWrite,
+ bool inRetry,
SqlDataReader ds=null,
bool describeParameterEncryptionRequest = false,
Task describeParameterEncryptionTask = null) {
Debug.Assert(!asyncWrite || async, "AsyncWrite should be always accompanied by Async");
- Debug.Assert((describeParameterEncryptionTask != null) == async, @"async should be true if and only if describeParameterEncryptionTask is not null.");
if (ds == null && returnStream) {
ds = new SqlDataReader(this, cmdBehavior);
if (describeParameterEncryptionTask != null) {
long parameterEncryptionStart = ADP.TimerCurrent();
- TaskCompletionSource<object> completion = new TaskCompletionSource<object>();
- AsyncHelper.ContinueTask(describeParameterEncryptionTask, completion,
- () => {
- Task subTask = null;
- RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, parameterEncryptionStart), out subTask, asyncWrite, ds);
- if (subTask == null) {
- completion.SetResult(null);
- }
- else {
- AsyncHelper.ContinueTask(subTask, completion, () => completion.SetResult(null));
- }
- }, connectionToDoom: null,
- onFailure: ((exception) => {
- if (_cachedAsyncState != null) {
- _cachedAsyncState.ResetAsyncState();
- }
- if (exception != null) {
- throw exception;
- }}),
- onCancellation: (() => {
- if (_cachedAsyncState != null) {
- _cachedAsyncState.ResetAsyncState();
- }}),
- connectionToAbort: _activeConnection);
- task = completion.Task;
- return ds;
+ TaskCompletionSource<object> completion = new TaskCompletionSource<object>();
+ AsyncHelper.ContinueTask(describeParameterEncryptionTask, completion,
+ () => {
+ Task subTask = null;
+ RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, parameterEncryptionStart), out subTask, asyncWrite, inRetry, ds);
+ if (subTask == null) {
+ completion.SetResult(null);
+ }
+ else {
+ AsyncHelper.ContinueTask(subTask, completion, () => completion.SetResult(null));
+ }
+ }, connectionToDoom: null,
+ onFailure: ((exception) => {
+ if (_cachedAsyncState != null) {
+ _cachedAsyncState.ResetAsyncState();
+ }
+ if (exception != null) {
+ throw exception;
+ }
+ }),
+ onCancellation: (() => {
+ if (_cachedAsyncState != null) {
+ _cachedAsyncState.ResetAsyncState();
+ }
+ }),
+ connectionToAbort: _activeConnection);
+ task = completion.Task;
+ return ds;
}
else {
// Synchronous execution.
- return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite, ds);
+ return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite, inRetry, ds);
}
}
- private SqlDataReader RunExecuteReaderTds( CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, bool async, int timeout, out Task task, bool asyncWrite, SqlDataReader ds=null, bool describeParameterEncryptionRequest = false) {
+ private SqlDataReader RunExecuteReaderTds( CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, bool async, int timeout, out Task task, bool asyncWrite, bool inRetry, SqlDataReader ds=null, bool describeParameterEncryptionRequest = false) {
Debug.Assert(!asyncWrite || async, "AsyncWrite should be always accompanied by Async");
if (ds == null && returnStream) {
Interlocked.CompareExchange(ref _reconnectionCompletionSource, null, completion);
timeoutCTS.Cancel();
Task subTask;
- RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, reconnectionStart), out subTask, asyncWrite, ds);
+ RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, reconnectionStart), out subTask, asyncWrite, inRetry, ds);
if (subTask == null) {
completion.SetResult(null);
}
bool processFinallyBlock = true;
bool decrementAsyncCountOnFailure = false;
- if (async) {
+ // If we are in retry, don't increment the Async count. This should have already been set.
+ if (async && !inRetry) {
_activeConnection.GetOpenTdsConnection().IncrementAsyncCount();
decrementAsyncCountOnFailure = true;
}
}
else {
// Always execute - even if no reader!
- FinishExecuteReader(ds, runBehavior, optionSettings);
+ FinishExecuteReader(ds, runBehavior, optionSettings, isInternal: false, forDescribeParameterEncryption: false);
}
}
catch (Exception e) {
return ds;
}
- private SqlDataReader CompleteAsyncExecuteReader() {
+ private SqlDataReader CompleteAsyncExecuteReader(bool isInternal = false, bool forDescribeParameterEncryption = false) {
SqlDataReader ds = cachedAsyncState.CachedAsyncReader; // should not be null
bool processFinallyBlock = true;
try {
- FinishExecuteReader(ds, cachedAsyncState.CachedRunBehavior, cachedAsyncState.CachedSetOptions);
+ FinishExecuteReader(ds, cachedAsyncState.CachedRunBehavior, cachedAsyncState.CachedSetOptions, isInternal, forDescribeParameterEncryption);
}
catch (Exception e) {
processFinallyBlock = ADP.IsCatchableExceptionType(e);
finally {
TdsParser.ReliabilitySection.Assert("unreliable call to CompleteAsyncExecuteReader"); // you need to setup for a thread abort somewhere before you call this method
if (processFinallyBlock) {
- cachedAsyncState.ResetAsyncState();
+ // Don't reset the state for internal End. The user End will do that eventually.
+ if (!isInternal) {
+ cachedAsyncState.ResetAsyncState();
+ }
+
PutStateObject();
}
}
return ds;
}
- private void FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, string resetOptionsString) {
+ private void FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, string resetOptionsString, bool isInternal, bool forDescribeParameterEncryption) {
// always wrap with a try { FinishExecuteReader(...) } finally { PutStateObject(); }
- NotifyDependency();
+ // If this is not for internal usage, notify the dependency. If we have already initiated the end internally, the reader should be ready, so just return.
+ if (!isInternal && !forDescribeParameterEncryption) {
+ NotifyDependency();
+
+ if (_internalEndExecuteInitiated) {
+ Debug.Assert(_stateObj == null);
+ return;
+ }
+ }
+
if (runBehavior == RunBehavior.UntilDone) {
try {
bool dataReady;
parameter.Value = status;
}
+
+ // If we are not in Batch RPC mode, update the query cache with the encryption MD.
+ // We can do this now that we have distinguished between ReturnValue and ReturnStatus.
+ // Read comment in AddQueryMetadata() for more details.
+ if (!BatchRPCMode && CachingQueryMetadataPostponed) {
+ SqlQueryMetadataCache.GetInstance().AddQueryMetadata(this, ignoreQueriesWithReturnValueParams: false);
+ }
+
break;
}
}
return _ColumnEncryptionTrustedMasterKeyPaths;
}
}
-
+
+ /// <summary>
+ /// Defines whether query metadata caching is enabled.
+ /// </summary>
+ static private bool _ColumnEncryptionQueryMetadataCacheEnabled = true;
+
+ [
+ DefaultValue(null),
+ ResCategoryAttribute(Res.DataCategory_Data),
+ ResDescriptionAttribute(Res.TCE_SqlConnection_ColumnEncryptionQueryMetadataCacheEnabled),
+ ]
+ static public bool ColumnEncryptionQueryMetadataCacheEnabled
+ {
+ get
+ {
+ return _ColumnEncryptionQueryMetadataCacheEnabled;
+ }
+ set
+ {
+ _ColumnEncryptionQueryMetadataCacheEnabled = value;
+ }
+ }
+
+ /// <summary>
+ /// Defines whether query metadata caching is enabled.
+ /// </summary>
+ static private TimeSpan _ColumnEncryptionKeyCacheTtl = TimeSpan.FromHours(2);
+
+ [
+ DefaultValue(null),
+ ResCategoryAttribute(Res.DataCategory_Data),
+ ResDescriptionAttribute(Res.TCE_SqlConnection_ColumnEncryptionKeyCacheTtl),
+ ]
+ static public TimeSpan ColumnEncryptionKeyCacheTtl
+ {
+ get
+ {
+ return _ColumnEncryptionKeyCacheTtl;
+ }
+ set
+ {
+ _ColumnEncryptionKeyCacheTtl = value;
+ }
+ }
+
/// <summary>
/// This function should only be called once in an app. This does shallow copying of the dictionary so that
/// the app cannot alter the custom provider list once it has been set.
get {
return ((SqlConnectionString)ConnectionOptions).TypeSystemAssemblyVersion;
}
- }
+ }
+
+ internal PoolBlockingPeriod PoolBlockingPeriod
+ {
+ get
+ {
+ return ((SqlConnectionString)ConnectionOptions).PoolBlockingPeriod;
+ }
+ }
internal int ConnectRetryInterval {
get {
internal const string Application_Name = TdsEnums.SQL_PROVIDER_NAME;
internal const bool Asynchronous = false;
internal const string AttachDBFilename = "";
+ internal const PoolBlockingPeriod PoolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
internal const int Connect_Timeout = ADP.DefaultConnectionTimeout;
internal const bool Connection_Reset = true;
internal const bool Context_Connection = false;
internal const string Application_Name = "application name";
internal const string AsynchronousProcessing = "asynchronous processing";
internal const string AttachDBFilename = "attachdbfilename";
+ internal const string PoolBlockingPeriod = "poolblockingperiod";
internal const string ColumnEncryptionSetting = "column encryption setting";
internal const string Connect_Timeout = "connect timeout";
internal const string Connection_Reset = "connection reset";
private readonly bool _integratedSecurity;
+ private readonly PoolBlockingPeriod _poolBlockingPeriod;
private readonly bool _connectionReset;
private readonly bool _contextConnection;
private readonly bool _encrypt;
ConvertValueToBoolean(KEY.AsynchronousProcessing, DEFAULT.Asynchronous); // while we don't use it anymore, we still need to verify it is true/false
// SQLPT 41700: Ignore ResetConnection=False (still validate the keyword/value)
+ _poolBlockingPeriod = ConvertValueToPoolBlockingPeriod();
_connectionReset = ConvertValueToBoolean(KEY.Connection_Reset, DEFAULT.Connection_Reset);
_contextConnection = ConvertValueToBoolean(KEY.Context_Connection, DEFAULT.Context_Connection);
_encrypt = ConvertValueToEncrypt();
_userInstance = userInstance;
_connectTimeout = connectionOptions._connectTimeout;
_loadBalanceTimeout = connectionOptions._loadBalanceTimeout;
+ _poolBlockingPeriod = connectionOptions._poolBlockingPeriod;
_maxPoolSize = connectionOptions._maxPoolSize;
_minPoolSize = connectionOptions._minPoolSize;
_multiSubnetFailover = connectionOptions._multiSubnetFailover;
// will work. In the future we can deprecate the keyword entirely.
internal bool Asynchronous { get { return true; } }
+ internal PoolBlockingPeriod PoolBlockingPeriod { get { return _poolBlockingPeriod; } }
+
// SQLPT 41700: Ignore ResetConnection=False, always reset the connection for security
internal bool ConnectionReset { get { return true; } }
internal bool ContextConnection { get { return _contextConnection; } }
hash.Add(KEY.Application_Name, KEY.Application_Name);
hash.Add(KEY.AsynchronousProcessing, KEY.AsynchronousProcessing);
hash.Add(KEY.AttachDBFilename, KEY.AttachDBFilename);
+ hash.Add(KEY.PoolBlockingPeriod, KEY.PoolBlockingPeriod);
hash.Add(KEY.Connect_Timeout, KEY.Connect_Timeout);
hash.Add(KEY.Connection_Reset, KEY.Connection_Reset);
hash.Add(KEY.Context_Connection, KEY.Context_Connection);
// ArgumentException and other types are raised as is (no wrapping)
}
+ internal System.Data.SqlClient.PoolBlockingPeriod ConvertValueToPoolBlockingPeriod()
+ {
+ object value = base.Parsetable[KEY.PoolBlockingPeriod];
+ if (value == null)
+ {
+ return DEFAULT.PoolBlockingPeriod;
+ }
+
+ try
+ {
+ return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(KEY.PoolBlockingPeriod, value);
+ }
+ catch (FormatException e)
+ {
+ throw ADP.InvalidConnectionOptionValue(KEY.PoolBlockingPeriod, e);
+ }
+ catch (OverflowException e)
+ {
+ throw ADP.InvalidConnectionOptionValue(KEY.PoolBlockingPeriod, e);
+ }
+ }
+
internal SqlAuthenticationMethod ConvertValueToAuthenticationType() {
object value = base.Parsetable[KEY.Authentication];
Pooling,
MinPoolSize,
MaxPoolSize,
+ PoolBlockingPeriod,
AsynchronousProcessing,
ConnectionReset,
private bool _userInstance = DbConnectionStringDefaults.UserInstance;
private SqlAuthenticationMethod _authentication = DbConnectionStringDefaults.Authentication;
private SqlConnectionColumnEncryptionSetting _columnEncryptionSetting = DbConnectionStringDefaults.ColumnEncryptionSetting;
+ private PoolBlockingPeriod _poolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
static SqlConnectionStringBuilder() {
string[] validKeywords = new string[KeywordsCount];
validKeywords[(int)Keywords.ApplicationName] = DbConnectionStringKeywords.ApplicationName;
validKeywords[(int)Keywords.AsynchronousProcessing] = DbConnectionStringKeywords.AsynchronousProcessing;
validKeywords[(int)Keywords.AttachDBFilename] = DbConnectionStringKeywords.AttachDBFilename;
+ validKeywords[(int)Keywords.PoolBlockingPeriod] = DbConnectionStringKeywords.PoolBlockingPeriod;
validKeywords[(int)Keywords.ConnectionReset] = DbConnectionStringKeywords.ConnectionReset;
validKeywords[(int)Keywords.ContextConnection] = DbConnectionStringKeywords.ContextConnection;
validKeywords[(int)Keywords.ConnectTimeout] = DbConnectionStringKeywords.ConnectTimeout;
hash.Add(DbConnectionStringKeywords.ApplicationName, Keywords.ApplicationName);
hash.Add(DbConnectionStringKeywords.AsynchronousProcessing, Keywords.AsynchronousProcessing);
hash.Add(DbConnectionStringKeywords.AttachDBFilename, Keywords.AttachDBFilename);
+ hash.Add(DbConnectionStringKeywords.PoolBlockingPeriod, Keywords.PoolBlockingPeriod);
hash.Add(DbConnectionStringKeywords.ConnectTimeout, Keywords.ConnectTimeout);
hash.Add(DbConnectionStringKeywords.ConnectionReset, Keywords.ConnectionReset);
hash.Add(DbConnectionStringKeywords.ContextConnection, Keywords.ContextConnection);
case Keywords.Authentication: Authentication = ConvertToAuthenticationType(keyword, value); break;
case Keywords.ColumnEncryptionSetting: ColumnEncryptionSetting = ConvertToColumnEncryptionSetting(keyword, value); break;
case Keywords.AsynchronousProcessing: AsynchronousProcessing = ConvertToBoolean(value); break;
+ case Keywords.PoolBlockingPeriod: PoolBlockingPeriod = ConvertToPoolBlockingPeriod(keyword, value); break;
#pragma warning disable 618 // Obsolete ConnectionReset
case Keywords.ConnectionReset: ConnectionReset = ConvertToBoolean(value); break;
#pragma warning restore 618
}
}
+ [DisplayName(DbConnectionStringKeywords.PoolBlockingPeriod)]
+ [ResCategoryAttribute(Res.DataCategory_Pooling)]
+ [ResDescriptionAttribute(Res.DbConnectionString_PoolBlockingPeriod)]
+ [RefreshPropertiesAttribute(RefreshProperties.All)]
+ public PoolBlockingPeriod PoolBlockingPeriod
+ {
+ get { return _poolBlockingPeriod; }
+ set
+ {
+ if (!DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value))
+ {
+ throw ADP.InvalidEnumerationValue(typeof(PoolBlockingPeriod), (int)value);
+ }
+
+ SetPoolBlockingPeriodValue(value);
+ _poolBlockingPeriod = value;
+ }
+ }
+
[Browsable(false)]
[DisplayName(DbConnectionStringKeywords.ConnectionReset)]
[Obsolete("ConnectionReset has been deprecated. SqlConnection will ignore the 'connection reset' keyword and always reset the connection")] // SQLPT 41700
private static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) {
return DbConnectionStringBuilderUtil.ConvertToAuthenticationType(keyword, value);
}
+ private static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value)
+ {
+ return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(keyword, value);
+ }
/// <summary>
/// Convert to SqlConnectionColumnEncryptionSetting.
case Keywords.ApplicationName: return ApplicationName;
case Keywords.AsynchronousProcessing: return AsynchronousProcessing;
case Keywords.AttachDBFilename: return AttachDBFilename;
+ case Keywords.PoolBlockingPeriod: return PoolBlockingPeriod;
case Keywords.ConnectTimeout: return ConnectTimeout;
#pragma warning disable 618 // Obsolete ConnectionReset
case Keywords.ConnectionReset: return ConnectionReset;
case Keywords.Authentication:
_authentication = DbConnectionStringDefaults.Authentication;
break;
+ case Keywords.PoolBlockingPeriod:
+ _poolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod;
+ break;
+
case Keywords.ConnectTimeout:
_connectTimeout = DbConnectionStringDefaults.ConnectTimeout;
break;
Debug.Assert(DbConnectionStringBuilderUtil.IsValidApplicationIntentValue(value), "Invalid value for ApplicationIntent");
base[DbConnectionStringKeywords.ApplicationIntent] = DbConnectionStringBuilderUtil.ApplicationIntentToString(value);
}
+ private void SetPoolBlockingPeriodValue(PoolBlockingPeriod value)
+ {
+ Debug.Assert(DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value), "Invalid value for PoolBlockingPeriod");
+ base[DbConnectionStringKeywords.PoolBlockingPeriod] = DbConnectionStringBuilderUtil.PoolBlockingPeriodToString(value);
+ }
private void SetAuthenticationValue(SqlAuthenticationMethod value) {
Debug.Assert(DbConnectionStringBuilderUtil.IsValidAuthenticationTypeValue(value), "Invalid value for AuthenticationType");
base[DbConnectionStringKeywords.Authentication] = DbConnectionStringBuilderUtil.AuthenticationTypeToString(value);
durationString = null;
break;
}
-
+
// This message is to be added only when within the various stages of a connection.
// In all other cases, it will default to the original error message.
- if ((currentPhase != SqlConnectionTimeoutErrorPhase.Undefined) || (currentPhase != SqlConnectionTimeoutErrorPhase.Complete))
+ if ((currentPhase != SqlConnectionTimeoutErrorPhase.Undefined) && (currentPhase != SqlConnectionTimeoutErrorPhase.Complete))
{
// NOTE: In case of a failover scenario, add a string that this failure occured as part of the primary or secondary server
if (isFailoverScenario)
originalPhaseDurations[(int)SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth].GetMilliSecondDuration(),
originalPhaseDurations[(int)SqlConnectionTimeoutErrorPhase.PostLogin].GetMilliSecondDuration());
}
+ }
- // NOTE: To display duration in each phase.
- if (durationString != null)
- {
- errorBuilder.Append(" ");
- errorBuilder.Append(durationString);
- }
+ // NOTE: To display duration in each phase.
+ if (durationString != null)
+ {
+ errorBuilder.Append(" ");
+ errorBuilder.Append(durationString);
}
return errorBuilder.ToString();
}
internal void DecrementAsyncCount() {
+ Debug.Assert(_asyncCommandCount > 0);
Interlocked.Decrement(ref _asyncCommandCount);
}
}
set {
- Debug.Assert(_columnEncryptionCipherMetadata == null || value == null,
- "_columnEncryptionCipherMetadata should be set to a non-null value only once.");
-
_columnEncryptionCipherMetadata = value;
}
}
using System.Diagnostics;
using System.Globalization;
using System.Linq;
+ using System.Runtime.Caching;
using System.Text;
/// <summary>
/// <para> Implements a cache of Symmetric Keys (once they are decrypted).Useful for rapidly decrypting multiple data values.</para>
/// </summary>
sealed internal class SqlSymmetricKeyCache {
- private readonly ConcurrentDictionary<string,SqlClientSymmetricKey> _cache;
+ private readonly MemoryCache _cache;
private static readonly SqlSymmetricKeyCache _singletonInstance = new SqlSymmetricKeyCache();
private SqlSymmetricKeyCache () {
- _cache = new ConcurrentDictionary<string, SqlClientSymmetricKey>(concurrencyLevel: 4 * Environment.ProcessorCount /* default value in ConcurrentDictionary*/, capacity: 2);
+ _cache = new MemoryCache("ColumnEncryptionKeyCache");
}
internal static SqlSymmetricKeyCache GetInstance () {
Debug.Assert(cacheLookupKey.Length <= capacity, "We needed to allocate a larger array");
#endif //DEBUG
- encryptionKey = null;
-
// Lookup the key in cache
- if (!_cache.TryGetValue(cacheLookupKey, out encryptionKey)) {
+ encryptionKey = _cache.Get(cacheLookupKey) as SqlClientSymmetricKey;
+
+ if (encryptionKey == null) {
Debug.Assert(SqlConnection.ColumnEncryptionTrustedMasterKeyPaths != null, @"SqlConnection.ColumnEncryptionTrustedMasterKeyPaths should not be null");
// Check against the trusted key paths
encryptionKey = new SqlClientSymmetricKey (plaintextKey);
- // In case multiple threads reach here at the same time, the first one wins.
- // The allocated memory will be reclaimed by Garbage Collector.
- _cache.TryAdd(cacheLookupKey, encryptionKey);
+ // If the cache TTL is zero, don't even bother inserting to the cache.
+ if (SqlConnection.ColumnEncryptionKeyCacheTtl != TimeSpan.Zero) {
+ // In case multiple threads reach here at the same time, the first one wins.
+ // The allocated memory will be reclaimed by Garbage Collector.
+ DateTimeOffset expirationTime = DateTimeOffset.UtcNow.Add(SqlConnection.ColumnEncryptionKeyCacheTtl);
+ _cache.Add(cacheLookupKey, encryptionKey, expirationTime);
+ }
}
return true;
return Res.GetString(Res.SQL_SSPIGenerateError);
}
static internal string Timeout() {
- return Res.GetString(Res.SQL_Timeout);
+ return Res.GetString(Res.SQL_Timeout_Execution);
}
static internal string Timeout_PreLogin_Begin() {
return Res.GetString(Res.SQL_Timeout_PreLogin_Begin);
public const int IMPERSONATION_FAILED = 1346;
public const int P_TOKENTOOLONG = 103;
+ // SQL error that indicates retry for Always Encrypted
+ public const int TCE_CONVERSION_ERROR_CLIENT_RETRY = 33514;
+
// SNI\Win32 error values
// NOTE: these are simply windows system error codes, not SNI specific
public const uint SNI_UNINITIALIZED = unchecked((uint)-1);
RealFoliate();
AssertValid();
if ( NodeType == XPathNodeType.Namespace ) {
- Debug.Assert( _parentOfNS != null );
MoveTo( _parentOfNS );
return true;
}
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
+
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
using System;
using System.Collections.Generic;
static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
}
}
+
+#pragma warning restore 436
//
// ==--==
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
// NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches
using System;
using System.Collections.Generic;
}
}
}
+
+#pragma warning restore 436
namespace System.IdentityModel.Claims
{
using System.Collections.Generic;
+ using System.Diagnostics;
using System.IdentityModel.Policy;
using System.Net.Mail;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;
+ using Globalization;
public class X509CertificateClaimSet : ClaimSet, IIdentityInfo, IDisposable
{
if (!string.IsNullOrEmpty(value))
claims.Add(Claim.CreateX500DistinguishedNameClaim(this.certificate.SubjectName));
- // App context switch for disabling support for multiple dns entries in a SAN certificate
- if (LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate)
- {
- // old behavior, default for <= 4.6
- value = this.certificate.GetNameInfo(X509NameType.DnsName, false);
- if (!string.IsNullOrEmpty(value))
- claims.Add(Claim.CreateDnsClaim(value));
- }
- else
- {
- // new behavior as this is the default long term behavior
- // Since a SAN can have multiple DNS entries
- string[] entries = GetDnsFromExtensions(this.certificate);
- for (int i = 0; i < entries.Length; ++i)
- {
- claims.Add(Claim.CreateDnsClaim(entries[i]));
- }
- }
+ claims.AddRange(GetDnsClaims(this.certificate));
value = this.certificate.GetNameInfo(X509NameType.SimpleName, false);
if (!string.IsNullOrEmpty(value))
{
if (right == null || Rights.PossessProperty.Equals(right))
{
- // App context switch for disabling support for multiple dns entries in a SAN certificate
- if (LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate)
- {
- // old behavior, default for <= 4.6
- string value = this.certificate.GetNameInfo(X509NameType.DnsName, false);
- if (!string.IsNullOrEmpty(value))
- {
- yield return Claim.CreateDnsClaim(value);
- }
- }
- else
- {
- // new behavior since this is the default long term behavior
- string[] entries = GetDnsFromExtensions(certificate);
- for (int i = 0; i < entries.Length; ++i)
- {
- yield return Claim.CreateDnsClaim(entries[i]);
- }
- }
+ foreach (var claim in GetDnsClaims(certificate))
+ yield return claim;
}
}
else
}
}
- // Fixing Bug 795660: SAN having multiple DNS entries
- private static string[] GetDnsFromExtensions(X509Certificate2 cert)
+ private static List<Claim> GetDnsClaims(X509Certificate2 cert)
{
- foreach (X509Extension ext in cert.Extensions)
+ List<Claim> dnsClaimEntries = new List<Claim>();
+
+ // old behavior, default for <= 4.6
+ string value = cert.GetNameInfo(X509NameType.DnsName, false);
+ if (!string.IsNullOrEmpty(value))
+ dnsClaimEntries.Add(Claim.CreateDnsClaim(value));
+
+ // App context switch for disabling support for multiple dns entries in a SAN certificate
+ // If we can't dynamically parse the alt subject names, we will not add any dns claims ONLY for the alt subject names.
+ // In this way, if the X509NameType.DnsName was enough to succeed for the out-bound-message. We would have a success.
+ if (!LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate && X509SubjectAlternativeNameConstants.SuccessfullyInitialized)
{
- // Extension is SAN or SAN2
- if (ext.Oid.Value == "2.5.29.7" || ext.Oid.Value == "2.5.29.17")
+ foreach (X509Extension ext in cert.Extensions)
{
- string asnString = ext.Format(true);
- if (string.IsNullOrEmpty(asnString))
+ // Extension is SAN or SAN2
+ if (ext.Oid.Value == X509SubjectAlternativeNameConstants.SanOid || ext.Oid.Value == X509SubjectAlternativeNameConstants.San2Oid)
{
- return new string[0];
- }
-
- string[] rawDnsEntries = asnString.Split(new string[1] { "\n" }, StringSplitOptions.RemoveEmptyEntries);
- string[] dnsEntries = new string[rawDnsEntries.Length];
- for (int i = 0; i < rawDnsEntries.Length; ++i)
- {
- int equalSignIndex = rawDnsEntries[i].IndexOf('=');
- dnsEntries[i] = rawDnsEntries[i].Substring(equalSignIndex + 1).Trim();
+ string asnString = ext.Format(false);
+ if (string.IsNullOrWhiteSpace(asnString))
+ break;
+
+ // SubjectAlternativeNames might contain something other than a dNSName,
+ // so we have to parse through and only use the dNSNames
+ // <identifier><delimiter><value><separator(s)>
+ string[] rawDnsEntries = asnString.Split(X509SubjectAlternativeNameConstants.SeparatorArray, StringSplitOptions.RemoveEmptyEntries);
+ for (int i = 0; i < rawDnsEntries.Length; i++)
+ {
+ string[] keyval = rawDnsEntries[i].Split(X509SubjectAlternativeNameConstants.Delimiter);
+ if (string.Equals(keyval[0], X509SubjectAlternativeNameConstants.Identifier))
+ dnsClaimEntries.Add(Claim.CreateDnsClaim(keyval[1]));
+ }
}
- return dnsEntries;
}
}
- return new string[0];
+
+ return dnsClaimEntries;
}
public override IEnumerator<Claim> GetEnumerator()
get { return this.identity; }
}
}
+
+ // We don't have a strongly typed extension to parse Subject Alt Names, so we have to do a workaround
+ // to figure out what the identifier, delimiter, and separator is by using a well-known extension
+ private static class X509SubjectAlternativeNameConstants
+ {
+ public const string SanOid = "2.5.29.7";
+ public const string San2Oid = "2.5.29.17";
+
+ public static string Identifier
+ {
+ get;
+ private set;
+ }
+
+ public static char Delimiter
+ {
+ get;
+ private set;
+ }
+
+ public static string Separator
+ {
+ get;
+ private set;
+ }
+
+ public static string[] SeparatorArray
+ {
+ get;
+ private set;
+ }
+
+ public static bool SuccessfullyInitialized
+ {
+ get;
+ private set;
+ }
+
+ // static initializer will run before properties are accessed
+ static X509SubjectAlternativeNameConstants()
+ {
+ // Extracted a well-known X509Extension
+ byte[] x509ExtensionBytes = new byte[] {
+ 48, 36, 130, 21, 110, 111, 116, 45, 114, 101, 97, 108, 45, 115, 117, 98, 106, 101, 99,
+ 116, 45, 110, 97, 109, 101, 130, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109
+ };
+ const string subjectName = "not-real-subject-name";
+ string x509ExtensionFormattedString = string.Empty;
+ try
+ {
+ X509Extension x509Extension = new X509Extension(SanOid, x509ExtensionBytes, true);
+ x509ExtensionFormattedString = x509Extension.Format(false);
+
+ // Each OS has a different dNSName identifier and delimiter
+ // On Windows, dNSName == "DNS Name" (localizable), on Linux, dNSName == "DNS"
+ // e.g.,
+ // Windows: x509ExtensionFormattedString is: "DNS Name=not-real-subject-name, DNS Name=example.com"
+ // Linux: x509ExtensionFormattedString is: "DNS:not-real-subject-name, DNS:example.com"
+ // Parse: <identifier><delimiter><value><separator(s)>
+
+ int delimiterIndex = x509ExtensionFormattedString.IndexOf(subjectName) - 1;
+ Delimiter = x509ExtensionFormattedString[delimiterIndex];
+
+ // Make an assumption that all characters from the the start of string to the delimiter
+ // are part of the identifier
+ Identifier = x509ExtensionFormattedString.Substring(0, delimiterIndex);
+
+ int separatorFirstChar = delimiterIndex + subjectName.Length + 1;
+ int separatorLength = 1;
+ for (int i = separatorFirstChar + 1; i < x509ExtensionFormattedString.Length; i++)
+ {
+ // We advance until the first character of the identifier to determine what the
+ // separator is. This assumes that the identifier assumption above is correct
+ if (x509ExtensionFormattedString[i] == Identifier[0])
+ {
+ break;
+ }
+
+ separatorLength++;
+ }
+
+ Separator = x509ExtensionFormattedString.Substring(separatorFirstChar, separatorLength);
+ SeparatorArray = new string[1] { Separator };
+ SuccessfullyInitialized = true;
+ }
+ catch (Exception ex)
+ {
+ SuccessfullyInitialized = false;
+ DiagnosticUtility.TraceHandledException(
+ new FormatException(string.Format(CultureInfo.InvariantCulture,
+ "There was an error parsing the SubjectAlternativeNames: '{0}'. See inner exception for more details.{1}Detected values were: Identifier: '{2}'; Delimiter:'{3}'; Separator:'{4}'",
+ x509ExtensionFormattedString,
+ Environment.NewLine,
+ Identifier,
+ Delimiter,
+ Separator),
+ ex),
+ TraceEventType.Warning);
+ }
+ }
+ }
}
class X509Identity : GenericIdentity, IDisposable
{
private const string EnableCachedEmptyDefaultAuthorizationContextString = "Switch.System.IdentityModel.EnableCachedEmptyDefaultAuthorizationContext";
private const string DisableMultipleDNSEntriesInSANCertificateString = "Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate";
+ private const string DisableUpdatingRsaProviderTypeString = "Switch.System.IdentityModel.DisableUpdatingRsaProviderType";
private static int enableCachedEmptyDefaultAuthorizationContext;
private static int disableMultipleDNSEntriesInSANCertificate;
+ private static int disableUpdatingRsaProviderType;
public static bool EnableCachedEmptyDefaultAuthorizationContext
{
}
}
+ public static bool DisableUpdatingRsaProviderType
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(DisableUpdatingRsaProviderTypeString, ref disableUpdatingRsaProviderType);
+ }
+ }
+
public static void SetDefaultsLessOrEqual_452()
{
+#pragma warning disable BCL0012
// Define the switches that should be true for 4.5.2 or less, false for 4.6+.
LocalAppContext.DefineSwitchDefault(EnableCachedEmptyDefaultAuthorizationContextString, true);
+#pragma warning restore BCL0012
}
public static void SetDefaultsLessOrEqual_46()
{
+#pragma warning disable BCL0012
// Define the switches that should be true for 4.6 or less, false for 4.6.1+.
LocalAppContext.DefineSwitchDefault(DisableMultipleDNSEntriesInSANCertificateString, true);
+#pragma warning restore BCL0012
}
}
}
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.GetString(SR.EmptyOrNullArgumentString, "algorithm"));
}
- // We support one of the two algoritms, but not both.
+
+ // We support:
// XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
// XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
+ // RsaSha256Signature = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
+ AsymmetricAlgorithm privateKey = LevelUpRsa(this.PrivateKey, algorithm);
+
object algorithmObject = CryptoHelper.GetAlgorithmFromConfig(algorithm);
if (algorithmObject != null)
{
SignatureDescription description = algorithmObject as SignatureDescription;
if (description != null)
- return description.CreateFormatter(this.PrivateKey);
+ return description.CreateFormatter(privateKey);
try
{
AsymmetricSignatureFormatter asymmetricSignatureFormatter = algorithmObject as AsymmetricSignatureFormatter;
if (asymmetricSignatureFormatter != null)
{
- asymmetricSignatureFormatter.SetKey(this.PrivateKey);
+ asymmetricSignatureFormatter.SetKey(privateKey);
return asymmetricSignatureFormatter;
}
}
case SecurityAlgorithms.RsaSha256Signature:
// Ensure that we have an RSA algorithm object.
- RSACryptoServiceProvider rsa_prov_full = (this.PrivateKey as RSACryptoServiceProvider);
- if (rsa_prov_full == null)
+ RSA rsaSha256 = (privateKey as RSA);
+ if (rsaSha256 == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.PrivateKeyNotRSA)));
- CspParameters csp = new CspParameters();
- csp.ProviderType = 24;
- csp.KeyContainerName = rsa_prov_full.CspKeyContainerInfo.KeyContainerName;
- csp.KeyNumber = (int)rsa_prov_full.CspKeyContainerInfo.KeyNumber;
- if (rsa_prov_full.CspKeyContainerInfo.MachineKeyStore)
- csp.Flags = CspProviderFlags.UseMachineKeyStore;
-
- csp.Flags |= CspProviderFlags.UseExistingKey;
-
- return new RSAPKCS1SignatureFormatter(new RSACryptoServiceProvider(csp));
+ return new RSAPKCS1SignatureFormatter(rsaSha256);
default:
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedCryptoAlgorithm, algorithm)));
}
+ private static AsymmetricAlgorithm LevelUpRsa(AsymmetricAlgorithm asymmetricAlgorithm, string algorithm)
+ {
+ // If user turned off leveling up at app level, return
+ if (LocalAppContextSwitches.DisableUpdatingRsaProviderType)
+ return asymmetricAlgorithm;
+
+ if (asymmetricAlgorithm == null)
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("asymmetricAlgorithm"));
+
+ if (string.IsNullOrEmpty(algorithm))
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.GetString(SR.EmptyOrNullArgumentString, "algorithm"));
+
+ // only level up if alg is sha256
+ if (!string.Equals(algorithm, SecurityAlgorithms.RsaSha256Signature))
+ return asymmetricAlgorithm;
+
+ RSACryptoServiceProvider rsaCsp = asymmetricAlgorithm as RSACryptoServiceProvider;
+ if (rsaCsp == null)
+ return asymmetricAlgorithm;
+
+ // ProviderType == 1(PROV_RSA_FULL) and providerType == 12(PROV_RSA_SCHANNEL) are provider types that only support SHA1. Change them to PROV_RSA_AES=24 that supports SHA2 also.
+ // Only levels up if the associated key is not a hardware key.
+ // Another provider type related to rsa, PROV_RSA_SIG == 2 that only supports Sha1 is no longer supported
+ if ((rsaCsp.CspKeyContainerInfo.ProviderType == 1 || rsaCsp.CspKeyContainerInfo.ProviderType == 12) && !rsaCsp.CspKeyContainerInfo.HardwareDevice)
+ {
+ CspParameters csp = new CspParameters();
+ csp.ProviderType = 24;
+ csp.KeyContainerName = rsaCsp.CspKeyContainerInfo.KeyContainerName;
+ csp.KeyNumber = (int)rsaCsp.CspKeyContainerInfo.KeyNumber;
+ if (rsaCsp.CspKeyContainerInfo.MachineKeyStore)
+ csp.Flags = CspProviderFlags.UseMachineKeyStore;
+
+ csp.Flags |= CspProviderFlags.UseExistingKey;
+ return new RSACryptoServiceProvider(csp);
+ }
+
+ return rsaCsp;
+ }
+
public override bool HasPrivateKey()
{
return (this.PrivateKey != null);
private long[] _cacheSizeSamples;
private DateTime[] _cacheSizeSampleTimes;
private int _idx;
- private SRef _sizedRef;
+ private SRefMultiple _sizedRefMultiple;
private int _gen2Count;
private long _memoryLimit;
private void InitDisposableMembers(int cacheMemoryLimitMegabytes) {
bool dispose = true;
try {
- _sizedRef = new SRef(_memoryCache);
+ _sizedRefMultiple = new SRefMultiple(_memoryCache.AllSRefTargets);
SetLimit(cacheMemoryLimitMegabytes);
InitHistory();
dispose = false;
}
public void Dispose() {
- SRef sref = _sizedRef;
- if (sref != null && Interlocked.CompareExchange(ref _sizedRef, null, sref) == sref) {
+ SRefMultiple sref = _sizedRefMultiple;
+ if (sref != null && Interlocked.CompareExchange(ref _sizedRefMultiple, null, sref) == sref) {
sref.Dispose();
}
IMemoryCacheManager memoryCacheManager = s_memoryCacheManager;
// This update must happen, otherwise the CacheManager won't
// know the total cache size.
int gen2Count = GC.CollectionCount(2);
- SRef sref = _sizedRef;
+ SRefMultiple sref = _sizedRefMultiple;
if (gen2Count != _gen2Count && sref != null) {
// update _gen2Count
_gen2Count = gen2Count;
private static object s_initLock = new object();
private static MemoryCache s_defaultCache;
private static CacheEntryRemovedCallback s_sentinelRemovedCallback = new CacheEntryRemovedCallback(SentinelEntry.OnCacheEntryRemovedCallback);
- private MemoryCacheStore[] _stores;
+ private GCHandleRef<MemoryCacheStore>[] _storeRefs;
private int _storeCount;
- private int _storeMask;
private int _disposed;
private MemoryCacheStatistics _stats;
private string _name;
if (hashCode < 0) {
hashCode = (hashCode == Int32.MinValue) ? 0 : -hashCode;
}
- int idx = hashCode & _storeMask;
- return _stores[idx];
+ int idx = hashCode % _storeCount;
+ return _storeRefs[idx].Target;
+ }
+
+ internal object[] AllSRefTargets {
+ get {
+ var allStores = new MemoryCacheStore[_storeCount];
+ for (int i = 0; i < _storeCount; i++) {
+ allStores[i] = _storeRefs[i].Target;
+ }
+ return allStores;
+ }
}
[SecuritySafeCritical]
catch {
// ignore exceptions from perf counters
}
- for (int i = 0; i < _stores.Length; i++) {
- _stores[i] = new MemoryCacheStore(this, _perfCounters);
+ for (int i = 0; i < _storeCount; i++) {
+ _storeRefs[i] = new GCHandleRef<MemoryCacheStore> (new MemoryCacheStore(this, _perfCounters));
}
_stats = new MemoryCacheStatistics(this, config);
AppDomain appDomain = Thread.GetDomain();
}
}
#endif
- _storeMask = _storeCount - 1;
- _stores = new MemoryCacheStore[_storeCount];
+ _storeRefs = new GCHandleRef<MemoryCacheStore>[_storeCount];
InitDisposableMembers(config);
}
if (_stats != null) {
_stats.Dispose();
}
- if (_stores != null) {
- foreach (MemoryCacheStore store in _stores) {
- if (store != null) {
- store.Dispose();
+ if (_storeRefs != null) {
+ foreach (var storeRef in _storeRefs) {
+ if (storeRef != null) {
+ storeRef.Dispose();
}
}
}
IEnumerator IEnumerable.GetEnumerator() {
Hashtable h = new Hashtable();
if (!IsDisposed) {
- foreach (MemoryCacheStore store in _stores) {
- store.CopyTo(h);
+ foreach (var storeRef in _storeRefs) {
+ storeRef.Target.CopyTo(h);
}
}
return h.GetEnumerator();
protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
Dictionary<string, object> h = new Dictionary<string, object>();
if (!IsDisposed) {
- foreach (MemoryCacheStore store in _stores) {
- store.CopyTo(h);
+ foreach (var storeRef in _storeRefs) {
+ storeRef.Target.CopyTo(h);
}
}
return h.GetEnumerator();
}
long trimmed = 0;
if (_disposed == 0) {
- foreach (MemoryCacheStore store in _stores) {
- trimmed += store.TrimInternal(percent);
+ foreach (var storeRef in _storeRefs) {
+ trimmed += storeRef.Target.TrimInternal(percent);
}
}
return trimmed;
}
long count = 0;
if (!IsDisposed) {
- foreach (MemoryCacheStore store in _stores) {
- count += store.Count;
+ foreach (var storeRef in _storeRefs) {
+ count += storeRef.Target.Count;
}
}
return count;
private int _lastTrimPercent;
private DateTime _lastTrimTime;
private int _pollingInterval;
- private Timer _timer;
+ private GCHandleRef<Timer> _timerHandleRef;
private Object _timerLock;
private long _totalCountBeforeTrim;
private void AdjustTimer() {
lock (_timerLock) {
- if (_timer == null)
+ if (_timerHandleRef == null)
return;
+ Timer timer = _timerHandleRef.Target;
+
// the order of these if statements is important
// When above the high pressure mark, interval should be 5 seconds or less
if (_physicalMemoryMonitor.IsAboveHighPressure() || _cacheMemoryMonitor.IsAboveHighPressure()) {
if (_pollingInterval > MEMORYSTATUS_INTERVAL_5_SECONDS) {
_pollingInterval = MEMORYSTATUS_INTERVAL_5_SECONDS;
- _timer.Change(_pollingInterval, _pollingInterval);
+ timer.Change(_pollingInterval, _pollingInterval);
}
return;
}
int newPollingInterval = Math.Min(_configPollingInterval, MEMORYSTATUS_INTERVAL_30_SECONDS);
if (_pollingInterval != newPollingInterval) {
_pollingInterval = newPollingInterval;
- _timer.Change(_pollingInterval, _pollingInterval);
+ timer.Change(_pollingInterval, _pollingInterval);
}
return;
}
// there is no pressure, interval should be the value from config
if (_pollingInterval != _configPollingInterval) {
_pollingInterval = _configPollingInterval;
- _timer.Change(_pollingInterval, _pollingInterval);
+ timer.Change(_pollingInterval, _pollingInterval);
}
}
}
bool dispose = true;
try {
_cacheMemoryMonitor = new CacheMemoryMonitor(_memoryCache, _configCacheMemoryLimitMegabytes);
- _timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval);
+ Timer timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval);
+ _timerHandleRef = new GCHandleRef<Timer>(timer);
dispose = false;
}
finally {
public void Dispose() {
if (Interlocked.Exchange(ref _disposed, 1) == 0) {
lock (_timerLock) {
- Timer timer = _timer;
- if (timer != null && Interlocked.CompareExchange(ref _timer, null, timer) == timer) {
- timer.Dispose();
+ GCHandleRef<Timer> timerHandleRef = _timerHandleRef;
+ if (timerHandleRef != null && Interlocked.CompareExchange(ref _timerHandleRef, null, timerHandleRef) == timerHandleRef) {
+ timerHandleRef.Dispose();
Dbg.Trace("MemoryCacheStats", "Stopped CacheMemoryTimers");
}
}
using System.Security;
using System.Security.Permissions;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
namespace System.Runtime.Caching {
internal class SRef {
+#if !MONO
private static Type s_type = Type.GetType("System.SizedReference", true, false);
private Object _sizedRef;
+#endif
internal SRef(Object target) {
+#if !MONO
_sizedRef = Activator.CreateInstance(s_type,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance,
null,
new object[] { target },
null);
+#endif
}
internal long ApproximateSize {
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
get {
+#if MONO
+ // TODO: .net uses System.SizedReference which contains approximate size after Gen 2 collection
+ return 16;
+#else
object o = s_type.InvokeMember("ApproximateSize",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty,
null, // binder
null, // args
CultureInfo.InvariantCulture);
return (long)o;
+#endif
}
}
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
internal void Dispose() {
+#if !MONO
s_type.InvokeMember("Dispose",
BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod,
null, // binder
_sizedRef, // target
null, // args
CultureInfo.InvariantCulture);
+#endif
+ }
+ }
+
+ internal class SRefMultiple {
+ private SRef[] _srefs;
+ private long[] _sizes; // Getting SRef size in the debugger is extremely tedious so we keep the last read value here
+
+ internal SRefMultiple(object[] targets) {
+ _srefs = new SRef[targets.Length];
+ _sizes = new long[targets.Length];
+ for (int i = 0; i < targets.Length; i++) {
+ _srefs[i] = new SRef(targets[i]);
+ }
+ }
+
+ internal long ApproximateSize {
+ get {
+ long size = 0;
+ for (int i = 0; i < _srefs.Length; i++) {
+ size += (_sizes[i] = _srefs[i].ApproximateSize);
+ }
+ return size;
+ }
+ }
+
+ internal void Dispose() {
+ foreach (SRef s in _srefs) {
+ s.Dispose();
+ }
+ }
+ }
+
+ internal class GCHandleRef<T> : IDisposable
+ where T : class, IDisposable {
+ GCHandle _handle;
+ T _t;
+
+ [SecuritySafeCritical]
+ [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
+ public GCHandleRef(T t) {
+ _handle = GCHandle.Alloc(t);
+ }
+
+ public T Target {
+ [SecuritySafeCritical]
+ [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
+ get {
+ try {
+ T t = (T)_handle.Target;
+ if (t != null) {
+ return t;
+ }
+ }
+ catch (InvalidOperationException) {
+ // use the normal reference instead of throwing an exception when _handle is already freed
+ }
+ return _t;
+ }
+ }
+
+ [SecuritySafeCritical]
+ [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
+ public void Dispose() {
+ Target.Dispose();
+ // Safe to call Dispose more than once but not thread-safe
+ if (_handle.IsAllocated) {
+ // We must free the GC handle to avoid leaks.
+ // However after _handle is freed we no longer have access to its Target
+ // which will cause AVs and various race conditions under stress.
+ // We revert to using normal references after disposing the GC handle
+ _t = (T)_handle.Target;
+ _handle.Free();
+ }
}
}
}
if (dataContract == null)
{
dataContract = CreateGetOnlyCollectionDataContract(id, typeHandle, type);
- dataContractCache[id] = dataContract;
+
+ AssignDataContractToId(dataContract, id);
}
return dataContract;
}
{
return id;
}
- for (int i = 0; i < DataContractCriticalHelper.dataContractID; i++)
+
+ int currentDataContractId = DataContractCriticalHelper.dataContractID;
+
+ for (int i = 0; i < currentDataContractId; i++)
{
if (ContractMatches(classContract, dataContractCache[i]))
{
// check whether a corresponding update is required in ClassDataContract.IsNonAttributedTypeValidForSerialization
static DataContract CreateDataContract(int id, RuntimeTypeHandle typeHandle, Type type)
{
- lock (createDataContractLock)
+ DataContract dataContract = dataContractCache[id];
+
+ if (dataContract == null)
{
- DataContract dataContract = dataContractCache[id];
- if (dataContract == null)
+ lock (createDataContractLock)
{
- if (type == null)
- type = Type.GetTypeFromHandle(typeHandle);
- type = UnwrapNullableType(type);
- type = GetDataContractAdapterType(type);
- dataContract = GetBuiltInDataContract(type);
+ dataContract = dataContractCache[id];
+
if (dataContract == null)
{
- if (type.IsArray)
- dataContract = new CollectionDataContract(type);
- else if (type.IsEnum)
- dataContract = new EnumDataContract(type);
- else if (type.IsGenericParameter)
- dataContract = new GenericParameterDataContract(type);
- else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
- dataContract = new XmlDataContract(type);
- else
+ if (type == null)
+ type = Type.GetTypeFromHandle(typeHandle);
+ type = UnwrapNullableType(type);
+ type = GetDataContractAdapterType(type);
+ dataContract = GetBuiltInDataContract(type);
+ if (dataContract == null)
{
- //if (type.ContainsGenericParameters)
- // ThrowInvalidDataContractException(SR.GetString(SR.TypeMustNotBeOpenGeneric, type), type);
- if (type.IsPointer)
- type = Globals.TypeOfReflectionPointer;
-
- if (!CollectionDataContract.TryCreate(type, out dataContract))
+ if (type.IsArray)
+ dataContract = new CollectionDataContract(type);
+ else if (type.IsEnum)
+ dataContract = new EnumDataContract(type);
+ else if (type.IsGenericParameter)
+ dataContract = new GenericParameterDataContract(type);
+ else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
+ dataContract = new XmlDataContract(type);
+ else
{
- if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false) || ClassDataContract.IsNonAttributedTypeValidForSerialization(type))
- {
- dataContract = new ClassDataContract(type);
- }
- else
+ //if (type.ContainsGenericParameters)
+ // ThrowInvalidDataContractException(SR.GetString(SR.TypeMustNotBeOpenGeneric, type), type);
+ if (type.IsPointer)
+ type = Globals.TypeOfReflectionPointer;
+
+ if (!CollectionDataContract.TryCreate(type, out dataContract))
{
- ThrowInvalidDataContractException(SR.GetString(SR.TypeNotSerializable, type), type);
+ if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false) || ClassDataContract.IsNonAttributedTypeValidForSerialization(type))
+ {
+ dataContract = new ClassDataContract(type);
+ }
+ else
+ {
+ ThrowInvalidDataContractException(SR.GetString(SR.TypeNotSerializable, type), type);
+ }
}
}
}
- }
+
+ AssignDataContractToId(dataContract, id);
+ }
}
+ }
+
+ return dataContract;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static void AssignDataContractToId(DataContract dataContract, int id)
+ {
+ lock (cacheLock)
+ {
dataContractCache[id] = dataContract;
- return dataContract;
}
}
parseMethodSet = true;
}
- return parseMethod; }
+ return parseMethod;
+ }
}
internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString ns)
// This will break round-tripping of these dates (see bug 9690 in CSD Developer Framework)
if (value.Kind != DateTimeKind.Utc)
{
- long tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks;
+ long tickCount;
+ if (!LocalAppContextSwitches.DoNotUseTimeZoneInfo)
+ {
+ tickCount = value.Ticks - TimeZoneInfo.Local.GetUtcOffset(value).Ticks;
+ }
+ else
+ {
+ tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks;
+ }
if ((tickCount > DateTime.MaxValue.Ticks) || (tickCount < DateTime.MinValue.Ticks))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
case DateTimeKind.Unspecified:
case DateTimeKind.Local:
// +"zzzz";
- TimeSpan ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime());
+ TimeSpan ts;
+ if (!LocalAppContextSwitches.DoNotUseTimeZoneInfo)
+ {
+ ts = TimeZoneInfo.Local.GetUtcOffset(value.ToLocalTime());
+ }
+ else
+ {
+ ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime());
+ }
if (ts.Ticks < 0)
{
writer.WriteString("-");
if (!Schemas.Contains(Globals.SerializationNamespace))
{
StringReader reader = new StringReader(Globals.SerializationSchema);
- XmlSchema schema = XmlSchema.Read(reader, null);
+ XmlSchema schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
if (schema == null)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace)));
Schemas.Add(schema);
if (!schemaSet.Contains(Globals.SerializationNamespace))
{
StringReader reader = new StringReader(Globals.SerializationSchema);
- XmlSchema schema = XmlSchema.Read(reader, null);
+ XmlSchema schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
if (schema == null)
throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace)));
schemaSet.Add(schema);
}
}
- // Provides the version of the WebSocket protocol supported by IIS. Throws an exception if called before we determined the value.
+ // Provides the version of the WebSocket protocol supported by IIS.
// Returns null if WebSockets are not supported (because the IIS WebSocketModule is not installed or enabled).
public override string WebSocketVersion
{
get
{
- if (isWebSocketVersionSet)
- {
- return webSocketVersion;
- }
- else
- {
- throw Fx.AssertAndFailFast("The supported WebSocket protocol version is not determined at this time.");
- }
+ return isWebSocketVersionSet ? webSocketVersion : null;
}
}
/// </remarks>
public static void TrySetWebSocketVersion(HttpApplication application)
{
- Fx.Assert(application != null, "Invalid argument.");
-
if (!isWebSocketVersionSet)
{
webSocketVersion = application.Request.ServerVariables[WebSocketVersionServerProperty];
[Fx.Tag.SecurityNote(Critical = "Usage of EventDescriptor, which is protected by a LinkDemand")]
[SecurityCritical]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml", Justification = "It is internal code. No security concern.")]
public void WriteTraceSource(ref EventDescriptor eventDescriptor, string description, TracePayload payload)
{
if (this.TracingEnabled)
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
+
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
using System;
using System.Collections.Generic;
static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
}
}
+
+#pragma warning restore 436
//
// ==--==
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
// NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches
using System;
using System.Collections.Generic;
}
}
}
+
+#pragma warning restore 436
LocalAppContextSwitches.SetDefaultsLessOrEqual_452();
}
+ if (version <= 40601)
+ {
+ LocalAppContextSwitches.SetDefaultsLessOrEqual_461();
+ }
+
break;
}
}
{
AspNetEnvironment env = AspNetEnvironment.Current;
- // When IIS hosted, WebSockets can be used if the pipeline mode is integrated and the WebSocketModule is loaded.
- // Otherwise, the client requests will not be upgraded to web sockets (see the code in HostedHttpTransportManager.HttpContextReceived(..)).
- // We do the checks below (and fail the service activation), to avoid starting a WebSockets listener that won't get called.
+ // When IIS hosted, WebSockets can be used if the pipeline mode is integrated
if (!env.UsingIntegratedPipeline)
{
throw FxTrace.Exception.AsError(new NotSupportedException(SR.GetString(SR.WebSocketsNotSupportedInClassicPipeline)));
}
- else if (!env.IsWebSocketModuleLoaded)
- {
- throw FxTrace.Exception.AsError(new NotSupportedException(SR.GetString(SR.WebSocketModuleNotLoaded)));
- }
}
else if (!WebSocketHelper.OSSupportsWebSockets())
{
{
using System.Collections.Generic;
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Net;
// then the Exact HostName, and lastly the WeakWildcard
string[] hostChoices = new string[] { "+", uri.Host, "*" };
bool[] globalChoices = new bool[] { true, false };
+ string matchPath = String.Empty;
+ string matchPipeName = null;
+
for (int i = 0; i < hostChoices.Length; i++)
{
for (int iGlobal = 0; iGlobal < globalChoices.Length; iGlobal++)
continue;
}
- // walk up the path hierarchy, looking for first match
+ // walk up the path hierarchy, looking for match
string path = PipeUri.GetPath(uri);
while (path.Length > 0)
string pipeName = sharedMemory.GetPipeName(appInfo);
if (pipeName != null)
{
- return pipeName;
+ // Found a matching pipe name.
+ // If the best match app setting is enabled, save the match if it is the best so far and continue.
+ // Otherwise, just return the first match we find.
+ if (ServiceModelAppSettings.UseBestMatchNamedPipeUri)
+ {
+ if (path.Length > matchPath.Length)
+ {
+ matchPath = path;
+ matchPipeName = pipeName;
+ }
+ }
+ else
+ {
+ return pipeName;
+ }
}
}
finally
}
}
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri),
- new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri))));
+ if (string.IsNullOrEmpty(matchPipeName))
+ {
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
+ new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri),
+ new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri))));
+ }
+
+ return matchPipeName;
}
public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
new StringTraceRecord("Uri", remoteUri.ToString()), this, null);
}
resolvedAddress = GetPipeName(remoteUri, this.pipeSettings);
-
const int backoffBufferMilliseconds = 150;
TimeSpan backoffTimeout;
if (timeout >= TimeSpan.FromMilliseconds(backoffBufferMilliseconds * 2))
return builder.ToString();
}
+ [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. It will cause compatibility issue. Not used for cryptographic purposes.")]
static HashAlgorithm GetHashAlgorithm()
{
if (SecurityUtilsEx.RequiresFipsCompliance)
internal const bool RequireClientCertificate = false;
internal const int MaxFaultSize = MaxBufferSize;
internal const int MaxSecurityFaultSize = 16384;
- internal const SslProtocols SslProtocols = System.Security.Authentication.SslProtocols.Ssl3 |
- System.Security.Authentication.SslProtocols.Tls |
+
+ internal const SslProtocols SslProtocols = System.Security.Authentication.SslProtocols.Tls |
System.Security.Authentication.SslProtocols.Tls11 |
System.Security.Authentication.SslProtocols.Tls12;
#if !FEATURE_CORECLR
- // On CoreCLR this is not the way to determine if a process is a tailored application (which means APPX).
- // On CoreCLR AppX is determined by a flag past to the host which is exposed by AppDomain.IsAppXProcess in mscorlib.
- // The reason for this if-def is to ensure nobody takes a dependency on this on CoreCLR.
-
+ private static IntPtr GetCurrentProcessToken() { return new IntPtr(-4); }
+
+ enum AppPolicyClrCompat
+ {
+ AppPolicyClrCompat_Others = 0,
+ AppPolicyClrCompat_ClassicDesktop = 1,
+ AppPolicyClrCompat_Universal = 2,
+ AppPolicyClrCompat_PackagedDesktop = 3
+ };
+
+ [DllImport(KERNEL32, CharSet = CharSet.None, EntryPoint = "AppPolicyGetClrCompat")]
+ [System.Security.SecuritySafeCritical]
+ [return: MarshalAs(UnmanagedType.I4)]
+ private static extern Int32 _AppPolicyGetClrCompat(IntPtr processToken, out AppPolicyClrCompat appPolicyClrCompat);
+
// AppModel.h functions (Win8+)
[DllImport(KERNEL32, CharSet = CharSet.None, EntryPoint = "GetCurrentPackageId")]
- [SecurityCritical]
+ [System.Security.SecuritySafeCritical]
[return: MarshalAs(UnmanagedType.I4)]
- private static extern Int32 GetCurrentPackageId(ref Int32 pBufferLength, Byte[] pBuffer);
+ private static extern Int32 _GetCurrentPackageId(ref Int32 pBufferLength, Byte[] pBuffer);
- [Fx.Tag.SecurityNote(
- Critical = "Critical because it calls the native function GetCurrentPackageId.",
- Safe = "Safe because it takes no user input and it doesn't leak security sensitive information.")]
- [SecuritySafeCritical]
+ [DllImport(KERNEL32, CharSet=System.Runtime.InteropServices.CharSet.Auto, BestFitMapping=false)]
+ [ResourceExposure(ResourceScope.Machine)]
+ private static extern IntPtr GetModuleHandle(string modName);
+
+ // Copied from Win32Native.cs
+ // Note - do NOT use this to call methods. Use P/Invoke, which will
+ // do much better things w.r.t. marshaling, pinning memory, security
+ // stuff, better interactions with thread aborts, etc. This is used
+ // solely by DoesWin32MethodExist for avoiding try/catch EntryPointNotFoundException
+ // in scenarios where an OS Version check is insufficient
+ [DllImport(KERNEL32, CharSet=CharSet.Ansi, BestFitMapping=false, SetLastError=true, ExactSpelling=true)]
+ [ResourceExposure(ResourceScope.None)]
+ private static extern IntPtr GetProcAddress(IntPtr hModule, String methodName);
+
+ [System.Security.SecurityCritical] // auto-generated
+ private static bool DoesWin32MethodExist(String moduleName, String methodName)
+ {
+ // GetModuleHandle does not increment the module's ref count, so we don't need to call FreeLibrary.
+ IntPtr hModule = GetModuleHandle(moduleName);
+ if (hModule == IntPtr.Zero) {
+ System.Diagnostics.Debug.Assert(hModule != IntPtr.Zero, "GetModuleHandle failed. Dll isn't loaded?");
+ return false;
+ }
+ IntPtr functionPointer = GetProcAddress(hModule, methodName);
+ return (functionPointer != IntPtr.Zero);
+ }
+
+ // On CoreCLR this is not the way to determine if a process is a tailored application (which means APPX).
+ // On CoreCLR AppX is determined by a flag past to the host which is exposed by AppDomain.IsAppXProcess in mscorlib.
+ // The reason for this if-def is to ensure nobody takes a dependency on this on CoreCLR.
+ [System.Security.SecuritySafeCritical]
private static bool _IsTailoredApplication()
{
- if (OSEnvironmentHelper.IsAtLeast(OSVersion.Win8))
+ Version windows8Version = new Version(6, 2, 0, 0);
+ OperatingSystem os = Environment.OSVersion;
+ bool osSupportsPackagedProcesses = os.Platform == PlatformID.Win32NT && os.Version >= windows8Version;
+
+ if (osSupportsPackagedProcesses && DoesWin32MethodExist(KERNEL32, "AppPolicyGetClrCompat"))
{
- int bufLen = 0;
- // Will return ERROR_INSUFFICIENT_BUFFER when running within a tailored application,
+ // Use AppPolicyGetClrCompat if it is available. Return true if and only if this is a UWA which means if
+ // this is packaged desktop app this method will return false. This may cause some confusion however
+ // this is necessary to make the behavior of packaged desktop apps identical to desktop apps.
+ AppPolicyClrCompat appPolicyClrCompat;
+ return _AppPolicyGetClrCompat(GetCurrentProcessToken(), out appPolicyClrCompat) == ERROR_SUCCESS &&
+ appPolicyClrCompat == AppPolicyClrCompat.AppPolicyClrCompat_Universal;
+ }
+ else if(osSupportsPackagedProcesses && DoesWin32MethodExist(KERNEL32, "GetCurrentPackageId"))
+ {
+ Int32 bufLen = 0;
+ // Will return ERROR_INSUFFICIENT_BUFFER when running within a packaged application,
// and will return ERROR_NO_PACKAGE_IDENTITY otherwise.
- return GetCurrentPackageId(ref bufLen, null) == ERROR_INSUFFICIENT_BUFFER;
+ return _GetCurrentPackageId(ref bufLen, null) == ERROR_INSUFFICIENT_BUFFER;
}
else
- {
+ { // We must be running on a downlevel OS.
return false;
}
}
{
using System;
using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Net;
static readonly HashSet<char> InvalidSeparatorSet = new HashSet<char>(new char[] { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ' });
static string currentWebSocketVersion;
+ [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Usage of SHA1 is part of WebSocket spec. Justification in RFC6455 section 10.8")]
internal static string ComputeAcceptHeader(string webSocketKey)
{
Fx.Assert(webSocketKey != null, "webSocketKey should not be null.");
{
ConfigurationPropertyCollection properties = new ConfigurationPropertyCollection();
properties.Add(new ConfigurationProperty("requireClientCertificate", typeof(System.Boolean), false, null, null, System.Configuration.ConfigurationPropertyOptions.None));
- properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Default | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None));
+ properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None));
this.properties = properties;
}
return this.properties;
properties.Add(new ConfigurationProperty("clientCredentialType", typeof(System.ServiceModel.TcpClientCredentialType), System.ServiceModel.TcpClientCredentialType.Windows, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.TcpClientCredentialTypeHelper)), System.Configuration.ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty("protectionLevel", typeof(System.Net.Security.ProtectionLevel), System.Net.Security.ProtectionLevel.EncryptAndSign, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.ProtectionLevelHelper)), System.Configuration.ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty("extendedProtectionPolicy", typeof(System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement), null, null, null, System.Configuration.ConfigurationPropertyOptions.None));
- properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Default | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None));
+ properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None));
this.properties = properties;
}
return this.properties;
internal static XmlSchema CreateWsdl()
{
- return XmlSchema.Read(new StringReader(wsdl), null);
+ StringReader reader = new StringReader(wsdl);
+ return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
}
+
internal static XmlSchema CreateSoap()
{
- return XmlSchema.Read(new StringReader(soap), null);
+ StringReader reader = new StringReader(soap);
+ return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
}
internal static XmlSchema CreateSoapEncoding()
{
- return XmlSchema.Read(new StringReader(soapEncoding), null);
+ StringReader reader = new StringReader(soapEncoding);
+ return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
}
internal static XmlSchema CreateFakeSoapEncoding()
{
- return XmlSchema.Read(new StringReader(fakeSoapEncoding), null);
+ StringReader reader = new StringReader(fakeSoapEncoding);
+ return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
}
internal static XmlSchema CreateFakeXsdSchema()
{
- return XmlSchema.Read(new StringReader(fakeXsd), null);
+ StringReader reader = new StringReader(fakeXsd);
+ return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
}
internal static XmlSchema CreateFakeXmlSchema()
{
- return XmlSchema.Read(new StringReader(fakeXmlSchema), null);
+ StringReader reader = new StringReader(fakeXmlSchema);
+ return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
}
internal static bool IsKnownSchema(string ns)
namespace System.ServiceModel.Description
{
using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
return newWsdl;
}
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3069:ReviewDtdProcessingAssignment", Justification = "This is trusted server code from the application only. We should allow the customer add dtd.")]
private static XmlSchema CloneXsd(XmlSchema originalXsd)
{
Fx.Assert(originalXsd != null, "originalXsd must not be null");
{
originalXsd.Write(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
- newXsd = XmlSchema.Read(memoryStream, null);
+ newXsd = XmlSchema.Read(new XmlTextReader(memoryStream) { DtdProcessing = DtdProcessing.Parse }, null);
}
return newXsd;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+ using System.Diagnostics.CodeAnalysis;
using System.Runtime;
using System.ServiceModel.Channels;
using System.ServiceModel.Diagnostics;
}
}
+ [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml")]
static QueryMatcher()
{
QueryMatcher.defaultFunctionLibs = new IFunctionLibrary[] { new XPathFunctionLibrary() };
using System.Diagnostics;
using System.Reflection;
using System.Runtime;
- using System.Runtime.Diagnostics;
using System.Security;
using System.ServiceModel.Description;
using System.ServiceModel.Diagnostics;
- using System.ServiceModel.Diagnostics.Application;
using System.Threading.Tasks;
+ using Threading;
/// <summary>
/// An invoker used when some operation contract has a return value of Task or its generic counterpart (Task of T)
internal class TaskMethodInvoker : IOperationInvoker
{
private const string ResultMethodName = "Result";
- private MethodInfo taskMethod;
- private bool isGenericTask;
+ private readonly MethodInfo taskMethod;
private InvokeDelegate invokeDelegate;
private int inputParameterCount;
private int outputParameterCount;
- private object[] outputs;
- private MethodInfo toAsyncMethodInfo;
private MethodInfo taskTResultGetMethod;
+ private bool isGenericTask;
public TaskMethodInvoker(MethodInfo taskMethod, Type taskType)
{
if (taskType != ServiceReflector.VoidType)
{
- this.toAsyncMethodInfo = TaskExtensions.MakeGenericMethod(taskType);
this.taskTResultGetMethod = ((PropertyInfo)taskMethod.ReturnType.GetMember(ResultMethodName)[0]).GetGetMethod();
this.isGenericTask = true;
}
get { return this.taskMethod; }
}
- private InvokeDelegate InvokeDelegate
- {
- get
- {
- this.EnsureIsInitialized();
- return this.invokeDelegate;
- }
- }
-
- private int InputParameterCount
- {
- get
- {
- this.EnsureIsInitialized();
- return this.inputParameterCount;
- }
- }
-
- private int OutputParameterCount
- {
- get
- {
- this.EnsureIsInitialized();
- return this.outputParameterCount;
- }
- }
-
public object[] AllocateInputs()
{
- return EmptyArray.Allocate(this.InputParameterCount);
+ EnsureIsInitialized();
+
+ return EmptyArray<object>.Allocate(this.inputParameterCount);
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
+ {
+ return ToApm(InvokeAsync(instance, inputs), callback, state);
+ }
+
+ public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
if (instance == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject)));
}
- if (inputs == null)
- {
- if (this.InputParameterCount > 0)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceNull, this.InputParameterCount)));
- }
- }
- else if (inputs.Length != this.InputParameterCount)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceInvalid, this.InputParameterCount, inputs.Length)));
- }
-
- this.outputs = EmptyArray.Allocate(this.OutputParameterCount);
-
- AsyncMethodInvoker.StartOperationInvokePerformanceCounters(this.taskMethod.Name);
-
- IAsyncResult returnValue;
+ object returnVal = null;
bool callFailed = true;
bool callFaulted = false;
ServiceModelActivity activity = null;
+ Activity boundOperation = null;
try
{
- Activity boundActivity = null;
- AsyncMethodInvoker.CreateActivityInfo(ref activity, ref boundActivity);
+ AsyncMethodInvoker.GetActivityInfo(ref activity, ref boundOperation);
- AsyncMethodInvoker.StartOperationInvokeTrace(this.taskMethod.Name);
-
- using (boundActivity)
+ Task<Tuple<object, object[]>> invokeTask = result as Task<Tuple<object, object[]>>;
+
+ if (invokeTask == null)
{
- if (DiagnosticUtility.ShouldUseActivity)
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.SFxInvalidCallbackIAsyncResult));
+ }
+
+ AggregateException ae = null;
+ Tuple<object, object[]> tuple = null;
+ Task task = null;
+
+ if (invokeTask.IsFaulted)
+ {
+ Fx.Assert(invokeTask.Exception != null, "Task.IsFaulted guarantees non-null exception.");
+ ae = invokeTask.Exception;
+ }
+ else
+ {
+ Fx.Assert(invokeTask.IsCompleted, "Task.Result is expected to be completed");
+
+ tuple = invokeTask.Result;
+ task = tuple.Item1 as Task;
+
+ if (task == null)
{
- string activityName = SR.GetString(SR.ActivityExecuteMethod, this.taskMethod.DeclaringType.FullName, this.taskMethod.Name);
- ServiceModelActivity.Start(activity, activityName, ActivityType.ExecuteUserCode);
+ outputs = tuple.Item2;
+ return null;
}
- object taskReturnValue = this.InvokeDelegate(instance, inputs, this.outputs);
-
- if (taskReturnValue == null)
+ if (task.IsFaulted)
{
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("task");
+ Fx.Assert(task.Exception != null, "Task.IsFaulted guarantees non-null exception.");
+ ae = task.Exception;
}
- else if (this.isGenericTask)
+ }
+
+ if (ae != null && ae.InnerException != null)
+ {
+ if (ae.InnerException is FaultException)
{
- returnValue = (IAsyncResult)this.toAsyncMethodInfo.Invoke(null, new object[] { taskReturnValue, callback, state });
+ // If invokeTask.IsFaulted we produce the 'callFaulted' behavior below.
+ // Any other exception will retain 'callFailed' behavior.
+ callFaulted = true;
+ callFailed = false;
}
- else
+
+ if (ae.InnerException is SecurityException)
{
- returnValue = ((Task)taskReturnValue).AsAsyncResult(callback, state);
+ DiagnosticUtility.TraceHandledException(ae.InnerException, TraceEventType.Warning);
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
}
- callFailed = false;
+ invokeTask.GetAwaiter().GetResult();
}
- }
- catch (System.Security.SecurityException e)
- {
- DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
- }
- catch (Exception e)
- {
- TraceUtility.TraceUserCodeException(e, this.taskMethod);
- if (e is FaultException)
+
+ // Task cancellation without an exception indicates failure but we have no
+ // additional information to provide. Accessing Task.Result will throw a
+ // TaskCanceledException. For consistency between void Tasks and Task<T>,
+ // we detect and throw here.
+ if (task.IsCanceled)
{
- callFaulted = true;
- callFailed = false;
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TaskCanceledException(task));
}
- throw;
+ outputs = tuple.Item2;
+
+ returnVal = this.isGenericTask ? this.taskTResultGetMethod.Invoke(task, Type.EmptyTypes) : null;
+ callFailed = false;
+
+ return returnVal;
}
finally
{
- ServiceModelActivity.Stop(activity);
-
- // Any exception above means InvokeEnd will not be called, so complete it here.
- if (callFailed || callFaulted)
+ if (boundOperation != null)
{
- AsyncMethodInvoker.StopOperationInvokeTrace(callFailed, callFaulted, this.TaskMethod.Name);
- AsyncMethodInvoker.StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.TaskMethod.Name);
+ ((IDisposable)boundOperation).Dispose();
}
- }
- return returnValue;
+ ServiceModelActivity.Stop(activity);
+ AsyncMethodInvoker.StopOperationInvokeTrace(callFailed, callFaulted, this.TaskMethod.Name);
+ AsyncMethodInvoker.StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.TaskMethod.Name);
+ }
}
- public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
+ private async Task<Tuple<object, object[]>> InvokeAsync(object instance, object[] inputs)
{
- object returnVal;
- bool callFailed = true;
- bool callFaulted = false;
- ServiceModelActivity activity = null;
+ EnsureIsInitialized();
if (instance == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject)));
}
+ if (inputs == null)
+ {
+ if (this.inputParameterCount > 0)
+ {
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceNull, this.inputParameterCount)));
+ }
+ }
+ else if (inputs.Length != this.inputParameterCount)
+ {
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceInvalid, this.inputParameterCount, inputs.Length)));
+ }
+
+ object[] outputs = EmptyArray.Allocate(this.outputParameterCount);
+
+ AsyncMethodInvoker.StartOperationInvokePerformanceCounters(this.taskMethod.Name);
+
+ object returnValue;
+ ServiceModelActivity activity = null;
+ Activity boundActivity = null;
+
try
{
- Activity boundOperation = null;
- AsyncMethodInvoker.GetActivityInfo(ref activity, ref boundOperation);
+ AsyncMethodInvoker.CreateActivityInfo(ref activity, ref boundActivity);
+ AsyncMethodInvoker.StartOperationInvokeTrace(this.taskMethod.Name);
- using (boundOperation)
+ if (DiagnosticUtility.ShouldUseActivity)
{
- Task task = result as Task;
+ string activityName = SR.GetString(SR.ActivityExecuteMethod, this.taskMethod.DeclaringType.FullName, this.taskMethod.Name);
+ ServiceModelActivity.Start(activity, activityName, ActivityType.ExecuteUserCode);
+ }
- Fx.Assert(task != null, "InvokeEnd needs to be called with the result returned from InvokeBegin.");
- if (task.IsFaulted)
- {
- Fx.Assert(task.Exception != null, "Task.IsFaulted guarantees non-null exception.");
+ OperationContext.EnableAsyncFlow();
- // If FaultException is thrown, we will get 'callFaulted' behavior below.
- // Any other exception will retain 'callFailed' behavior.
- throw FxTrace.Exception.AsError<FaultException>(task.Exception);
- }
+ returnValue = this.invokeDelegate(instance, inputs, outputs);
- // Task cancellation without an exception indicates failure but we have no
- // additional information to provide. Accessing Task.Result will throw a
- // TaskCanceledException. For consistency between void Tasks and Task<T>,
- // we detect and throw here.
- if (task.IsCanceled)
- {
- throw FxTrace.Exception.AsError(new TaskCanceledException(task));
- }
+ if (returnValue == null)
+ {
+ throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("task");
+ }
- outputs = this.outputs;
- if (this.isGenericTask)
- {
- returnVal = this.taskTResultGetMethod.Invoke(result, Type.EmptyTypes);
- }
- else
- {
- returnVal = null;
- }
+ var returnValueTask = returnValue as Task;
- callFailed = false;
+ if (returnValueTask != null)
+ {
+ // Only return once the task has completed
+ await returnValueTask;
}
+
+ return Tuple.Create(returnValue, outputs);
}
catch (SecurityException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
}
- catch (FaultException)
+ catch (Exception e)
{
- callFaulted = true;
- callFailed = false;
+ TraceUtility.TraceUserCodeException(e, this.taskMethod);
throw;
}
finally
{
+ OperationContext.DisableAsyncFlow();
+
+ if (boundActivity != null)
+ {
+ ((IDisposable)boundActivity).Dispose();
+ }
+
ServiceModelActivity.Stop(activity);
- AsyncMethodInvoker.StopOperationInvokeTrace(callFailed, callFaulted, this.TaskMethod.Name);
- AsyncMethodInvoker.StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.TaskMethod.Name);
}
+ }
+
+ // Helper method when implementing an APM wrapper around a Task based async method which returns a result.
+ // In the BeginMethod method, you would call use ToApm to wrap a call to MethodAsync:
+ // return MethodAsync(params).ToApm(callback, state);
+ // In the EndMethod, you would use ToApmEnd<TResult> to ensure the correct exception handling
+ // This will handle throwing exceptions in the correct place and ensure the IAsyncResult contains the provided
+ // state object
+ private static Task<TResult> ToApm<TResult>(Task<TResult> task, AsyncCallback callback, object state)
+ {
+ // When using APM, the returned IAsyncResult must have the passed in state object stored in AsyncState. This
+ // is so the callback can regain state. If the incoming task already holds the state object, there's no need
+ // to create a TaskCompletionSource to ensure the returned (IAsyncResult)Task has the right state object.
+ // This is a performance optimization for this special case.
+ if (task.AsyncState == state)
+ {
+ if (callback != null)
+ {
+ task.ContinueWith((antecedent, obj) =>
+ {
+ AsyncCallback callbackObj = (AsyncCallback)obj;
+ callbackObj(antecedent);
+ }, callback, CancellationToken.None, TaskContinuationOptions.HideScheduler, TaskScheduler.Default);
+ }
+
+ return task;
+ }
+
+ // Need to create a TaskCompletionSource so that the returned Task object has the correct AsyncState value.
+ var tcs = new TaskCompletionSource<TResult>(state);
+ var continuationState = Tuple.Create(tcs, callback);
+
+ task.ContinueWith((antecedent, obj) =>
+ {
+ Tuple<TaskCompletionSource<TResult>, AsyncCallback> tuple = (Tuple<TaskCompletionSource<TResult>, AsyncCallback>)obj;
+ TaskCompletionSource<TResult> tcsObj = tuple.Item1;
+ AsyncCallback callbackObj = tuple.Item2;
+
+ if (antecedent.IsFaulted)
+ {
+ tcsObj.TrySetException(antecedent.Exception.InnerException);
+ }
+ else if (antecedent.IsCanceled)
+ {
+ tcsObj.TrySetCanceled();
+ }
+ else
+ {
+ tcsObj.TrySetResult(antecedent.Result);
+ }
+
+ if (callbackObj != null)
+ {
+ callbackObj(tcsObj.Task);
+ }
+ }, continuationState, CancellationToken.None, TaskContinuationOptions.HideScheduler, TaskScheduler.Default);
- return returnVal;
+ return tcs.Task;
}
private void EnsureIsInitialized()
bufferWriter.Flush();
XmlDocument doc = new XmlDocument();
memoryStream.Position = 0;
- doc.Load(memoryStream);
+ doc.Load(new XmlTextReader(memoryStream) { DtdProcessing = DtdProcessing.Prohibit });
//doc.Save(Console.Out);
foreach (XmlElement element in doc.DocumentElement.ChildNodes)
{
static XmlSchema GetEprSchema()
{
- using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema)))
+ using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema)) { DtdProcessing = DtdProcessing.Prohibit })
{
return XmlSchema.Read(reader, null);
}
static XmlSchema GetEprSchema()
{
- using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema)))
+ using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema)) { DtdProcessing = DtdProcessing.Prohibit })
{
return XmlSchema.Read(reader, null);
}
{
private const string DisableExplicitConnectionCloseHeaderString = "Switch.System.ServiceModel.DisableExplicitConnectionCloseHeader";
private const string AllowUnsignedToHeaderString = "Switch.System.ServiceModel.AllowUnsignedToHeader";
+ private const string DisableCngCertificatesString = "Switch.System.ServiceModel.DisableCngCertificates";
private static int disableExplicitConnectionCloseHeader;
private static int allowUnsignedToHeader;
+ private static int disableCngCertificates;
public static bool DisableExplicitConnectionCloseHeader
{
}
}
+ public static bool DisableCngCertificates
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(DisableCngCertificatesString, ref disableCngCertificates);
+ }
+ }
+
public static void SetDefaultsLessOrEqual_452()
{
+#pragma warning disable BCL0012
// Define the switches that should be true for 4.5.2 or less, false for 4.6+.
LocalAppContext.DefineSwitchDefault(DisableExplicitConnectionCloseHeaderString, true);
+#pragma warning restore BCL0012
+ }
+
+ public static void SetDefaultsLessOrEqual_461()
+ {
+#pragma warning disable BCL0012
+ // Define the switches that should be true for 4.6.1 or less, false for 4.6.2+.
+ LocalAppContext.DefineSwitchDefault(DisableCngCertificatesString, true);
+#pragma warning restore BCL0012
}
}
}
namespace System.ServiceModel
{
using System.Collections.Generic;
- using System.ComponentModel;
using System.Runtime;
using System.Security.Claims;
using System.Security.Principal;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Security;
+ using System.Threading;
public sealed class OperationContext : IExtensibleObject<OperationContext>
{
[ThreadStatic]
static Holder currentContext;
+ static AsyncLocal<OperationContext> currentAsyncLocalContext = new AsyncLocal<OperationContext>();
+
ServiceChannel channel;
Message clientReply;
bool closeClientReply;
MessageHeaders outgoingMessageHeaders;
MessageVersion outgoingMessageVersion;
EndpointDispatcher endpointDispatcher;
+ bool isAsyncFlowEnabled;
public event EventHandler OperationCompleted;
{
get
{
- return CurrentHolder.Context;
+ return ShouldUseAsyncLocalContext ? OperationContext.currentAsyncLocalContext.Value : CurrentHolder.Context;
}
set
{
- CurrentHolder.Context = value;
+ if (ShouldUseAsyncLocalContext)
+ {
+ OperationContext.currentAsyncLocalContext.Value = value;
+ }
+ else
+ {
+ CurrentHolder.Context = value;
+ }
}
}
}
}
+ private static bool ShouldUseAsyncLocalContext
+ {
+ get
+ {
+ return CurrentHolder.Context == null && OperationContext.currentAsyncLocalContext.Value != null && OperationContext.currentAsyncLocalContext.Value.isAsyncFlowEnabled;
+ }
+ }
+
public EndpointDispatcher EndpointDispatcher
{
get
this.clientReply = null;
}
+ internal static void EnableAsyncFlow()
+ {
+ CurrentHolder.Context.isAsyncFlowEnabled = true;
+ currentAsyncLocalContext.Value = CurrentHolder.Context;
+ }
+
+ internal static void DisableAsyncFlow()
+ {
+ if (OperationContext.Current != null && OperationContext.Current.isAsyncFlowEnabled)
+ {
+ OperationContext.Current.isAsyncFlowEnabled = false;
+ currentAsyncLocalContext.Value = null;
+ }
+ }
+
internal void FireOperationCompleted()
{
try
public sealed class OperationContextScope : IDisposable
{
- [ThreadStatic]
- static OperationContextScope currentScope;
+ static AsyncLocal<OperationContextScope> currentScope = new AsyncLocal<OperationContextScope>();
OperationContext currentContext;
bool disposed;
readonly OperationContext originalContext = OperationContext.Current;
- readonly OperationContextScope originalScope = OperationContextScope.currentScope;
- readonly Thread thread = Thread.CurrentThread;
+ readonly OperationContextScope originalScope = OperationContextScope.currentScope.Value;
public OperationContextScope(IContextChannel channel)
{
void PushContext(OperationContext context)
{
this.currentContext = context;
- OperationContextScope.currentScope = this;
+ OperationContextScope.currentScope.Value = this;
OperationContext.Current = this.currentContext;
}
void PopContext()
{
- if (this.thread != Thread.CurrentThread)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidContextScopeThread0)));
-
- if (OperationContextScope.currentScope != this)
+ if (OperationContextScope.currentScope.Value != this)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInterleavedContextScopes0)));
if (OperationContext.Current != this.currentContext)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxContextModifiedInsideScope0)));
- OperationContextScope.currentScope = this.originalScope;
+ OperationContextScope.currentScope.Value = this.originalScope;
OperationContext.Current = this.originalContext;
if (this.currentContext != null)
using System.Text;
using System.Xml;
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
using Psha1DerivedKeyGenerator = System.IdentityModel.Psha1DerivedKeyGenerator;
return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest);
}
+ [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Required as SOAP spec requires supporting SHA1.")]
internal static HashAlgorithm CreateHashAlgorithm(string digestMethod)
{
object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(digestMethod);
}
}
+ [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Required as SOAP spec requires supporting SHA1.")]
internal static HashAlgorithm CreateHashForAsymmetricSignature(string signatureMethod)
{
object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(signatureMethod);
[SecuritySafeCritical]
static bool CanKeyDoKeyExchange(X509Certificate2 certificate)
{
- CspKeyContainerInfo info = GetKeyContainerInfo(certificate);
- return info != null && info.KeyNumber == KeyNumber.Exchange;
+ bool canDoKeyExchange = false;
+
+ if (!LocalAppContextSwitches.DisableCngCertificates)
+ {
+ X509KeyUsageExtension keyUsageExtension = null;
+ for (int i = 0; i < certificate.Extensions.Count; i++)
+ {
+ keyUsageExtension = certificate.Extensions[i] as X509KeyUsageExtension;
+ if (keyUsageExtension != null)
+ {
+ break;
+ }
+ }
+
+ // No KeyUsage extension means most usages are permitted including key exchange.
+ // See RFC 5280 section 4.2.1.3 (Key Usage) for details. If the extension is non-critical
+ // then it's non-enforcing and meant as an aid in choosing the best certificate when
+ // there are multiple certificates to choose from.
+ if (keyUsageExtension == null || !keyUsageExtension.Critical)
+ {
+ return true;
+ }
+
+ // One of KeyAgreement, KeyEncipherment or DigitalSignature need to be allowed depending on the cipher
+ // being used. See RFC 5246 section 7.4.6 for more details.
+ // Additionally, according to msdn docs for PFXImportCertStore, the key specification is set to AT_KEYEXCHANGE
+ // when the data encipherment usage is set.
+ canDoKeyExchange = (keyUsageExtension.KeyUsages &
+ (X509KeyUsageFlags.KeyAgreement | X509KeyUsageFlags.KeyEncipherment |
+ X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DataEncipherment)) != X509KeyUsageFlags.None;
+ }
+
+ if (!canDoKeyExchange)
+ {
+ CspKeyContainerInfo info = GetKeyContainerInfo(certificate);
+ canDoKeyExchange = info != null && info.KeyNumber == KeyNumber.Exchange;
+ }
+
+ return canDoKeyExchange;
}
[Fx.Tag.SecurityNote(Critical = "Elevates to call properties: X509Certificate2.PrivateKey and CspKeyContainerInfo. Caller must protect the return value.")]
}
}
+ public static bool CanReadPrivateKey(X509Certificate2 certificate)
+ {
+ if (!certificate.HasPrivateKey)
+ return false;
+
+ try
+ {
+ // CNG key, CNG permissions tests
+ using (RSA rsa = CngLightup.GetRSAPrivateKey(certificate))
+ {
+ if (rsa != null)
+ {
+ return true;
+ }
+ }
+
+ using (DSA dsa = CngLightup.GetDSAPrivateKey(certificate))
+ {
+ if (dsa != null)
+ {
+ return true;
+ }
+ }
+
+ using (ECDsa ecdsa = CngLightup.GetECDsaPrivateKey(certificate))
+ {
+ if (ecdsa != null)
+ {
+ return true;
+ }
+ }
+
+ // CAPI key, CAPI permissions test
+ if (certificate.PrivateKey != null)
+ {
+ return true;
+ }
+
+ return false;
+ }
+ catch (CryptographicException)
+ {
+ return false;
+ }
+ }
+
static class NetworkCredentialHelper
{
[Fx.Tag.SecurityNote(Critical = "Uses unsafe critical methods UnsafeGetUsername, UnsafeGetPassword, and UnsafeGetDomain to access the credential details without a Demand.",
bool hasPrivateKey = false;
try
{
- hasPrivateKey = certificate != null && certificate.PrivateKey != null;
+ if (System.ServiceModel.LocalAppContextSwitches.DisableCngCertificates)
+ {
+ hasPrivateKey = certificate != null && certificate.PrivateKey != null;
+ }
+ else
+ {
+ hasPrivateKey = certificate.HasPrivateKey && SecurityUtils.CanReadPrivateKey(certificate);
+ }
}
catch (SecurityException e)
{
XmlDocument dom = new XmlDocument();
dom.PreserveWhitespace = true;
- dom.Load(stream);
+ dom.Load(new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Prohibit });
stream.Close();
return dom.DocumentElement;
writer.WriteEndElement();
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
- result = (XmlElement)doc.ReadNode(new XmlTextReader(stream));
+ result = (XmlElement)doc.ReadNode(new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Prohibit });
}
return result;
}
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
XmlNode skiNode;
- using (XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader(new XmlTextReader(stream)))
+ using (XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader(new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Prohibit }))
{
reader.MoveToContent();
skiNode = doc.ReadNode(reader);
throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID5004, ns));
}
- return XmlSchema.Read(new StringReader(xmlSchema), null);
+ StringReader reader = new StringReader(xmlSchema);
+ return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
}
/// <summary>
- //-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
{
ManagementExtension.OnServiceOpened(this);
}
+
+ // log telemetry data for the current WCF service.
+ TelemetryTraceLogging.LogSeriveKPIData(this.Description);
}
base.OnOpened();
internal const string HttpTransportPerFactoryConnectionPoolString = "wcf:httpTransportBinding:useUniqueConnectionPoolPerFactory";
internal const string EnsureUniquePerformanceCounterInstanceNamesString = "wcf:ensureUniquePerformanceCounterInstanceNames";
internal const string UseConfiguredTransportSecurityHeaderLayoutString = "wcf:useConfiguredTransportSecurityHeaderLayout";
+ internal const string UseBestMatchNamedPipeUriString = "wcf:useBestMatchNamedPipeUri";
const bool DefaultHttpTransportPerFactoryConnectionPool = false;
const bool DefaultEnsureUniquePerformanceCounterInstanceNames = false;
const bool DefaultUseConfiguredTransportSecurityHeaderLayout = false;
+ const bool DefaultUseBestMatchNamedPipeUri = false;
static bool httpTransportPerFactoryConnectionPool;
static bool ensureUniquePerformanceCounterInstanceNames;
static bool useConfiguredTransportSecurityHeaderLayout;
+ static bool useBestMatchNamedPipeUri;
static volatile bool settingsInitalized = false;
static object appSettingsLock = new object();
}
}
+ internal static bool UseBestMatchNamedPipeUri
+ {
+ get
+ {
+ EnsureSettingsLoaded();
+
+ return useBestMatchNamedPipeUri;
+ }
+ }
+
[SuppressMessage(FxCop.Category.ReliabilityBasic, "Reliability104:CaughtAndHandledExceptionsRule",
Justification = "Handle the configuration exceptions here to avoid regressions on customer's existing scenarios")]
static void EnsureSettingsLoaded()
useConfiguredTransportSecurityHeaderLayout = DefaultUseConfiguredTransportSecurityHeaderLayout;
}
+ if ((appSettingsSection == null) || !bool.TryParse(appSettingsSection[UseBestMatchNamedPipeUriString], out useBestMatchNamedPipeUri))
+ {
+ useBestMatchNamedPipeUri = DefaultUseBestMatchNamedPipeUri;
+ }
+
settingsInitalized = true;
}
}
namespace System
{
+ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
+ using System.Threading;
using System.Runtime.CompilerServices;
using System.Globalization;
const string NullableDefault = "null";
readonly WildcardInfo wildcard;
IDictionary<string, string> defaults;
- Dictionary<string, string> unescapedDefaults;
+ ConcurrentDictionary<string, string> unescapedDefaults;
VariablesCollection variables;
{
if (this.defaults == null)
{
- this.defaults = new UriTemplateDefaults(this);
+ Interlocked.CompareExchange<IDictionary<string, string>>(ref this.defaults, new UriTemplateDefaults(this), null);
}
return this.defaults;
}
}
if (this.unescapedDefaults == null)
{
- this.unescapedDefaults = new Dictionary<string, string>(StringComparer.Ordinal);
- }
- string unescapedValue;
- if (!this.unescapedDefaults.TryGetValue(escapedValue, out unescapedValue))
- {
- unescapedValue = Uri.UnescapeDataString(escapedValue);
- this.unescapedDefaults.Add(escapedValue, unescapedValue);
+ this.unescapedDefaults = new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
}
- return unescapedValue;
+ return this.unescapedDefaults.GetOrAdd(escapedValue, Uri.UnescapeDataString);
}
struct BindInformation
{
if (this.pathSegmentVariableNamesSnapshot == null)
{
- this.pathSegmentVariableNamesSnapshot = new ReadOnlyCollection<string>(
- this.pathSegmentVariableNames);
+ Interlocked.CompareExchange<ReadOnlyCollection<string>>(ref this.pathSegmentVariableNamesSnapshot, new ReadOnlyCollection<string>(
+ this.pathSegmentVariableNames), null);
}
return this.pathSegmentVariableNamesSnapshot;
}
{
if (this.queryValueVariableNamesSnapshot == null)
{
- this.queryValueVariableNamesSnapshot = new ReadOnlyCollection<string>(
- this.queryValueVariableNames);
+ Interlocked.CompareExchange<ReadOnlyCollection<string>>(ref this.queryValueVariableNamesSnapshot, new ReadOnlyCollection<string>(
+ this.queryValueVariableNames), null);
}
return this.queryValueVariableNamesSnapshot;
}
using System.Web.Resources;
using System.Web.UI;
using System.Web.UI.WebControls;
+ using System.Web.DynamicData.Util;
/// <summary>
/// Validator that enforces model validation. It can be used either at the field level or the entity level
}
if (!attrib.IsValid(value)) {
- ErrorMessage = HttpUtility.HtmlEncode(attrib.FormatErrorMessage(Column.DisplayName));
+ ErrorMessage = HttpUtility.HtmlEncode(StringLocalizerUtil.GetLocalizedString(attrib, Column.DisplayName));
return false;
}
}
validator.MaximumValue = converter(rangeAttribute.Maximum);
if (String.IsNullOrEmpty(validator.ErrorMessage)) {
- validator.ErrorMessage = HttpUtility.HtmlEncode(rangeAttribute.FormatErrorMessage(column.DisplayName));
+ validator.ErrorMessage = HttpUtility.HtmlEncode(
+ StringLocalizerUtil.GetLocalizedString(rangeAttribute, column.DisplayName));
}
}
validator.ValidationExpression = regexAttribute.Pattern;
if (String.IsNullOrEmpty(validator.ErrorMessage)) {
- validator.ErrorMessage = HttpUtility.HtmlEncode(regexAttribute.FormatErrorMessage(column.DisplayName));
+ validator.ErrorMessage = HttpUtility.HtmlEncode(
+ StringLocalizerUtil.GetLocalizedString(regexAttribute, column.DisplayName));
}
}
public string RequiredErrorMessage {
get {
var requiredAttribute = Metadata.RequiredAttribute;
- return requiredAttribute != null ? requiredAttribute.FormatErrorMessage(DisplayName) : String.Empty;
+ return requiredAttribute != null ?
+ StringLocalizerUtil.GetLocalizedString(requiredAttribute, DisplayName) : String.Empty;
}
}
public string Description {
get {
- return DisplayAttribute.GetPropertyValue(a => a.GetDescription(), null) ??
+ return DisplayAttribute.GetLocalizedDescription() ??
DescriptionAttribute.GetPropertyValue(a => a.Description, null);
}
}
public string DisplayName {
get {
- return DisplayAttribute.GetPropertyValue(a => a.GetName(), null) ??
+ return DisplayAttribute.GetLocalizedName() ??
DisplayNameAttribute.GetPropertyValue(a => a.DisplayName, null);
}
}
public string ShortDisplayName {
get {
- return DisplayAttribute.GetPropertyValue(a => a.GetShortName(), null);
+ return DisplayAttribute.GetLocalizedShortName();
}
}
public string Prompt {
get {
- return DisplayAttribute.GetPropertyValue(a => a.GetPrompt(), null);
+ return DisplayAttribute.GetLocalizedPrompt();
}
}
#endregion
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml.Schema;
using System.Xml.Serialization;
return mapFile is DataSvcMapFile ? ((DataSvcMapFile)mapFile).Impl : null;
}
+ [SuppressMessage("Microsoft.Security.Xml", "CA3060:UseXmlReaderForSchemaRead", Justification = "asp.net controls this .xsd file")]
protected override XmlSchemaSet GetMapFileSchemaSet()
{
if (_mapFileSchemaSet == null)
#if WEB_EXTENSIONS_CODE
using System.Web.Resources;
+using System.Diagnostics.CodeAnalysis;
#else
using Microsoft.VSDesigner.WCF.Resources;
#endif
/// </summary>
/// <param name="contentReader"></param>
/// <remarks></remarks>
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")]
private void LoadContentFromTextReader(TextReader contentReader)
{
if (contentReader == null)
/// </summary>
/// <return></return>
/// <remarks></remarks>
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")]
private MetadataContent LoadMetadataContent(MetadataType fileType)
{
if (ErrorInLoading != null)
#endregion
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Xml.Schema;
using System.Xml.Serialization;
return mapFile is SvcMapFile ? ((SvcMapFile)mapFile).Impl : null;
}
+ [SuppressMessage("Microsoft.Security.Xml", "CA3060:UseXmlReaderForSchemaRead", Justification = "asp.net controls this .xsd file")]
protected override XmlSchemaSet GetMapFileSchemaSet()
{
if (_mapFileSchemaSet == null)
// This member variable is set each time when calendar info needs to
// be accessed and be shared for other helper functions.
- private Globalization.Calendar _threadCalendar;
+ private System.Globalization.Calendar _threadCalendar;
private String _textBoxErrorMessage;
// This member variable is set each time when calendar info needs to
// be accessed and be shared for other helper functions.
- private Globalization.Calendar _threadCalendar;
+ private System.Globalization.Calendar _threadCalendar;
private String _textBoxErrorMessage;
// Event signals that ASP.NET has started processing a request.
// Overload used only for deducing ETW parameters; use the public entry point instead.
//
+ // Visual Studio Online #222067 - This event is hardcoded to opt-out of EventSource activityID tracking.
+ // This would normally be done by setting ActivityOptions = EventActivityOptions.Disable in the
+ // Event attribute, but this causes a dependency between System.Web and mscorlib that breaks servicing.
+ //
// !! WARNING !!
// The logic in RequestStartedImpl must be kept in [....] with these parameters, otherwise
// type safety violations could occur.
}
// Event signals that ASP.NET has completed processing a request.
+ //
+ // Visual Studio Online #222067 - This event is hardcoded to opt-out of EventSource activityID tracking.
+ // This would normally be done by setting ActivityOptions = EventActivityOptions.Disable in the
+ // Event attribute, but this causes a dependency between System.Web and mscorlib that breaks servicing.
[Event((int)Events.RequestCompleted, Level = EventLevel.Informational, Task = (EventTask)Tasks.Request, Opcode = EventOpcode.Stop, Version = 1)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RequestCompleted() {
return false;
}
- //
- // This method will return only the file dependencies from this dependency
- //
- internal virtual string[] GetFileDependencies()
+ /// <summary>
+ /// This method will return only the file dependencies from this dependency
+ /// </summary>
+ /// <returns></returns>
+ public virtual string[] GetFileDependencies()
{
#if USE_MEMORY_CACHE
if (CacheInternal.UseMemoryCache) {
return true;
}
-
- //
- // This method will return only the file dependencies from this dependency
- //
- internal override string[] GetFileDependencies()
+
+ /// <summary>
+ /// This method will return only the file dependencies from this dependency
+ /// </summary>
+ /// <returns></returns>
+ public override string[] GetFileDependencies()
{
ArrayList fileNames = null;
CacheDependency[] dependencies = null;
internal class SRef {
private static Type s_type = Type.GetType("System.SizedReference", true, false);
private Object _sizedRef;
+ private long _lastReportedSize; // This helps tremendously when looking at large dumps
internal SRef(Object target) {
_sizedRef = HttpRuntime.CreateNonPublicInstance(s_type, new object[] {target});
_sizedRef, // target
null, // args
CultureInfo.InvariantCulture);
- return (long) o;
+ return _lastReportedSize = (long) o;
}
}
internal Cache _cachePublic;
internal protected CacheMemoryStats _cacheMemoryStats;
private object _timerLock = new object();
- private Timer _timer;
+ private DisposableGCHandleRef<Timer> _timerHandleRef;
private int _currentPollInterval = MEMORYSTATUS_INTERVAL_30_SECONDS;
internal int _inCacheManagerThread;
internal bool _enableMemoryCollection;
internal bool _enableExpiration;
internal bool _internalConfigRead;
internal SRefMultiple _srefMultiple;
+ private int _disposed = 0;
internal CacheCommon() {
_cachePublic = new Cache(0);
internal void Dispose(bool disposing) {
if (disposing) {
- EnableCacheMemoryTimer(false);
- _cacheMemoryStats.Dispose();
+ // This method must be tolerant to multiple calls to Dispose on the same instance
+ if (Interlocked.Exchange(ref _disposed, 1) == 0) {
+ EnableCacheMemoryTimer(false);
+ _cacheMemoryStats.Dispose();
+ }
}
}
- internal void AddSRefTarget(CacheInternal c) {
- _srefMultiple.AddSRefTarget(c);
+ internal void AddSRefTarget(object o) {
+ _srefMultiple.AddSRefTarget(o);
}
internal void SetCacheInternal(CacheInternal cacheInternal) {
if (enable) {
- if (_timer == null) {
+ if (_timerHandleRef == null) {
// <cache privateBytesPollTime> has not been read yet
- _timer = new Timer(new TimerCallback(this.CacheManagerTimerCallback), null, _currentPollInterval, _currentPollInterval);
+ Timer timer = new Timer(new TimerCallback(this.CacheManagerTimerCallback), null, _currentPollInterval, _currentPollInterval);
+ _timerHandleRef = new DisposableGCHandleRef<Timer>(timer);
Debug.Trace("Cache", "Started CacheMemoryTimers");
}
else {
- _timer.Change(_currentPollInterval, _currentPollInterval);
+ _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval);
}
}
else {
- Timer timer = _timer;
- if (timer != null && Interlocked.CompareExchange(ref _timer, null, timer) == timer) {
- timer.Dispose();
+ var timerHandleRef = _timerHandleRef;
+ if (timerHandleRef != null && Interlocked.CompareExchange(ref _timerHandleRef, null, timerHandleRef) == timerHandleRef) {
+ timerHandleRef.Dispose();
Debug.Trace("Cache", "Stopped CacheMemoryTimers");
}
}
void AdjustTimer() {
lock (_timerLock) {
- if (_timer == null)
+ if (_timerHandleRef == null)
return;
// the order of these if statements is important
if (_cacheMemoryStats.IsAboveHighPressure()) {
if (_currentPollInterval > MEMORYSTATUS_INTERVAL_5_SECONDS) {
_currentPollInterval = MEMORYSTATUS_INTERVAL_5_SECONDS;
- _timer.Change(_currentPollInterval, _currentPollInterval);
+ _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval);
}
return;
}
int newPollInterval = Math.Min(CacheMemorySizePressure.PollInterval, MEMORYSTATUS_INTERVAL_30_SECONDS);
if (_currentPollInterval != newPollInterval) {
_currentPollInterval = newPollInterval;
- _timer.Change(_currentPollInterval, _currentPollInterval);
+ _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval);
}
return;
}
// there is no pressure, interval should be the value from config
if (_currentPollInterval != CacheMemorySizePressure.PollInterval) {
_currentPollInterval = CacheMemorySizePressure.PollInterval;
- _timer.Change(_currentPollInterval, _currentPollInterval);
+ _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval);
}
}
}
#endif
try {
// Dev10 633335: if the timer has been disposed, return without doing anything
- if (_timer == null)
+ if (_timerHandleRef == null)
return 0;
// The timer thread must always call Update so that the CacheManager
_usage = new CacheUsage(this);
_lock = new object();
_insertBlock = new ManualResetEvent(true);
- cacheCommon.AddSRefTarget(this);
+ cacheCommon.AddSRefTarget(new { _entries, _expires, _usage });
}
/*
class CacheMultiple : CacheInternal {
int _disposed;
- CacheSingle[] _caches;
+ DisposableGCHandleRef<CacheSingle>[] _cachesRefs;
int _cacheIndexMask;
internal CacheMultiple(CacheCommon cacheCommon, int numSingleCaches) : base(cacheCommon) {
Debug.Assert(numSingleCaches > 1, "numSingleCaches is not greater than 1");
Debug.Assert((numSingleCaches & (numSingleCaches - 1)) == 0, "numSingleCaches is not a power of 2");
_cacheIndexMask = numSingleCaches - 1;
- _caches = new CacheSingle[numSingleCaches];
+
+ // Each CacheSingle will have its own SRef reporting the size of the data it references.
+ // Objects in this CacheSingle may have refs to the root Cache and therefore reference other instances of CacheSingle.
+ // This leads to an unbalanced tree of SRefs and makes GC less efficient while calculating multiple SRefs on multiple cores.
+ // Using DisposableGCHandleRef here prevents SRefs from calculating data that does not belong to other CacheSingle instances.
+ _cachesRefs = new DisposableGCHandleRef<CacheSingle>[numSingleCaches];
for (int i = 0; i < numSingleCaches; i++) {
- _caches[i] = new CacheSingle(cacheCommon, this, i);
+ _cachesRefs[i] = new DisposableGCHandleRef<CacheSingle>(new CacheSingle(cacheCommon, this, i));
}
}
protected override void Dispose(bool disposing) {
if (disposing) {
if (Interlocked.Exchange(ref _disposed, 1) == 0) {
- foreach (CacheSingle cacheSingle in _caches) {
- cacheSingle.Dispose();
+ foreach (var cacheSingleRef in _cachesRefs) {
+ // Unfortunately the application shutdown logic allows user to access cache even after its disposal.
+ // We'll keep the GCHandle inside cacheSingleRef until it gets reclaimed during appdomain shutdown.
+ // And we'll only dispose the Target to preserve the old behavior.
+ cacheSingleRef.Target.Dispose();
}
}
}
internal override int PublicCount {
get {
int count = 0;
- foreach (CacheSingle cacheSingle in _caches) {
- count += cacheSingle.PublicCount;
+ foreach (var cacheSingleRef in _cachesRefs) {
+ count += cacheSingleRef.Target.PublicCount;
}
return count;
internal override long TotalCount {
get {
long count = 0;
- foreach (CacheSingle cacheSingle in _caches) {
- count += cacheSingle.TotalCount;
+ foreach (var cacheSingleRef in _cachesRefs) {
+ count += cacheSingleRef.Target.TotalCount;
}
return count;
}
internal override IDictionaryEnumerator CreateEnumerator() {
- IDictionaryEnumerator[] enumerators = new IDictionaryEnumerator[_caches.Length];
- for (int i = 0, c = _caches.Length; i < c; i++) {
- enumerators[i] = _caches[i].CreateEnumerator();
+ IDictionaryEnumerator[] enumerators = new IDictionaryEnumerator[_cachesRefs.Length];
+ for (int i = 0, c = _cachesRefs.Length; i < c; i++) {
+ enumerators[i] = _cachesRefs[i].Target.CreateEnumerator();
}
return new AggregateEnumerator(enumerators);
}
internal CacheSingle GetCacheSingle(int hashCode) {
- Debug.Assert(_caches != null && _caches.Length != 0);
+ Debug.Assert(_cachesRefs != null && _cachesRefs.Length != 0);
// Dev10 865907: Math.Abs throws OverflowException for Int32.MinValue
if (hashCode < 0) {
hashCode = (hashCode == Int32.MinValue) ? 0 : -hashCode;
}
int index = (hashCode & _cacheIndexMask);
- return _caches[index];
+ Debug.Assert(_cachesRefs[index].Target != null);
+ return _cachesRefs[index].Target;
}
internal override CacheEntry UpdateCache(
internal override long TrimIfNecessary(int percent) {
long count = 0;
- foreach (CacheSingle cacheSingle in _caches) {
- count += cacheSingle.TrimIfNecessary(percent);
+ foreach (var cacheSingleRef in _cachesRefs) {
+ count += cacheSingleRef.Target.TrimIfNecessary(percent);
}
return count;
}
internal override void EnableExpirationTimer(bool enable) {
- foreach (CacheSingle cacheSingle in _caches) {
- cacheSingle.EnableExpirationTimer(enable);
+ foreach (var cacheSingleRef in _cachesRefs) {
+ cacheSingleRef.Target.EnableExpirationTimer(enable);
}
}
}
}
[SuppressMessage("Microsoft.Security", "MSEC1207:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")]
private static bool ReadPrecompMarkerFile(string appRoot, out bool updatable) {
updatable = false;
}
[SuppressMessage("Microsoft.Security", "MSEC1207:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")]
private BuildResult ReadFileInternal(VirtualPath virtualPath, string preservationFile, long hashCode, bool ensureIsUpToDate) {
XmlDocument doc = new XmlDocument();
internal class XsdBuildProvider: BuildProvider {
[SuppressMessage("Microsoft.Security", "MSEC1207:UseXmlReaderForLoad", Justification = "Developer-controlled .xsd files in application directory are implicitly trusted by ASP.Net.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")]
public override void GenerateCode(AssemblyBuilder assemblyBuilder) {
#if !FEATURE_PAL // FEATURE_PAL does not support System.Data.Design
// Get the namespace that we will use
using Microsoft.Build.Utilities;
using Microsoft.CSharp;
+ using System.Diagnostics.CodeAnalysis;
[PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)]
[PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)]
return false;
}
+ [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")]
protected void ProcessBrowserFiles(bool useVirtualPath, string virtualDir) {
_browserTree = new BrowserTree();
_defaultTree = new BrowserTree();
ProcessCustomBrowserFiles(false, String.Empty);
}
+ [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")]
internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) {
//get all custom browser files and put them in the "tree"
DirectoryInfo browserDirInfo = null;
using System.Collections;
using System.Configuration;
+ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Security;
using System.Security.Permissions;
using System.Web.Configuration;
using System.Web.Util;
using System.Xml;
-
using Pair = System.Web.UI.Pair;
//
//
// ResolveFiles - parse files referenced with <file src="" />
//
+ [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")]
static void ResolveFiles(ParseState parseState, object configurationContext) {
//
using System.Security.AccessControl;
#endif // !FEATURE_PAL
using System.Security.Permissions;
+ using System.Diagnostics.CodeAnalysis;
#if !FEATURE_PAL // FEATURE_PAL does not enable COM
return sb.ToString();
}
+ [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml", Justification = "Developer-controlled xml contents are implicitly trusted by ASP.Net.")]
public string DoEncryptOrDecrypt(bool doEncrypt, string xmlString, string protectionProviderName, string protectionProviderType, string[] paramKeys, string[] paramValues)
{
Type t = Type.GetType(protectionProviderType, true);
namespace System.Web.Handlers {
using System;
+ using System.Threading.Tasks;
using System.Web.Hosting;
-
- internal class TransferRequestHandler : IHttpHandler {
-
- public void ProcessRequest(HttpContext context) {
+
+ internal class TransferRequestHandler : IHttpAsyncHandler {
+ public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
+ {
+ return TaskAsyncHelper.BeginTask(() => ProcessRequestAsync(context), cb, extraData);
+ }
+
+ public void EndProcessRequest(IAsyncResult result)
+ {
+ TaskAsyncHelper.EndTask(result);
+ }
+
+ private Task ProcessRequestAsync(HttpContext context) {
IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest;
if (wr == null) {
throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
context.Request.EntityBody,
null,
preserveUser: false);
-
+
// force the completion of the current request so that the
// child execution can be performed immediately after unwind
- context.ApplicationInstance.EnsureReleaseState();
+ var releaseStateTask = context.ApplicationInstance.EnsureReleaseStateAsync();
// DevDiv Bugs 162750: IIS7 Integrated Mode: TransferRequest performance issue
// Instead of calling Response.End we call HttpApplication.CompleteRequest()
- context.ApplicationInstance.CompleteRequest();
+ if (releaseStateTask.IsCompleted) {
+ context.ApplicationInstance.CompleteRequest();
+ return TaskAsyncHelper.CompletedTask;
+ }
+ else {
+ return releaseStateTask.ContinueWith((_) => context.ApplicationInstance.CompleteRequest());
+ }
+ }
+
+ public void ProcessRequest(HttpContext context)
+ {
+ string errorMessage = SR.GetString(SR.HttpTaskAsyncHandler_CannotExecuteSynchronously, GetType());
+ throw new NotSupportedException(errorMessage);
}
public bool IsReusable {
// delegate OnRespondToPing
private WaitCallback _onRespondToPingWaitCallback;
+ // flag indicates whether any fatal exception has been recorded
+ private bool _fatalExceptionRecorded = false;
+
// single instance of app manager
private static ApplicationManager _theAppManager;
}
}
+ private bool FatalExceptionRecorded
+ {
+ get {
+ return _fatalExceptionRecorded;
+ }
+ set {
+ _fatalExceptionRecorded = value;
+ }
+ }
+
internal static void RecordFatalException(Exception e) {
RecordFatalException(AppDomain.CurrentDomain, e);
}
}
}
- private static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs eventArgs) {
+ internal static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs eventArgs) {
// if the CLR is not terminating, ignore the notification
if (!eventArgs.IsTerminating) {
return;
return;
}
+ // If any fatal exception was recorded in applicaiton AppDomains,
+ // we wouldn't record exceptions in the default AppDomain.
+ var appManager = GetApplicationManager();
+ if (AppDomain.CurrentDomain.IsDefaultAppDomain() && appManager.FatalExceptionRecorded) {
+ return;
+ }
+
+ appManager.FatalExceptionRecorded = true;
+
RecordFatalException(appDomain, exception);
}
// start watching for app domain unloading
_onAppDomainUnload = new EventHandler(OnAppDomainUnload);
Thread.GetDomain().DomainUnload += _onAppDomainUnload;
+
+ // VSO 160528: We used to listen to the default AppDomain's UnhandledException only.
+ // However, non-serializable exceptions cannot be passed to the default domain. Therefore
+ // we should try to log exceptions in application AppDomains.
+ Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(ApplicationManager.OnUnhandledException);
}
internal long TrimCache(int percent) {
}
}
- // DevDiv Bugs 151914: Release session state before executing child request
- internal void EnsureReleaseState() {
+ private ISessionStateModule FindISessionStateModule() {
+ if (!HttpRuntime.UseIntegratedPipeline)
+ return null;
+
if (_moduleCollection != null) {
for (int i = 0; i < _moduleCollection.Count; i++) {
- IHttpModule module = _moduleCollection.Get(i);
- if (module is SessionStateModule) {
- ((SessionStateModule) module).EnsureReleaseState(this);
- break;
+ ISessionStateModule module = _moduleCollection.Get(i) as ISessionStateModule;
+ if (module != null) {
+ return module;
}
}
}
+
+ return null;
+ }
+
+ // DevDiv Bugs 151914: Release session state before executing child request
+ internal void EnsureReleaseState() {
+ ISessionStateModule module = FindISessionStateModule();
+ if (module != null) {
+ module.ReleaseSessionState(Context);
+ }
+ }
+
+ internal Task EnsureReleaseStateAsync() {
+ ISessionStateModule module = FindISessionStateModule();
+ if (module != null) {
+ return module.ReleaseSessionStateAsync(Context);
+ }
+
+ return TaskAsyncHelper.CompletedTask;
}
/// <devdoc>
_ignoreParams = -1;
}
- /*
- * Reset based on the cached vary headers.
- */
- internal void ResetFromParams(String[] parameters) {
+ /// <summary>
+ /// Set the Parameters in Cache Vary
+ /// </summary>
+ /// <param name="parameters"></param>
+ public void SetParams(string[] parameters) {
int i, n;
Reset();
return _ignoreParams == 1 || _paramsStar || _parameters != null;
}
- internal String[] GetParams() {
- String[] s = null;
+ /// <summary>
+ /// Get the Parameters in Cache Vary
+ /// </summary>
+ /// <returns></returns>
+ public string[] GetParams() {
+ string[] s = null;
Object item;
int i, j, c, n;
if (_ignoreParams == 1) {
- s = new String[1] {String.Empty};
+ s = new string[1] {string.Empty};
}
else if (_paramsStar) {
- s = new String[1] {"*"};
+ s = new string[1] {"*"};
}
else if (_parameters != null) {
n = _parameters.Size;
for (i = 0; i < n; i++) {
item = _parameters.GetValue(i);
if (item != null) {
- s[j] = (String) item;
+ s[j] = (string) item;
j++;
}
}
//
// Public methods and properties
- //
+ //
/// <devdoc>
//
// Public constants for cache-control
//
-
+
/// <devdoc>
/// <para>
int i, n;
string[] fields;
-
- _utcTimestampRequest = utcTimestampRequest;
-
- _varyByContentEncodings.ResetFromContentEncodings(settings.VaryByContentEncodings);
- _varyByHeaders.ResetFromHeaders(settings.VaryByHeaders);
- _varyByParams.ResetFromParams(settings.VaryByParams);
+
+ _varyByContentEncodings.SetContentEncodings(settings.VaryByContentEncodings);
+ _varyByHeaders.SetHeaders(settings.VaryByHeaders);
+ _varyByParams.SetParams(settings.VaryByParams);
_isModified = settings.IsModified;
_hasSetCookieHeader = settings.hasSetCookieHeader;
}
}
- internal bool IsModified() {
+ /// <summary>
+ /// Return true if the CachePolicy has been modified
+ /// </summary>
+ /// <returns></returns>
+ public bool IsModified() {
return _isModified || _varyByContentEncodings.IsModified() || _varyByHeaders.IsModified() || _varyByParams.IsModified();
}
return;
}
- Debug.Assert((_utcTimestampCreated == DateTime.MinValue && _utcTimestampRequest == DateTime.MinValue) ||
- (_utcTimestampCreated != DateTime.MinValue && _utcTimestampRequest != DateTime.MinValue),
- "_utcTimestampCreated and _utcTimestampRequest are out of [....] in UpdateCachedHeaders");
-
+ //To enable Out of Band OutputCache Module support, we will always refresh the UtcTimestampRequest.
if (_utcTimestampCreated == DateTime.MinValue) {
- _utcTimestampCreated = _utcTimestampRequest = response.Context.UtcTimestamp;
+ _utcTimestampCreated = response.Context.UtcTimestamp;
}
+ _utcTimestampRequest = response.Context.UtcTimestamp;
if (_slidingExpiration != 1) {
_slidingDelta = TimeSpan.Zero;
}
else if (_isMaxAgeSet) {
_slidingDelta = _maxAge;
- }
+ }
else if (_isExpiresSet) {
_slidingDelta = _utcExpires - _utcTimestampCreated;
}
}
sb.Append('\"');
- }
+ }
if (_noStore) {
AppendValueToHeader(sb, "no-store");
headers.Add(_headerVaryBy);
}
}
-
+
/*
- * Public methods
- */
+ * Public methods
+ */
internal HttpCachePolicySettings GetCurrentSettings(HttpResponse response) {
String[] varyByContentEncodings;
return absoluteExpiration;
}
+ // Expose this property to OutputCacheUtility class
+ // In order to enable Out of Band output cache module to access the Validation Callback Info
+ internal IEnumerable GetValidationCallbacks() {
+ if (_validationCallbackInfo == null) {
+ return new ArrayList();
+ }
+
+ return _validationCallbackInfo;
+ }
+
/*
* Cache at server?
*/
_noServerCaching = true;
}
- internal bool GetNoServerCaching() {
+ /// <summary>
+ /// Return True if we should stops all server caching for current response
+ /// </summary>
+ /// <returns></returns>
+ public bool GetNoServerCaching() {
return _noServerCaching;
}
_varyByCustom = custom;
}
+ /// <summary>
+ /// Get the Vary by Custom Value
+ /// </summary>
+ /// <returns></returns>
+ public string GetVaryByCustom() {
+ return _varyByCustom;
+ }
/*
* Cache-Control: extension
*/
}
}
+ /// <summary>
+ /// Get Cache Extensions Value
+ /// </summary>
+ /// <returns></returns>
+ public string GetCacheExtensions() {
+ return _cacheExtension;
+ }
+
/*
* Cache-Control: no-transform
*/
_noTransforms = true;
}
+ /// <summary>
+ /// Return true if No-transform directive, enables the sending of the CacheControl
+ /// </summary>
+ /// <returns></returns>
+ public bool GetNoTransforms() {
+ return _noTransforms;
+ }
+
internal void SetIgnoreRangeRequests() {
Dirtied();
_ignoreRangeRequests = true;
}
+ /// <summary>
+ /// Return true if ignore range request
+ /// </summary>
+ /// <returns></returns>
+ public bool GetIgnoreRangeRequests() {
+ return _ignoreRangeRequests;
+ }
+
/// <devdoc>
/// <para>Contains policy for the Vary: header.</para>
/// </devdoc>
}
}
- internal HttpCacheability GetCacheability() {
+ /// <summary>
+ /// Get the Cache-control (public, private and no-cache) directive
+ /// </summary>
+ /// <returns></returns>
+ public HttpCacheability GetCacheability() {
return _cacheability;
}
-
-
+
+
/// <devdoc>
/// <para>Sets the Cache-Control header to one of the values of HttpCacheability in
/// conjunction with a field-level exclusion directive.</para>
Dirtied();
_hasUserProvidedDependencies = hasUserProvidedDependencies;
}
+
+ /// <summary>
+ /// return true if no store is set
+ /// </summary>
+ /// <returns></returns>
+ public bool GetNoStore() {
+ return _noStore;
+ }
/*
* Expiration policy.
}
}
+ /// <summary>
+ /// Return the expire header as absolute expire datetime
+ /// </summary>
+ /// <returns></returns>
+ public DateTime GetExpires() {
+ return _utcExpires;
+ }
+
/*
* Cache-Control: max-age=delta-seconds
*/
}
}
+ /// <summary>
+ /// Get the Cache-Control Max Age
+ /// </summary>
+ /// <returns></returns>
+ public TimeSpan GetMaxAge() {
+ return _maxAge;
+ }
+
// Suppress max-age and s-maxage in cache-control header (required for IIS6 kernel mode cache)
internal void SetNoMaxAgeInCacheControl() {
_noMaxAgeInCacheControl = true;
}
}
+ /// <summary>
+ /// Get the Cache-Control: Proxy Max Age Value
+ /// </summary>
+ /// <returns></returns>
+ public TimeSpan GetProxyMaxAge() {
+ return _proxyMaxAge;
+ }
+
/*
* Sliding Expiration
*/
}
}
+ /// <summary>
+ /// Return true if to make expiration sliding. that is, if cached, it should be renewed with each
+ /// response. This feature is identical in spirit to the IIS
+ /// configuration option to add an expiration header relative to the current response
+ /// time. This feature is identical in spirit to the IIS configuration option to add
+ /// an expiration header relative to the current response time.
+ /// </summary>
+ /// <returns></returns>
+ public bool HasSlidingExpiration() {
+ return _slidingExpiration == 1;
+ }
public void SetValidUntilExpires(bool validUntilExpires) {
if (_validUntilExpires == -1 || _validUntilExpires == 1) {
}
}
+ /// <summary>
+ /// Return true if valid until expires
+ /// </summary>
+ /// <returns></returns>
+ public bool IsValidUntilExpires() {
+ return _validUntilExpires == 1;
+ }
public void SetAllowResponseInBrowserHistory(bool allow) {
if (_allowInHistory == -1 || _allowInHistory == 1) {
}
}
- /*
+ /// <summary>
+ /// Get the Cache-Control: header to reflect either the must-revalidate or
+ /// proxy-revalidate directives.
+ /// The default is to not send either of these directives unless explicitly enabled using this method.
+ /// </summary>
+ /// <returns></returns>
+ public HttpCacheRevalidation GetRevalidation() {
+ return _revalidation;
+ }
+
+ /*
* Etag
*/
_etag = etag;
}
+ /// <summary>
+ /// Get the ETag header. Once an ETag is set,
+ /// subsequent attempts to set it will fail and an exception will be thrown.
+ /// </summary>
+ /// <returns></returns>
+ public string GetETag() {
+ return _etag;
+ }
+
+
/*
* Last-Modified: RFC Date
*/
}
}
+ /// <summary>
+ /// Get the Last-Modified header.
+ /// </summary>
+ /// <returns></returns>
+ public DateTime GetUtcLastModified() {
+ return _utcLastModified;
+ }
+
/// <devdoc>
/// <para>Sets the Last-Modified: header based on the timestamps of the
_generateLastModifiedFromFiles = true;
}
+ /// <summary>
+ /// Return true if the Last-Modified header is set to base on the timestamps of the
+ /// file dependencies of the handler.
+ /// </summary>
+ /// <returns></returns>
+ public bool GetLastModifiedFromFileDependencies() {
+ return _generateLastModifiedFromFiles;
+ }
+
/// <devdoc>
/// <para>Sets the Etag header based on the timestamps of the file
_generateEtagFromFiles = true;
}
+ /// <summary>
+ /// Return true if the Etag header has been set to base on the timestamps of the file
+ /// dependencies of the handler
+ /// </summary>
+ /// <returns></returns>
+ public bool GetETagFromFileDependencies() {
+ return _generateEtagFromFiles;
+ }
public void SetOmitVaryStar(bool omit) {
Dirtied();
}
}
+ /// <summary>
+ /// Return true if to omit Vary Star
+ /// </summary>
+ /// <returns></returns>
+ public int GetOmitVaryStar() {
+ return _omitVaryStar;
+ }
/// <devdoc>
/// <para>Registers a validation callback for the current response.</para>
_validationCallbackInfo.Add(new ValidationCallbackInfo(handler, data));
}
+ /// <summary>
+ /// Utc Timestamp Created
+ /// </summary>
+ public DateTime UtcTimestampCreated {
+ get {
+ return _utcTimestampCreated;
+ }
+ set {
+ _utcTimestampCreated = value;
+ }
+ }
}
}
_headers = null;
}
- /*
- * Reset based on the cached vary headers.
- */
- internal void ResetFromHeaders(String[] headers) {
+ /// <summary>
+ /// Set the Headers in Cache Vary
+ /// </summary>
+ /// <param name="headers"></param>
+ public void SetHeaders(string[] headers) {
+
int i, n;
if (headers == null) {
_varyStar = false;
_headers = null;
}
- else {
+ else {
_isModified = true;
if (headers[0].Equals("*")) {
Debug.Assert(headers.Length == 1, "headers.Length == 1");
return null;
}
+
+ /// <summary>
+ /// Get the Headers in Cache Vary
+ /// </summary>
+ /// <returns></returns>
+ public string[] GetHeaders() {
+ string[] s = null;
- /*
- * Returns the headers, for package access only.
- *
- * @return the headers.
- */
- internal String[] GetHeaders() {
- String[] s = null;
Object item;
int i, j, c, n;
if (_varyStar) {
- return new String[1] {"*"};
+ return new string[1] {"*"};
}
else if (_headers != null) {
n = _headers.Size;
for (i = 0; i < n; i++) {
item = _headers.GetValue(i);
if (item != null) {
- s[j] = (String) item;
+ s[j] = (string) item;
j++;
}
}
return s;
}
-
+
//
// Public methods and properties
//
_isModified = false;
_contentEncodings = null;
}
+
+ /// <summary>
+ /// Set the Content Encodings in Cache Vary
+ /// </summary>
+ /// <param name="contentEncodings"></param>
+ public void SetContentEncodings(string[] contentEncodings) {
- /*
- * Reset based on content encodings.
- */
- internal void ResetFromContentEncodings(String[] contentEncodings) {
Reset();
if (contentEncodings != null) {
_isModified = true;
internal bool IsModified() {
return _isModified;
}
-
- internal String[] GetContentEncodings() {
- return _contentEncodings;
+
+ /// <summary>
+ /// Get the Content Encodings in Cache Vary
+ /// </summary>
+ /// <returns></returns>
+ public string[] GetContentEncodings() {
+ if (_contentEncodings != null) {
+ string[] contentEncodings = new string[_contentEncodings.Length];
+ _contentEncodings.CopyTo(contentEncodings, 0);
+ return contentEncodings;
+ }
+ return null;
}
//
using System.Linq;
using System.Net;
using System.Reflection;
+ using System.Runtime.CompilerServices;
using System.Runtime.Remoting.Messaging;
using System.Security.Permissions;
using System.Security.Principal;
if (_delayedSessionState) {
lock (this) {
if (_delayedSessionState) {
+ Debug.Assert(_sessionStateModule != null, "_sessionStateModule != null");
+
// If it's not null, it means we have a delayed session state item
_sessionStateModule.InitStateStoreItem(true);
_delayedSessionState = false;
}
}
+ [MethodImpl(MethodImplOptions.NoInlining)]
internal void EnsureSessionStateIfNecessary() {
- Debug.Assert(_sessionStateModule != null, "_sessionStateModule != null");
+ if (_sessionStateModule == null)
+ {
+ // If _sessionStateModule is null, we wouldn't be able to call
+ // _sessionStateModule.EnsureStateStoreItemLocked(), so we return here.
+ // _sessionStateModule could be null in the following cases,
+ // 1. No session state acquired.
+ // 2. HttpResponse.Flush() happens after session state being released.
+ // 3. The session state module in use is not System.Web.SessionState.SessionStateModule.
+ //
+ // This method is for the in-framework SessionStateModule only.
+ // OOB SessionStateModule can achieve this by using HttpResponse.AddOnSendingHeaders.
+ return;
+ }
HttpSessionState session = (HttpSessionState)Items[SessionStateUtility.SESSION_KEY];
}
internal void RemoveHttpSessionStateModule() {
- Debug.Assert(_sessionStateModule != null, "_sessionStateModule != null");
_delayedSessionState = false;
_sessionStateModule = null;
}
}
// restore content
- _httpWriter.UseSnapshot(rawResponse.Buffers);
+ SetResponseBuffers(rawResponse.Buffers);
+
+ _suppressContent = !sendBody;
+ }
+
+ // set the response content bufffers
+ internal void SetResponseBuffers(ArrayList buffers) {
+ if (_httpWriter == null) {
+ throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_for_TextWriter));
+ }
- _suppressContent = !sendBody;
+ _httpWriter.UseSnapshot(buffers);
}
internal void CloseConnectionAfterError() {
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
+ using System.Web.Globalization;
public class DataAnnotationsModelMetadataProvider : AssociatedMetadataProvider {
List<Attribute> attributeList = new List<Attribute>(attributes);
DisplayColumnAttribute displayColumnAttribute = attributeList.OfType<DisplayColumnAttribute>().FirstOrDefault();
DataAnnotationsModelMetadata result = new DataAnnotationsModelMetadata(this, containerType, modelAccessor, modelType, propertyName, displayColumnAttribute);
-
+
#if UNDEF
// Do [HiddenInput] before [UIHint], so you can override the template hint
HiddenInputAttribute hiddenInputAttribute = attributeList.OfType<HiddenInputAttribute>().FirstOrDefault();
DisplayAttribute display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
string name = null;
if (display != null) {
- result.Description = display.GetDescription();
- result.ShortDisplayName = display.GetShortName();
- result.Watermark = display.GetPrompt();
- result.Order = display.GetOrder() ?? ModelMetadata.DefaultOrder;
+ var displayAdapter = new DisplayAttributeAdapter(display);
+ result.Description = displayAdapter.GetDescription();
+ result.ShortDisplayName = displayAdapter.GetShortName();
+ result.Watermark = displayAdapter.GetPrompt();
+ result.Order = displayAdapter.GetOrder() ?? ModelMetadata.DefaultOrder;
- name = display.GetName();
+ name = displayAdapter.GetName();
}
if (name != null) {
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
+ using System.Threading;
+ using System.Web.Globalization;
- public class DataAnnotationsModelValidator : ModelValidator {
+ public class DataAnnotationsModelValidator : ModelValidator {
public DataAnnotationsModelValidator(ModelMetadata metadata, ModelBindingExecutionContext context, ValidationAttribute attribute)
: base(metadata, context) {
protected internal string ErrorMessage {
get {
- return Attribute.FormatErrorMessage(Metadata.GetDisplayName());
+ if (UseStringLocalizerProvider) {
+ var errorMsg = GetLocalizedString(Attribute.ErrorMessage);
+
+ return errorMsg ?? Attribute.FormatErrorMessage(Metadata.GetDisplayName());
+ }
+ else {
+ return Attribute.FormatErrorMessage(Metadata.GetDisplayName());
+ }
+ }
+ }
+
+ protected string GetLocalizedString(string name, params object[] arguments) {
+ if (StringLocalizerProviders.DataAnnotationStringLocalizerProvider != null) {
+ return StringLocalizerProviders.DataAnnotationStringLocalizerProvider
+ .GetLocalizedString(Thread.CurrentThread.CurrentUICulture, name, arguments);
+ }
+ else {
+ return null;
}
}
ValidationResult result = Attribute.GetValidationResult(Metadata.Model, context);
if (result != ValidationResult.Success) {
yield return new ModelValidationResult {
- Message = result.ErrorMessage
+ Message = GetValidationErrorMessage(result)
};
}
}
+
+ protected virtual string GetLocalizedErrorMessage(string errorMessage) {
+ return GetLocalizedString(errorMessage, Metadata.GetDisplayName());
+ }
+
+ private string GetValidationErrorMessage(ValidationResult result) {
+ string errorMsg;
+
+ if (UseStringLocalizerProvider) {
+ errorMsg = GetLocalizedErrorMessage(Attribute.ErrorMessage);
+
+ errorMsg = errorMsg ?? result.ErrorMessage;
+ }
+ else {
+ errorMsg = result.ErrorMessage;
+ }
+ return errorMsg;
+ }
+
+ private bool UseStringLocalizerProvider {
+ get {
+ // if developer already uses existing localization feature,
+ // then we don't opt in the new localization feature.
+ return (!string.IsNullOrEmpty(Attribute.ErrorMessage) &&
+ string.IsNullOrEmpty(Attribute.ErrorMessageResourceName) &&
+ Attribute.ErrorMessageResourceType == null);
+ }
+ }
}
}
namespace System.Web.ModelBinding {
- using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading;
+using System.Web.Globalization;
// A factory for validators based on ValidationAttribute
public delegate ModelValidator DataAnnotationsModelValidationFactory(ModelMetadata metadata, ModelBindingExecutionContext context, ValidationAttribute attribute);
public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider {
private static bool _addImplicitRequiredAttributeForValueTypes = true;
private static ReaderWriterLockSlim _adaptersLock = new ReaderWriterLockSlim();
-
+
// Factories for validation attributes
internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory =
typeof(StringLengthAttribute),
(metadata, context, attribute) => new StringLengthAttributeAdapter(metadata, context, (StringLengthAttribute)attribute)
},
+ {
+ typeof(MinLengthAttribute),
+ (metadata, context, attribute) => new MinLengthAttributeAdapter(metadata, context, (MinLengthAttribute)attribute)
+ },
+ {
+ typeof(MaxLengthAttribute),
+ (metadata, context, attribute) => new MaxLengthAttributeAdapter(metadata, context, (MaxLengthAttribute)attribute)
+ },
};
// Factories for IValidatableObject models
_addImplicitRequiredAttributeForValueTypes = value;
}
}
-
+
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ModelBindingExecutionContext context, IEnumerable<Attribute> attributes) {
_adaptersLock.EnterReadLock();
: base(metadata, context, attribute) {
}
+ protected override string GetLocalizedErrorMessage(string errorMessage) {
+ return GetLocalizedString(errorMessage, Metadata.GetDisplayName(), Attribute.Minimum, Attribute.Maximum);
+
+ }
+
#if UNDEF
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
string errorMessage = ErrorMessage; // Per Dev10 Bug #923283, need to make sure ErrorMessage is called before Minimum/Maximum
: base(metadata, context, attribute) {
}
+ protected override string GetLocalizedErrorMessage(string errorMessage) {
+ return GetLocalizedString(errorMessage, Metadata.GetDisplayName(), Attribute.Pattern);
+ }
+
#if UNDEF
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
return new[] { new ModelClientValidationRegexRule(ErrorMessage, Attribute.Pattern) };
: base(metadata, context, attribute) {
}
+ protected override string GetLocalizedErrorMessage(string errorMessage) {
+ return GetLocalizedString(errorMessage, Metadata.GetDisplayName(), Attribute.MinimumLength, Attribute.MaximumLength);
+ }
+
#if UNDEF
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
return new[] { new ModelClientValidationStringLengthRule(ErrorMessage, Attribute.MinimumLength, Attribute.MaximumLength) };
return new DESCryptoServiceProvider();
}
+ [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:SHA1CannotBeUsed", Justification = @"This is only used by legacy code; new features do not use this algorithm.")]
internal static HMACSHA1 CreateHMACSHA1() {
return new HMACSHA1();
}
using System.Security;
using System.Security.Claims;
using System.Security.Permissions;
+ using System.Security.Principal;
/// <devdoc>
/// This class is an IIdentity derived class
/// Constructor.
/// </devdoc>
protected FormsIdentity(FormsIdentity identity)
- : base(identity)
+ : base((IIdentity)identity)
{
_Ticket = identity._Ticket;
}
using System.Globalization;
using System.Security.Permissions;
using System.Text;
+ using System.Threading.Tasks;
using System.Web.Hosting;
using System.Web.Management;
using Microsoft.Win32;
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
- public sealed class SessionStateModule : IHttpModule {
+ public sealed class SessionStateModule : ISessionStateModule {
internal const string SQL_CONNECTION_STRING_DEFAULT = "data source=localhost;Integrated Security=SSPI";
internal const string STATE_CONNECTION_STRING_DEFAULT = "tcpip=loopback:42424";
}
}
}
-
- // DevDiv Bugs 151914: Release session state before executing child request
- internal void EnsureReleaseState(HttpApplication app) {
+
+ public void ReleaseSessionState(HttpContext context) {
if (HttpRuntime.UseIntegratedPipeline && _acquireCalled && !_releaseCalled) {
try {
- OnReleaseState(app, null);
+ OnReleaseState(context.ApplicationInstance, null);
}
catch { }
}
}
+
+ public Task ReleaseSessionStateAsync(HttpContext context) {
+ ReleaseSessionState(context);
+ return TaskAsyncHelper.CompletedTask;
+ }
}
}
return context.Application.SessionStaticObjects.Clone();
}
+ /// <summary>
+ /// Gets a value that indicates whether session state is required by the context.
+ /// </summary>
+ /// <param name="context">The HttpContext.</param>
+ /// <returns>A value that indicates whether session state is required by the context.</returns>
+ static public bool IsSessionStateRequired(HttpContext context) {
+ return context.RequiresSessionState;
+ }
+
+ /// <summary>
+ /// Gets a value that indicates whether session state is read-only in the context.
+ /// </summary>
+ /// <param name="context">The HttpContext.</param>
+ /// <returns>A value that indicates whether session state is read-only in the context.</returns>
+ static public bool IsSessionStateReadOnly(HttpContext context) {
+ return context.ReadOnlySessionState;
+ }
+
internal static SessionStateStoreData CreateLegitStoreData(HttpContext context,
ISessionStateItemCollection sessionItems,
HttpStaticObjectsCollection staticObjects,
internal static class TaskAsyncHelper {
+ private static readonly Task s_completedTask = Task.FromResult<object>(null);
+
internal static IAsyncResult BeginTask(Func<Task> taskFunc, AsyncCallback callback, object state) {
Task task = taskFunc();
if (task == null) {
taskWrapper.Task.GetAwaiter().GetResult();
}
+ internal static Task CompletedTask {
+ get {
+ return s_completedTask;
+ }
+ }
}
}
namespace System.Web.UI {
-using System;
-using System.IO;
-using System.Text;
-using System.Collections;
-using System.Collections.Specialized;
-using System.ComponentModel;
-using System.ComponentModel.Design;
-using System.Globalization;
-using System.Web;
-using System.Web.Util;
-using System.Web.UI.HtmlControls;
-using System.Web.UI.WebControls;
-using System.Web.Caching;
-using System.Web.Compilation;
-using System.Web.Configuration;
-using System.Security.Permissions;
-
-
-// Keeps track of one call to Page Register* API
-// The semantics of the fields depends to the call type
-[Serializable]
+ using System;
+ using System.IO;
+ using System.Text;
+ using System.Collections;
+ using System.Collections.Specialized;
+ using System.ComponentModel;
+ using System.ComponentModel.Design;
+ using System.Globalization;
+ using System.Web;
+ using System.Web.Util;
+ using System.Web.UI.HtmlControls;
+ using System.Web.UI.WebControls;
+ using System.Web.Caching;
+ using System.Web.Compilation;
+ using System.Web.Configuration;
+ using System.Security.Permissions;
+
+
+ // Keeps track of one call to Page Register* API
+ // The semantics of the fields depends to the call type
+ [Serializable]
internal class RegisterCallData {
internal ClientAPIRegisterType Type;
internal ScriptKey Key;
}
else {
string[] varyByParams = null;
- if (_varyByParamsCollection != null)
- varyByParams = _varyByParamsCollection.GetParams();
+ if (_varyByParamsCollection != null)
+ varyByParams = _varyByParamsCollection.GetParams();
cachedVary = new ControlCachedVary(varyByParams, _varyByControlsCollection, _varyByCustom);
string[] varyByParamsStrings = varyByParams.Split(varySeparator);
_varyByParamsCollection = new HttpCacheVaryByParams();
- _varyByParamsCollection.ResetFromParams(varyByParamsStrings);
+ _varyByParamsCollection.SetParams(varyByParamsStrings);
}
internal void RegisterPostBackScript() {
private ArrayList dateList;
private SelectedDatesCollection selectedDates;
- private Globalization.Calendar threadCalendar;
+ private System.Globalization.Calendar threadCalendar;
private DateTime minSupportedDate;
private DateTime maxSupportedDate;
#if DEBUG
}
ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
- MemberExpression property = Expression.Property(parameter, sortExpression);
+ //VSO bug 173528-- Add support for sorting by nested property names
+ MemberExpression property = null;
+ string[] sortExpressionFields = sortExpression.Split('.');
+ foreach (string sortExpressionField in sortExpressionFields) {
+ if (property == null) {
+ property = Expression.Property(parameter, sortExpressionField);
+ }
+ else {
+ property = Expression.Property(property, sortExpressionField);
+ }
+ }
LambdaExpression lambda = Expression.Lambda(property, parameter);
string methodName = (isDescending) ? "OrderByDescending" : "OrderBy" ;
[SuppressMessage("Microsoft.Security", "MSEC1220:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3069:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")]
public override void SetTagInnerText(string text) {
if (!Util.IsWhiteSpaceString(text)) {
#pragma warning restore 0618
[SuppressMessage("Microsoft.Security", "MSEC1201:DoNotUseXslTransform", Justification = "_identityTransform contents are trusted hard-coded string.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3050:DoNotUseXslTransform", Justification = "_identityTransform contents are trusted hard-coded string.")]
[SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "_identityTransform contents are trusted hard-coded string.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "_identityTransform contents are trusted hard-coded string.")]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
static Xml() {
[SuppressMessage("Microsoft.Security", "MSEC1218:ReviewWebControlForSet_DocumentContent", Justification = "Legacy code that trusts our developer input. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3067:ReviewWebControlForSet_DocumentContent", Justification = "Legacy code that trusts our developer input. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
protected override void AddParsedSubObject(object obj) {
if (obj is LiteralControl) {
// Trim the initial whitespaces since XML is very picky (related to ASURT 58100)
}
}
+
+ // This wrapper around a managed object is opaque to SizedReference GC handle
+ // and therefore helps with calculating size of only relevant graph of objects
+ internal class DisposableGCHandleRef<T> : IDisposable
+ where T : class, IDisposable {
+ GCHandle _handle;
+ [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
+ public DisposableGCHandleRef(T t) {
+ Debug.Assert(t != null);
+ _handle = GCHandle.Alloc(t);
+ }
+
+ public T Target {
+ [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
+ get {
+ Debug.Assert(_handle.IsAllocated);
+ return (T)_handle.Target;
+ }
+ }
+
+ [PermissionSet(SecurityAction.Assert, Unrestricted = true)]
+ public void Dispose() {
+ Target.Dispose();
+ Debug.Assert(_handle.IsAllocated);
+ if (_handle.IsAllocated) {
+ _handle.Free();
+ }
+ }
+ }
}
using System.Globalization;
using System.Runtime.InteropServices;
using System.Web.Hosting;
+using System.Diagnostics.CodeAnalysis;
/*
* Various string handling utilities
// Instead use the default AppDomain, because it doesn't have string hash randomization enabled.
// Marshal the call to reuse the default StringComparer behavior.
// PERF isn't optimal, so apply consideration!
+ [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control the callers.")]
internal static int GetNonRandomizedStringComparerHashCode(string s) {
// Preserve the default behavior when string hash randomization is off
if (!AppSettings.UseRandomizedStringHashAlgorithm) {
// This method only schedules work; it doesn't itself do any work. The lock is held for a very
// short period of time.
lock (_lockObj) {
- Task newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action));
+ Task newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action), TaskScheduler.Default);
_lastScheduledTask = newTask; // the newly-created task is now the last one
}
}
public static readonly long MaxEntityExpansion = 1024 * 1024;
[SuppressMessage("Microsoft.Security", "MSEC1208:DoNotUseLoadXml", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
public static XmlDocument CreateXmlDocumentFromContent(string content)
{
XmlDocument doc = new XmlDocument();
}
[SuppressMessage("Microsoft.Security", "MSEC1210:UseXmlReaderForXPathDocument", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3059:UseXmlReaderForXPathDocument", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
public static XPathDocument CreateXPathDocumentFromContent(string content)
{
StringReader reader = new StringReader(content);
}
[SuppressMessage("Microsoft.Security", "MSEC1220:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3069:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")]
public static XmlReaderSettings CreateXmlReaderSettings()
{
XmlReaderSettings settings = new XmlReaderSettings();
// try to guess at how to set matching defaults with XmlReader.Create().
// (E.g. DtdProcessing is Parse by default using XmlTextReader directly. It's Prohibit in default XmlReaderSettings.)
[SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
[SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
public static XmlReader CreateXmlReader(string filepath)
{
if (AppSettings.RestrictXmlControls)
}
[SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
[SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
public static XmlReader CreateXmlReader(Stream datastream)
{
if (AppSettings.RestrictXmlControls)
}
[SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
[SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
public static XmlReader CreateXmlReader(TextReader reader)
{
if (AppSettings.RestrictXmlControls)
}
[SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
[SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")]
public static XmlReader CreateXmlReader(Stream contentStream, string baseURI)
{
if (AppSettings.RestrictXmlControls)
#pragma warning disable 0618 // To avoid deprecation warning
[SuppressMessage("Microsoft.Security", "MSEC1201:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3050:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
public static XslTransform CreateXslTransform(XmlReader reader)
{
if (!AppSettings.RestrictXmlControls)
}
[SuppressMessage("Microsoft.Security", "MSEC1201:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3050:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")]
public static XslTransform CreateXslTransform(XmlReader reader, XmlResolver resolver)
{
if (!AppSettings.RestrictXmlControls)
[SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")]
+ [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")]
public override SiteMapNode BuildSiteMap() {
SiteMapNode tempNode = _siteMapNode;
using System.Diagnostics;
using System.Globalization;
using System.IO;
+ using System.Xml;
using System.Text;
using System.Collections;
using System.Collections.Specialized;
string name = null;
try
{
- Xml.XmlTextReader reader = new Xml.XmlTextReader(binaryStream);
+ Xml.XmlTextReader reader = new Xml.XmlTextReader(binaryStream) { DtdProcessing = DtdProcessing.Prohibit };
if (reader.MoveToContent() == System.Xml.XmlNodeType.Element)
{
if (reader.MoveToAttribute("Class", StandardXomlKeys.Definitions_XmlNs))
{
ArrayList objects = new ArrayList();
WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(serializationManager);
- XmlTextReader reader = new XmlTextReader(this.serializedXmlString, XmlNodeType.Element, null);
+ XmlTextReader reader = new XmlTextReader(this.serializedXmlString, XmlNodeType.Element, null) { DtdProcessing = DtdProcessing.Prohibit };
reader.MoveToElement();
do
{
xomlSerializationManager.AddSerializationProvider(propertySegmentSerializationProvider);
StringReader stringReader = new StringReader(this.serializedXmlString);
- using (XmlTextReader reader = new XmlTextReader(stringReader))
+ using (XmlTextReader reader = new XmlTextReader(stringReader) { DtdProcessing = DtdProcessing.Prohibit })
{
while (reader.NodeType != XmlNodeType.Element && reader.NodeType != XmlNodeType.ProcessingInstruction && reader.Read());
return HashServiceType(serviceType.AssemblyQualifiedName);
}
- [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5350:MD5CannotBeUsed",
+ [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5350:MD5CannotBeUsed",
Justification = "Design has been approved. We are not using MD5 for any security or cryptography purposes but rather as a hash.")]
internal static Guid HashServiceType(String serviceFullTypeName)
{
- MD5 md5 = new MD5CryptoServiceProvider();
byte[] data;
byte[] result;
UnicodeEncoding ue = new UnicodeEncoding();
data = ue.GetBytes(serviceFullTypeName);
- result = md5.ComputeHash(data);
+ if (AppSettings.FIPSRequired)
+ {
+ result = MD5PInvokeHelper.CalculateHash(data);
+ }
+ else
+ {
+ MD5 md5 = new MD5CryptoServiceProvider();
+ result = md5.ComputeHash(data);
+ }
return new Guid(result);
}
{
public TrackingProfileSerializer()
{
- _schema = XmlSchema.Read(new StringReader(_xsd), null);
+ StringReader reader = new StringReader(_xsd);
+ _schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null);
_schema.Namespaces.Add("", _ns);
}
// listen to activity definition resolve events
Activity.ActivityResolve += OnActivityDefinitionResolve;
Activity.WorkflowChangeActionsResolve += OnWorkflowChangeActionsResolve;
+
+ try
+ {
+ using (TelemetryEventSource eventSource = new TelemetryEventSource())
+ {
+ eventSource.V1Runtime();
+ }
+ }
+ catch
+ {
+ }
}
public WorkflowRuntime()
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
+
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
using System;
using System.Collections.Generic;
static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
}
}
+
+#pragma warning restore 436
//
// ==--==
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
// NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches
using System;
using System.Collections.Generic;
}
}
}
+
+#pragma warning restore 436
LocalAppContext.DefineSwitchDefault("Switch.System.Xml.DontThrowOnInvalidSurrogatePairs", true);
LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreEmptyKeySequences", true);
}
+ if (version <= 40601)
+ {
+ LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreKindInUtcTimeSerialization", true);
+ }
break;
}
case "WindowsPhone":
{
LocalAppContext.DefineSwitchDefault("Switch.System.Xml.DontThrowOnInvalidSurrogatePairs", true);
LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreEmptyKeySequences", true);
+ LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreKindInUtcTimeSerialization", true);
}
break;
}
return LocalAppContext.GetCachedSwitchValue(@"Switch.System.Xml.IgnoreEmptyKeySequences", ref _ignoreEmptyKeySequences);
}
}
+
+ private static int _ignoreKindInUtcTimeSerialization;
+ public static bool IgnoreKindInUtcTimeSerialization
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(@"Switch.System.Xml.IgnoreKindInUtcTimeSerialization", ref _ignoreKindInUtcTimeSerialization);
+ }
+ }
}
}
}
internal static string FromTime(DateTime value) {
- return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffzzzzzz");
+ if (!LocalAppContextSwitches.IgnoreKindInUtcTimeSerialization && value.Kind == DateTimeKind.Utc)
+ {
+ return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffZ");
+ }
+ else
+ {
+ return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffzzzzzz");
+ }
}
internal static string FromDateTime(DateTime value) {
}
internal static DateTime ToTime(string value) {
- return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite|DateTimeStyles.AllowTrailingWhite|DateTimeStyles.NoCurrentDateDefault);
+ if (!LocalAppContextSwitches.IgnoreKindInUtcTimeSerialization)
+ {
+ return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.RoundtripKind);
+ }
+ else
+ {
+ return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.NoCurrentDateDefault);
+ }
}
internal static char ToChar(string value) {
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
+
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
using System;
using System.Collections.Generic;
static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
}
}
+
+#pragma warning restore 436
//
// ==--==
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
// NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches
using System;
using System.Collections.Generic;
}
}
}
+
+#pragma warning restore 436
if (PinnableBufferCacheEventSource.Log.IsEnabled())
PinnableBufferCacheEventSource.Log.FreeBuffer(m_CacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), m_FreeList.Count);
-
+ if(buffer == null)
+ {
+ if (PinnableBufferCacheEventSource.Log.IsEnabled())
+ PinnableBufferCacheEventSource.Log.FreeBufferNull(m_CacheName, m_FreeList.Count);
+
+ return;
+ }
+
// After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path.
if ((m_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1))
{
public void AllocateBufferAged(string cacheName, int agedCount) {}
public void AllocateBufferFreeListEmpty(string cacheName, int notGen2CountBefore) {}
public void FreeBuffer(string cacheName, ulong objectId, int objectHash, int freeCountBefore) {}
+ public void FreeBufferNull(string cacheName, int freeCountBefore) { }
public void FreeBufferStillTooYoung(string cacheName, int notGen2CountBefore) {}
public void TrimCheck(string cacheName, int totalBuffs, bool neededMoreThanFreeList, int deltaMSec) {}
public void TrimFree(string cacheName, int totalBuffs, int freeListCount, int toBeFreed) {}
public void AgePendingBuffersResults(string cacheName, int promotedToFreeListCount, int heldBackCount) { if (IsEnabled()) WriteEvent(20, cacheName, promotedToFreeListCount, heldBackCount); }
[Event(21)]
public void WalkFreeListResult(string cacheName, int freeListCount, int gen0BuffersInFreeList) { if (IsEnabled()) WriteEvent(21, cacheName, freeListCount, gen0BuffersInFreeList); }
+ [Event(22)]
+ public void FreeBufferNull(string cacheName, int freeCountBefore) { if(IsEnabled()) WriteEvent(22, cacheName, freeCountBefore); }
static internal ulong AddressOf(object obj)
[ResourceExposure(ResourceScope.None)]
public static extern bool WTSUnRegisterSessionNotification(HandleRef hWnd);
+ private static IntPtr GetCurrentProcessToken() { return new IntPtr(-4); }
+
+ private const int ERROR_SUCCESS = 0;
+
+ enum AppPolicyClrCompat
+ {
+ AppPolicyClrCompat_Others = 0,
+ AppPolicyClrCompat_ClassicDesktop = 1,
+ AppPolicyClrCompat_Universal = 2,
+ AppPolicyClrCompat_PackagedDesktop = 3
+ };
+
+ [DllImport(ExternDll.Kernel32, CharSet = CharSet.None, EntryPoint = "AppPolicyGetClrCompat")]
+ [System.Security.SecuritySafeCritical]
+ [return: MarshalAs(UnmanagedType.I4)]
+ private static extern Int32 _AppPolicyGetClrCompat(IntPtr processToken, out AppPolicyClrCompat appPolicyClrCompat);
+
private const int ERROR_INSUFFICIENT_BUFFER = 0x007A;
private const int ERROR_NO_PACKAGE_IDENTITY = 0x3d54;
[System.Security.SecuritySafeCritical]
private static bool _IsPackagedProcess()
{
+ Version windows8Version = new Version(6, 2, 0, 0);
OperatingSystem os = Environment.OSVersion;
- if(os.Platform == PlatformID.Win32NT && os.Version >= new Version(6,2,0,0) && DoesWin32MethodExist(ExternDll.Kernel32, "GetCurrentPackageId"))
+ bool osSupportsPackagedProcesses = os.Platform == PlatformID.Win32NT && os.Version >= windows8Version;
+
+ if (osSupportsPackagedProcesses && DoesWin32MethodExist(ExternDll.Kernel32, "AppPolicyGetClrCompat"))
+ {
+ // Use AppPolicyGetClrCompat if it is available. Return true if and only if this is a UWA which means if
+ // this is packaged desktop app this method will return false. This may cause some confusion however
+ // this is necessary to make the behavior of packaged desktop apps identical to desktop apps.
+ AppPolicyClrCompat appPolicyClrCompat;
+ return _AppPolicyGetClrCompat(GetCurrentProcessToken(), out appPolicyClrCompat) == ERROR_SUCCESS &&
+ appPolicyClrCompat == AppPolicyClrCompat.AppPolicyClrCompat_Universal;
+ }
+ else if(osSupportsPackagedProcesses && DoesWin32MethodExist(ExternDll.Kernel32, "GetCurrentPackageId"))
{
Int32 bufLen = 0;
// Will return ERROR_INSUFFICIENT_BUFFER when running within a packaged application,
return false;
}
- if ((mdObj.description == null) != (description == null) ||
- (description != null && !mdObj.category.Equals(description))) {
- return false;
+ // VSO 149471 - Technically fixing this could cause a behavior change, so we are
+ // adding a quirk in case anyone is bit by this and needs the old, buggy behavior.
+ if (!LocalAppContextSwitches.MemberDescriptorEqualsReturnsFalseIfEquivalent) {
+ if ((mdObj.description == null) != (description == null) ||
+ (description != null && !mdObj.description.Equals(description))) {
+ return false;
+ }
+ }
+ else {
+ if ((mdObj.description == null) != (description == null) ||
+ (description != null && !mdObj.category.Equals(description))) {
+ return false;
+ }
}
if ((mdObj.attributes == null) != (attributes == null)) {
}
}
+ // Note: RequestBuffer may get moved in memory. If you dereference a pointer from inside the RequestBuffer,
+ // you must use 'OriginalBlobAddress' below to adjust the location of the pointer to match the location of
+ // RequestBuffer.
internal byte[] RequestBuffer
{
get
m_TokenBindings = new List<TokenBinding>();
- UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO* pTokenBindingInfo = GetTlsTokenBindingRequestInfo();
+ UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO* pTokenBindingInfo = UnsafeNclNativeMethods.HttpApi.GetTlsTokenBindingRequestInfo(RequestBuffer, OriginalBlobAddress);
if (pTokenBindingInfo == null)
{
}
}
- private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO* GetTlsTokenBindingRequestInfo() {
- fixed (byte* pMemoryBlob = RequestBuffer)
- {
- UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2* request = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)pMemoryBlob;
-
- for (int i = 0; i < request->RequestInfoCount; i++)
- {
- UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* pThisInfo = &request->pRequestInfo[i];
- if (pThisInfo != null && pThisInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslTokenBinding)
- {
- return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO*)pThisInfo->pInfo;
- }
- }
- }
- return null;
- }
-
internal void CheckDisposed() {
if (m_IsDisposed) {
throw new ObjectDisposedException(this.GetType().FullName);
ValidateManual = 0x08,
NoDefaultCred = 0x10,
ValidateAuto = 0x20,
+ SendAuxRecord = 0x00200000,
UseStrongCrypto = 0x00400000,
}
KeyExchangeStrength));
}
}
+ catch (Exception)
+ {
+ // If an exception emerges synchronously, the asynchronous operation was not
+ // initiated, so no operation is in progress.
+ _NestedAuth = 0;
+
+ throw;
+ }
finally
{
- if (lazyResult == null || _Exception != null)
+ if (lazyResult == null)
{
_NestedAuth = 0;
}
private static volatile CertPolicyValidationCallback s_CertPolicyValidationCallback = new CertPolicyValidationCallback();
private static volatile ServerCertValidationCallback s_ServerCertValidationCallback = null;
+ private const string sendAuxRecordValueName = "SchSendAuxRecord";
+ private const string sendAuxRecordAppSetting = "System.Net.ServicePointManager.SchSendAuxRecord";
private const string strongCryptoValueName = "SchUseStrongCrypto";
private const string secureProtocolAppSetting = "System.Net.ServicePointManager.SecurityProtocol";
- private static object disableStrongCryptoLock = new object();
- private static volatile bool disableStrongCryptoInitialized = false;
+ private static object configurationLoadedLock = new object();
+ private static volatile bool configurationLoaded = false;
private static bool disableStrongCrypto = false;
+ private static bool disableSendAuxRecord = false;
private static SecurityProtocolType s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
[SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety")]
public static SecurityProtocolType SecurityProtocol {
get {
- EnsureStrongCryptoSettingsInitialized();
+ EnsureConfigurationLoaded();
return s_SecurityProtocolType;
}
set {
- EnsureStrongCryptoSettingsInitialized();
+ EnsureConfigurationLoaded();
ValidateSecurityProtocol(value);
s_SecurityProtocolType = value;
}
internal static bool DisableStrongCrypto {
get {
- EnsureStrongCryptoSettingsInitialized();
- return (bool)disableStrongCrypto;
+ EnsureConfigurationLoaded();
+ return disableStrongCrypto;
}
}
- private static void EnsureStrongCryptoSettingsInitialized() {
-
- if (disableStrongCryptoInitialized) {
+ internal static bool DisableSendAuxRecord {
+ get {
+ EnsureConfigurationLoaded();
+ return disableSendAuxRecord;
+ }
+ }
+
+ private static void EnsureConfigurationLoaded() {
+ if (configurationLoaded) {
return;
}
- lock (disableStrongCryptoLock) {
- if (disableStrongCryptoInitialized) {
+ lock (configurationLoadedLock) {
+ if (configurationLoaded) {
return;
}
- try {
- bool disableStrongCryptoInternal = false;
- int schUseStrongCryptoKeyValue = 0;
+ LoadDisableStrongCryptoConfiguration();
+ LoadDisableSendAuxRecordConfiguration();
- if (LocalAppContextSwitches.DontEnableSchUseStrongCrypto)
- {
- //.Net 4.5.2 and below will default to false unless the registry key is specifically set to 1.
- schUseStrongCryptoKeyValue =
- RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 0);
+ configurationLoaded = true;
+ }
+ }
- disableStrongCryptoInternal = schUseStrongCryptoKeyValue != 1;
- }
- else
- {
- // .Net 4.6 and above will default to true unless the registry key is specifically set to 0.
- schUseStrongCryptoKeyValue =
- RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 1);
+ private static void LoadDisableStrongCryptoConfiguration() {
+ try {
+ bool disableStrongCryptoInternal = false;
+ int schUseStrongCryptoKeyValue = 0;
- disableStrongCryptoInternal = schUseStrongCryptoKeyValue == 0;
- }
-
- if (disableStrongCryptoInternal) {
- // Revert the SecurityProtocol selection to the legacy combination.
- s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
- }
- else {
- s_SecurityProtocolType =
- SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
+ if (LocalAppContextSwitches.DontEnableSchUseStrongCrypto) {
+ //.Net 4.5.2 and below will default to false unless the registry key is specifically set to 1.
+ schUseStrongCryptoKeyValue =
+ RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 0);
- string appSetting = RegistryConfiguration.AppConfigReadString(secureProtocolAppSetting, null);
+ disableStrongCryptoInternal = schUseStrongCryptoKeyValue != 1;
+ }
+ else {
+ // .Net 4.6 and above will default to true unless the registry key is specifically set to 0.
+ schUseStrongCryptoKeyValue =
+ RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 1);
- SecurityProtocolType value;
- try {
- value = (SecurityProtocolType)Enum.Parse(typeof(SecurityProtocolType), appSetting);
- ValidateSecurityProtocol(value);
- s_SecurityProtocolType = value;
- }
- // Ignore all potential exceptions caused by Enum.Parse.
- catch (ArgumentNullException) { }
- catch (ArgumentException) { }
- catch (NotSupportedException) { }
- catch (OverflowException) { }
- }
+ disableStrongCryptoInternal = schUseStrongCryptoKeyValue == 0;
+ }
- disableStrongCrypto = disableStrongCryptoInternal;
- disableStrongCryptoInitialized = true;
+ if (disableStrongCryptoInternal) {
+ // Revert the SecurityProtocol selection to the legacy combination.
+ s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
}
- catch (Exception e) {
- if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
- throw;
+ else {
+ s_SecurityProtocolType =
+ SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
+
+ string appSetting = RegistryConfiguration.AppConfigReadString(secureProtocolAppSetting, null);
+
+ SecurityProtocolType value;
+ try {
+ value = (SecurityProtocolType)Enum.Parse(typeof(SecurityProtocolType), appSetting);
+ ValidateSecurityProtocol(value);
+ s_SecurityProtocolType = value;
}
+ // Ignore all potential exceptions caused by Enum.Parse.
+ catch (ArgumentNullException) { }
+ catch (ArgumentException) { }
+ catch (NotSupportedException) { }
+ catch (OverflowException) { }
+ }
+
+ disableStrongCrypto = disableStrongCryptoInternal;
+ }
+ catch (Exception e)
+ {
+ if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
+ {
+ throw;
}
}
}
-
+
+ private static void LoadDisableSendAuxRecordConfiguration() {
+ try {
+ if (LocalAppContextSwitches.DontEnableSchSendAuxRecord) {
+ disableSendAuxRecord = true;
+ return;
+ }
+
+ int schSendAuxRecordKeyValue = 1;
+ schSendAuxRecordKeyValue = RegistryConfiguration.AppConfigReadInt(sendAuxRecordAppSetting, 1);
+ if (schSendAuxRecordKeyValue == 0) {
+ disableSendAuxRecord = true;
+ return;
+ }
+
+ schSendAuxRecordKeyValue = RegistryConfiguration.GlobalConfigReadInt(sendAuxRecordValueName, 1);
+ if (schSendAuxRecordKeyValue == 0) {
+ disableSendAuxRecord = true;
+ return;
+ }
+ }
+ catch (Exception e)
+ {
+ if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException)
+ {
+ throw;
+ }
+ }
+ }
+
public static bool ReusePort {
get {
EnsureReusePortSettingsInitialized();
[Out] out int bytesTransferred,
[In] SafeHandle overlapped,
[In] IntPtr completionRoutine
- );
+ );
[DllImport(WS2_32,SetLastError=true)]
internal static extern SocketError WSAEnumNetworkEvents(
GlobalLog.Leave("HttpApi::GetLocalEndPoint()");
return endpoint;
}
+
+ internal static HTTP_REQUEST_TOKEN_BINDING_INFO* GetTlsTokenBindingRequestInfo(byte[] memoryBlob, IntPtr originalAddress){
+
+ fixed (byte* pMemoryBlob = memoryBlob)
+ {
+ HTTP_REQUEST_V2* request = (HTTP_REQUEST_V2*)pMemoryBlob;
+ long fixup = pMemoryBlob - (byte*) originalAddress;
+
+ for (int i = 0; i < request->RequestInfoCount; i++)
+ {
+ HTTP_REQUEST_INFO* pThisInfo = (HTTP_REQUEST_INFO*)(fixup + (byte*)&request->pRequestInfo[i]);
+ if (pThisInfo != null && pThisInfo->InfoType == HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslTokenBinding)
+ {
+ return (HTTP_REQUEST_TOKEN_BINDING_INFO*)pThisInfo->pInfo;
+ }
+ }
+ }
+ return null;
+ }
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static void CopyOutAddress(IntPtr address, ref SocketAddress v4address, ref SocketAddress v6address)
if (store != null)
{
collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false);
- if (collectionEx.Count > 0 && collectionEx[0].PrivateKey != null)
+ if (collectionEx.Count > 0 && collectionEx[0].HasPrivateKey)
{
if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_found_cert_in_store, (m_ServerMode ? "LocalMachine" : "CurrentUser")));
return collectionEx[0];
if (store != null)
{
collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false);
- if (collectionEx.Count > 0 && collectionEx[0].PrivateKey != null)
+ if (collectionEx.Count > 0 && collectionEx[0].HasPrivateKey)
{
if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_found_cert_in_store, (m_ServerMode ? "CurrentUser" : "LocalMachine")));
return collectionEx[0];
else
{
SecureCredential.Flags flags = SecureCredential.Flags.ValidateManual | SecureCredential.Flags.NoDefaultCred;
+
+ if (!ServicePointManager.DisableSendAuxRecord)
+ {
+ flags |= SecureCredential.Flags.SendAuxRecord;
+ }
+
if (!ServicePointManager.DisableStrongCrypto
&& ((m_ProtocolFlags & (SchProtocols.Tls10 | SchProtocols.Tls11 | SchProtocols.Tls12)) != 0)
&& (m_EncryptionPolicy != EncryptionPolicy.AllowNoEncryption) && (m_EncryptionPolicy != EncryptionPolicy.NoEncryption))
}
else
{
- SecureCredential secureCredential = new SecureCredential(SecureCredential.CurrentVersion, selectedCert, SecureCredential.Flags.Zero, m_ProtocolFlags, m_EncryptionPolicy);
+ SecureCredential.Flags flags = SecureCredential.Flags.Zero;
+
+ if (!ServicePointManager.DisableSendAuxRecord)
+ {
+ flags |= SecureCredential.Flags.SendAuxRecord;
+ }
+
+ SecureCredential secureCredential = new SecureCredential(SecureCredential.CurrentVersion, selectedCert, flags, m_ProtocolFlags, m_EncryptionPolicy);
m_CredentialsHandle = AcquireCredentialsHandle(CredentialUse.Inbound, ref secureCredential);
thumbPrint = guessedThumbPrint;
m_ServerCertificate = localCertificate;
if (start==end)
return false;
-#if MONO
- if (!Uri.IsWindowsFileSystem) {
- if (!(end - start > 2 && name[start] == '\\' && name[start + 1] == '\\')) {
- return false;
- }
- }
-#endif
//
// First segment could consist of only '_' or '-' but it cannot be all digits or empty
//
}
else {
if (oldName != null) {
- Debug.Assert(false, "FileSystemWatcher: FILE_ACTION_RENAMED_OLD_NAME with no" +
- "new name! [" + oldName + "]");
-
NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName);
oldName = null;
}
{
LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DontEnableSchUseStrongCryptoName, true);
}
+
+ if (version <= 40601)
+ {
+ LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.MemberDescriptorEqualsReturnsFalseIfEquivalentName, true);
+ }
break;
}
case "WindowsPhone":
{
if (version <= 80100)
{
- LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DontEnableSchUseStrongCryptoName, true);
+ LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DontEnableSchUseStrongCryptoName, true);
}
break;
}
internal static class LocalAppContextSwitches
{
-#region System.Net quirks
+ #region System quirks
+ private static int _memberDescriptorEqualsReturnsFalseIfEquivalent;
+ internal const string MemberDescriptorEqualsReturnsFalseIfEquivalentName = @"Switch.System.MemberDescriptorEqualsReturnsFalseIfEquivalent";
+
+ public static bool MemberDescriptorEqualsReturnsFalseIfEquivalent
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(MemberDescriptorEqualsReturnsFalseIfEquivalentName, ref _memberDescriptorEqualsReturnsFalseIfEquivalent);
+ }
+ }
+ #endregion
+
+ #region System.Net quirks
private static int _dontEnableSchUseStrongCrypto;
internal const string DontEnableSchUseStrongCryptoName = @"Switch.System.Net.DontEnableSchUseStrongCrypto";
return LocalAppContext.GetCachedSwitchValue(DontEnableSchUseStrongCryptoName, ref _dontEnableSchUseStrongCrypto);
}
}
-#endregion
-#region System.Net.WebSockets.HttpListenerAsyncEventArgs
private static int _allocateOverlappedOnDemand;
internal const string AllocateOverlappedOnDemandName = @"Switch.System.Net.WebSockets.HttpListenerAsyncEventArgs.AllocateOverlappedOnDemand";
return LocalAppContext.GetCachedSwitchValue(AllocateOverlappedOnDemandName, ref _allocateOverlappedOnDemand);
}
}
-#endregion
+ private static int _dontEnableSchSendAuxRecord;
+ internal const string DontEnableSchSendAuxRecordName = @"Switch.System.Net.DontEnableSchSendAuxRecord";
+
+ public static bool DontEnableSchSendAuxRecord
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return LocalAppContext.GetCachedSwitchValue(DontEnableSchSendAuxRecordName, ref _dontEnableSchSendAuxRecord);
+ }
+ }
+ #endregion
}
}
}
else
{
- AppDomain.Unload(inProcessAppDomain);
- inProcessAppDomain = null;
+ if (inProcessAppDomain != null)
+ {
+ AppDomain.Unload(inProcessAppDomain);
+ inProcessAppDomain = null;
+ }
return GetAppDomainAndExecute();
}
}
appDomainSetup.ApplicationBase = buildTaskPath;
appDomainSetup.LoaderOptimization = LoaderOptimization.MultiDomainHost;
+ // Set the AppDomainManager class name and assembly name to the empty string. We don't want the AppDomain to try to load the
+ // Microsoft.VisualStudio.Platform.AppDomainManager.dll because it is no longer in the GAC, so it won't be found
+ // by the AppDomain that is created for the in-process build to support Intellisense in Visual Studio.
+ appDomainSetup.AppDomainManagerType = "";
+ appDomainSetup.AppDomainManagerAssembly = "";
+
// Create appdomain with fulltrust.
return AppDomain.CreateDomain(
friendlyName,
if (PinnableBufferCacheEventSource.Log.IsEnabled())
PinnableBufferCacheEventSource.Log.FreeBuffer(m_CacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), m_FreeList.Count);
-
+ if(buffer == null)
+ {
+ if (PinnableBufferCacheEventSource.Log.IsEnabled())
+ PinnableBufferCacheEventSource.Log.FreeBufferNull(m_CacheName, m_FreeList.Count);
+
+ return;
+ }
+
// After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path.
if ((m_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1))
{
public void AllocateBufferAged(string cacheName, int agedCount) {}
public void AllocateBufferFreeListEmpty(string cacheName, int notGen2CountBefore) {}
public void FreeBuffer(string cacheName, ulong objectId, int objectHash, int freeCountBefore) {}
+ public void FreeBufferNull(string cacheName, int freeCountBefore) { }
public void FreeBufferStillTooYoung(string cacheName, int notGen2CountBefore) {}
public void TrimCheck(string cacheName, int totalBuffs, bool neededMoreThanFreeList, int deltaMSec) {}
public void TrimFree(string cacheName, int totalBuffs, int freeListCount, int toBeFreed) {}
public void AgePendingBuffersResults(string cacheName, int promotedToFreeListCount, int heldBackCount) { if (IsEnabled()) WriteEvent(20, cacheName, promotedToFreeListCount, heldBackCount); }
[Event(21)]
public void WalkFreeListResult(string cacheName, int freeListCount, int gen0BuffersInFreeList) { if (IsEnabled()) WriteEvent(21, cacheName, freeListCount, gen0BuffersInFreeList); }
+ [Event(22)]
+ public void FreeBufferNull(string cacheName, int freeCountBefore) { if(IsEnabled()) WriteEvent(22, cacheName, freeCountBefore); }
static internal ulong AddressOf(object obj)
[ResourceExposure(ResourceScope.Machine)]
internal unsafe static extern int GetFullPathName(char* path, int numBufferChars, char* buffer, IntPtr mustBeZero);
+ [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
+ [ResourceExposure(ResourceScope.Machine)]
+ internal unsafe static extern uint GetFullPathNameW(char* path, uint numBufferChars, SafeHandle buffer, IntPtr mustBeZero);
+
[DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
[ResourceExposure(ResourceScope.Machine)]
internal unsafe static extern int GetFullPathName(String path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero);
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GetLongPathName(String path, [Out]StringBuilder longPathBuffer, int bufferLength);
+ [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
+ [ResourceExposure(ResourceScope.Machine)]
+ internal static extern uint GetLongPathNameW(SafeHandle lpszShortPath, SafeHandle lpszLongPath, uint cchBuffer);
+
+ [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
+ [ResourceExposure(ResourceScope.Machine)]
+ internal static extern uint GetLongPathNameW(string lpszShortPath, SafeHandle lpszLongPath, uint cchBuffer);
+
// Disallow access to all non-file devices from methods that take
// a String. This disallows DOS devices like "con:", "com1:",
// "lpt1:", etc. Use this to avoid security problems, like allowing
int nBufferLength,
[Out]StringBuilder lpBuffer);
+ [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)]
+ [ResourceExposure(ResourceScope.Machine)]
+ internal static extern uint GetCurrentDirectoryW(uint nBufferLength, SafeHandle lpBuffer);
+
[DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)]
[ResourceExposure(ResourceScope.None)]
internal static extern bool GetFileAttributesEx(String name, int fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
HasLookedForOverride = 0x4,
UnknownValue = 0x8 // Has no default and could not find an override
}
- private static Dictionary<string, SwitchValueState> s_switchMap = new Dictionary<string, SwitchValueState>();
- private static readonly object s_syncLock = new object();
+ private static readonly Dictionary<string, SwitchValueState> s_switchMap = new Dictionary<string, SwitchValueState>();
public static string BaseDirectory
{
if (switchName.Length == 0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "switchName");
- lock (s_syncLock)
+ SwitchValueState switchValue = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
+ | SwitchValueState.HasLookedForOverride;
+ lock (s_switchMap)
{
// Store the new value and the fact that we checked in the dictionary
- s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue)
- | SwitchValueState.HasLookedForOverride;
+ s_switchMap[switchName] = switchValue;
}
}
-// ==++==
+// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
internal static readonly string SwitchNoAsyncCurrentCulture = "Switch.System.Globalization.NoAsyncCurrentCulture";
internal static readonly string SwitchThrowExceptionIfDisposedCancellationTokenSource = "Switch.System.Threading.ThrowExceptionIfDisposedCancellationTokenSource";
internal static readonly string SwitchPreserveEventListnerObjectIdentity = "Switch.System.Diagnostics.EventSource.PreserveEventListnerObjectIdentity";
+ internal static readonly string SwitchUseLegacyPathHandling = "Switch.System.IO.UseLegacyPathHandling";
+ internal static readonly string SwitchBlockLongPaths = "Switch.System.IO.BlockLongPaths";
+ internal static readonly string SwitchSetActorAsReferenceWhenCopyingClaimsIdentity = "Switch.System.Security.ClaimsIdentity.SetActorAsReferenceWhenCopyingClaimsIdentity";
+
-
// This is a partial method. Platforms can provide an implementation of it that will set override values
// from whatever mechanism is available on that platform. If no implementation is provided, the compiler is going to remove the calls
// to it from the code
AppContext.DefineSwitchDefault(SwitchNoAsyncCurrentCulture, true);
AppContext.DefineSwitchDefault(SwitchThrowExceptionIfDisposedCancellationTokenSource, true);
}
+
+ if (version <= 40601)
+ {
+ AppContext.DefineSwitchDefault(SwitchUseLegacyPathHandling, true);
+ AppContext.DefineSwitchDefault(SwitchBlockLongPaths, true);
+ AppContext.DefineSwitchDefault(SwitchSetActorAsReferenceWhenCopyingClaimsIdentity, true);
+ }
+
break;
}
case "WindowsPhone":
{
AppContext.DefineSwitchDefault(SwitchNoAsyncCurrentCulture, true);
AppContext.DefineSwitchDefault(SwitchThrowExceptionIfDisposedCancellationTokenSource, true);
+ AppContext.DefineSwitchDefault(SwitchUseLegacyPathHandling, true);
+ AppContext.DefineSwitchDefault(SwitchBlockLongPaths, true);
}
break;
}
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
+
+// There are cases where we have multiple assemblies that are going to import this file and
+// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
+// that the type is found both in the source and in a referenced assembly. The compiler will prefer
+// the version of the type defined in the source
+//
+// In order to disable the warning for this type we are disabling this warning for this entire file.
+#pragma warning disable 436
+
using System;
using System.Collections.Generic;
static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
}
}
+
+#pragma warning restore 436
}
}
+ private static int _useLegacyPathHandling;
+
+ /// <summary>
+ /// Use legacy path normalization logic and blocking of extended syntax.
+ /// </summary>
+ public static bool UseLegacyPathHandling
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return GetCachedSwitchValue(AppContextDefaultValues.SwitchUseLegacyPathHandling, ref _useLegacyPathHandling);
+ }
+ }
+
+ private static int _blockLongPaths;
+
+ /// <summary>
+ /// Throw PathTooLongException for paths greater than MAX_PATH or directories greater than 248 (as per CreateDirectory Win32 limitations)
+ /// </summary>
+ public static bool BlockLongPaths
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return GetCachedSwitchValue(AppContextDefaultValues.SwitchBlockLongPaths, ref _blockLongPaths);
+ }
+ }
+
+ private static int _cloneActor;
+
+ /// <summary>
+ /// When copying a ClaimsIdentity.Actor this switch controls whether ClaimsIdentity.Actor should be set as a reference or the result of Actor.Clone()
+ /// </summary>
+ public static bool SetActorAsReferenceWhenCopyingClaimsIdentity
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return GetCachedSwitchValue(AppContextDefaultValues.SwitchSetActorAsReferenceWhenCopyingClaimsIdentity, ref _cloneActor);
+ }
+ }
+
//
// Implementation details
//
}
}
- [ResourceExposure(ResourceScope.Machine)]
- [ResourceConsumption(ResourceScope.Machine)]
- private String NormalizePath(String path, bool useAppBase)
+ [System.Security.SecuritySafeCritical]
+ private string NormalizePath(string path, bool useAppBase)
{
if(path == null)
return null;
// If we add very long file name support ("\\?\") to the Path class then this is unnecesary,
// but we do not plan on doing this for now.
+
+ // Long path checks can be quirked, and as loading default quirks too early in the setup of an AppDomain is risky
+ // we'll avoid checking path lengths- we'll still fail at MAX_PATH later if we're !useAppBase when we call Path's
+ // NormalizePath.
if (!useAppBase)
- path = System.Security.Util.URLString.PreProcessForExtendedPathRemoval(path, false);
+ path = System.Security.Util.URLString.PreProcessForExtendedPathRemoval(
+ checkPathLength: false,
+ url: path,
+ isFileUrl: false);
int len = path.Length;
if (len == 0)
if (localPath)
{
-
if (useAppBase &&
- ( (len == 1) || (path[1] != ':') )) {
- String appBase = Value[(int) LoaderInformation.ApplicationBaseValue];
+ ((len == 1) || (path[1] != ':')))
+ {
+ String appBase = Value[(int)LoaderInformation.ApplicationBaseValue];
if ((appBase == null) || (appBase.Length == 0))
throw new MemberAccessException(Environment.GetResourceString("AppDomain_AppBaseNotSet"));
bool slash = false;
if ((path[0] == '/') || (path[0] == '\\')) {
- String pathRoot = Path.GetPathRoot(appBase);
+ // Emulate Path.GetPathRoot without hitting code paths that check quirks
+ string pathRoot = AppDomain.NormalizePath(appBase, fullCheck: false);
+ pathRoot = pathRoot.Substring(0, System.IO.PathInternal.GetRootLength(pathRoot));
if (pathRoot.Length == 0) { // URL
int index = appBase.IndexOf(":/", StringComparison.Ordinal);
if (index == -1)
int urlLen = appBase.Length;
for (index += 1;
(index < urlLen) && ((appBase[index] == '/') || (appBase[index] == '\\'));
- index++);
+ index++) ;
// Now find the next slash to get domain name
- for(; (index < urlLen) && (appBase[index] != '/') && (appBase[index] != '\\');
- index++);
+ for (; (index < urlLen) && (appBase[index] != '/') && (appBase[index] != '\\');
+ index++) ;
pathRoot = appBase.Substring(0, index);
}
path = StringBuilderCache.GetStringAndRelease(result);
}
else
- path = Path.GetFullPathInternal(path);
+ {
+ path = AppDomain.NormalizePath(path, fullCheck: true);
+ }
}
return path;
[ResourceConsumption(ResourceScope.Machine)]
private String VerifyDir(String dir, bool normalize)
{
- if (dir != null) {
+ if (dir != null)
+ {
if (dir.Length == 0)
+ {
dir = null;
- else {
+ }
+ else
+ {
if (normalize)
dir = NormalizePath(dir, true);
- // The only way AppDomainSetup is exposed in coreclr is through the AppDomainManager
- // and the AppDomainManager is a SecurityCritical type. Also, all callers of callstacks
- // leading from VerifyDir are SecurityCritical. So we can remove the Demand because
- // we have validated that all callers are SecurityCritical
+ // The only way AppDomainSetup is exposed in coreclr is through the AppDomainManager
+ // and the AppDomainManager is a SecurityCritical type. Also, all callers of callstacks
+ // leading from VerifyDir are SecurityCritical. So we can remove the Demand because
+ // we have validated that all callers are SecurityCritical
#if !FEATURE_CORECLR
if (IsFilePath(dir))
- new FileIOPermission( FileIOPermissionAccess.PathDiscovery, dir ).Demand();
+ {
+ // If we've already normalized we don't need to do it again, and can avoid hitting
+ // quirks in FileIOPermission.
+ new FileIOPermission(
+ access: FileIOPermissionAccess.PathDiscovery,
+ pathList: new string[] { dir },
+ checkForDuplicates: false,
+ needFullPath: false).Demand();
+ }
#endif // !FEATURE_CORECLR
}
}
get {
String dyndir = GetDynamicDir();
if (dyndir != null)
- new FileIOPermission( FileIOPermissionAccess.PathDiscovery, dyndir ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, dyndir);
return dyndir;
}
AppDomainInitializerInfo initializerInfo = (AppDomainInitializerInfo)args[5];
string sandboxName = (string)args[6];
string[] propertyNames = (string[])args[7]; // can contain null elements
- string[] propertyValues = (string[])args[8]; // can contain null elements
+ string[] propertyValues = (string[])args[8]; // can contain null elements
// extract evidence
Evidence providedSecurityInfo = null;
Evidence creatorsSecurityInfo = null;
if (Path.IsRelative(propertyValues[i]))
throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) );
- newSetup.ApplicationBase=Path.NormalizePath(propertyValues[i],true);
-
+ newSetup.ApplicationBase = NormalizePath(propertyValues[i], fullCheck: true);
}
#if FEATURE_CAS_POLICY
else if(propertyNames[i]=="LOCATION_URI" && providedSecurityInfo==null)
{
providedSecurityInfo=new Evidence();
providedSecurityInfo.AddHostEvidence(new Url(propertyValues[i]));
- ad.SetDataHelper(propertyNames[i],propertyValues[i],null);
+ ad.SetDataHelper(propertyNames[i],propertyValues[i],null);
}
#endif // FEATURE_CAS_POLICY
-#if FEATURE_LOADER_OPTIMIZATION
+#if FEATURE_LOADER_OPTIMIZATION
else
if(propertyNames[i]=="LOADER_OPTIMIZATION")
{
default: throw new ArgumentException(Environment.GetResourceString("Argument_UnrecognizedLoaderOptimization"), "LOADER_OPTIMIZATION");
}
}
-#endif // FEATURE_LOADER_OPTIMIZATION
-#if FEATURE_CORECLR
+#endif // FEATURE_LOADER_OPTIMIZATION
+#if FEATURE_CORECLR
else
if(propertyNames[i]=="NATIVE_DLL_SEARCH_DIRECTORIES")
{
if (Path.IsRelative(path))
throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) );
- string appPath=Path.NormalizePath(path,true);
+ string appPath = NormalizePath(path, fullCheck: true);
+
normalisedAppPathList.Append(appPath);
normalisedAppPathList.Append(Path.PathSeparator);
}
{
normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1);
}
- ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
+ ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
}
else
if(propertyNames[i]=="PLATFORM_RESOURCE_ROOTS")
if (Path.IsRelative(path))
throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) );
- string appPath=Path.NormalizePath(path,true);
+ string appPath = NormalizePath(path, fullCheck: true);
+
normalisedAppPathList.Append(appPath);
normalisedAppPathList.Append(Path.PathSeparator);
}
{
normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1);
}
- ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
+ ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
}
else
if(propertyNames[i]=="APP_PATHS")
if (Path.IsRelative(path))
throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) );
- string appPath=Path.NormalizePath(path,true);
+ string appPath = NormalizePath(path, fullCheck: true);
+
normalisedAppPathList.Append(appPath);
normalisedAppPathList.Append(Path.PathSeparator);
}
{
normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1);
}
- ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
+ ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
}
else
if(propertyNames[i]=="APP_NI_PATHS")
if (Path.IsRelative(path))
throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) );
- string appPath=Path.NormalizePath(path,true);
+ string appPath = NormalizePath(path, fullCheck: true);
+
normalisedAppPathList.Append(appPath);
normalisedAppPathList.Append(Path.PathSeparator);
}
{
normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1);
}
- ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
+ ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly
}
else
if(propertyNames[i]!= null)
{
- ad.SetDataHelper(propertyNames[i],propertyValues[i],null); // just propagate
+ ad.SetDataHelper(propertyNames[i],propertyValues[i],null); // just propagate
}
#endif
#endif // FEATURE_CLICKONCE
}
+ [SecuritySafeCritical]
+ internal static string NormalizePath(string path, bool fullCheck)
+ {
+ // We have to directly hit LegacyNormalizePath to avoid loading quirks for
+ // the AppDomain. (Once we have runtime support for long paths we can
+ // use the new normalization in path, but we still need to go in directly
+ // to avoid quirks.)
+ return Path.LegacyNormalizePath(
+ path: path,
+ fullCheck: fullCheck,
+ maxPathLength: PathInternal.MaxShortPath,
+ expandShortPaths: true);
+ }
#if FEATURE_APTCA
// Called from DomainAssembly in Conditional APTCA cases
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal extern Int32 GetId();
internal const Int32 DefaultADID = 1;
Contract.Assert(i != -1, "invalid image location");
AppDomainSetup info = new AppDomainSetup();
+
info.ApplicationBase = imageLocation.Substring(0, i+1);
StringBuilder config = new StringBuilder(imageLocation.Substring(i+1));
}
// Used by the validator for testing but not executing an assembly
-#if FEATURE_REMOTING
+#if FEATURE_REMOTING
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
private static AppDomain InternalCreateDomain(String imageLocation)
// Converts an array of bytes into a String.
public static String ToString (byte[] value, int startIndex, int length) {
if (value == null) {
- throw new ArgumentNullException("byteArray");
+ throw new ArgumentNullException("value");
}
if (startIndex < 0 || startIndex >= value.Length && startIndex > 0) { // Don't throw for a 0 length array.
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- internal static string GetEntryPointFullPath (ActivationContext activationContext) {
+ internal static string GetEntryPointFullPath (ActivationContext activationContext)
+ {
string file, parameters;
GetEntryPoint(activationContext, out file, out parameters);
- if (!String.IsNullOrEmpty(file)) {
+ if (!string.IsNullOrEmpty(file))
+ {
string directoryName = activationContext.ApplicationDirectory;
- if (directoryName == null || directoryName.Length == 0) {
+ if (directoryName == null || directoryName.Length == 0)
+ {
// If we were passed a relative path, assume the app base is the current working directory
- StringBuilder sb = new StringBuilder(Path.MAX_PATH + 1);
- if (Win32Native.GetCurrentDirectory(sb.Capacity, sb) == 0)
- System.IO.__Error.WinIOError();
- directoryName = sb.ToString();
+ directoryName = Directory.UnsafeGetCurrentDirectory();
}
file = Path.Combine(directoryName, file);
{
collector.AddBinary(value);
}
+
+ public override object GetData(object value)
+ {
+ object val = base.GetData(value);
+ if (null == val)
+ val = "";
+
+ return val;
+ }
}
/// <summary>
}
this.WriteEventRaw(
+ eventName,
ref descriptor,
activityID,
childActivityID,
}
this.WriteEventRaw(
+ eventName,
ref descriptor,
activityID,
childActivityID,
eventTypes.typeInfo.WriteData(TraceLoggingDataCollector.Instance, ref data);
this.WriteEventRaw(
+ eventName,
ref descriptor,
pActivityId,
pRelatedActivityId,
if (ex is EventSourceException)
throw;
else
- ThrowEventSourceException(ex);
+ ThrowEventSourceException(eventName, ex);
}
finally
{
if (ex is EventSourceException)
throw;
else
- ThrowEventSourceException(ex);
+ ThrowEventSourceException(eventName, ex);
}
}
eventCallbackArgs.PayloadNames = new ReadOnlyCollection<string>((IList<string>)payload.Keys);
}
- DisptachToAllListeners(-1, pActivityId, eventCallbackArgs);
+ DispatchToAllListeners(-1, pActivityId, eventCallbackArgs);
}
#if !ES_BUILD_PCL
var newGroup = new FieldMetadata(
name,
TraceLoggingDataType.Struct,
- 0,
+ this.Tags,
this.BeginningBufferedArray);
this.AddField(newGroup);
result = new TraceLoggingMetadataCollector(this, newGroup);
using System;
using System.Diagnostics;
using System.Threading;
-using System.Threading.Tasks;
-
#if !ES_BUILD_AGAINST_DOTNET_V35
using Contract = System.Diagnostics.Contracts.Contract;
#else
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
-#else
+#else
+using System.Threading.Tasks;
namespace System.Diagnostics.Tracing
#endif
{
/// <summary>
- /// Tracks activities. This is meant to be a singledon (accessed by the ActivityTracer.Instance static property)
+ /// Tracks activities. This is meant to be a singleton (accessed by the ActivityTracer.Instance static property)
///
/// Logically this is simply holds the m_current variable that holds the async local that holds the current ActivityInfo
- /// An ActivityInfo is represents a actvity (which knows its creator and thus knows its path).
+ /// An ActivityInfo is represents a activity (which knows its creator and thus knows its path).
///
/// Most of the magic is in the async local (it gets copied to new tasks)
///
/// On any normal event log the event with activityTracker.CurrentActivityId
/// </summary>
internal class ActivityTracker
- {
+ {
/// <summary>
/// Called on work item begins. The activity name = providerName + activityName without 'Start' suffix.
public void OnStart(string providerName, string activityName, int task, ref Guid activityId, ref Guid relatedActivityId, EventActivityOptions options)
{
if (m_current == null) // We are not enabled
- return;
+ {
+ // We used to rely on the TPL provider turning us on, but that has the disadvantage that you don't get Start-Stop tracking
+ // until you use Tasks for the first time (which you may never do). Thus we change it to pull rather tan push for whether
+ // we are enabled.
+ if (m_checkedForEnable)
+ return;
+ m_checkedForEnable = true;
+#if ES_BUILD_STANDALONE
+ Enable(); // Enable it unconditionally.
+#else
+ if (System.Threading.Tasks.TplEtwProvider.Log.IsEnabled(EventLevel.Informational, System.Threading.Tasks.TplEtwProvider.Keywords.TasksFlowActivityIds))
+ Enable();
+#endif
+ if(m_current == null)
+ {
+ return;
+ }
+ }
Contract.Assert((options & EventActivityOptions.Disable) == 0);
var currentActivity = m_current.Value;
var fullActivityName = NormalizeActivityName(providerName, activityName, task);
-
+
var etwLog = TplEtwProvider.Log;
- if (etwLog.Debug)
+ if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStartEnter", fullActivityName);
etwLog.DebugFacilityMessage("OnStartEnterActivityState", ActivityInfo.LiveActivities(currentActivity));
else
id = Interlocked.Increment(ref currentActivity.m_lastChildID);
- // Remember the previous ID so we can log it
- relatedActivityId = currentActivity != null ? currentActivity.ActivityId : Guid.Empty;
+ // The previous ID is my 'causer' and becomes my related activity ID
+ relatedActivityId = EventSource.CurrentThreadActivityId;
// Add to the list of started but not stopped activities.
- ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, options);
+ ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, relatedActivityId, options);
m_current.Value = newActivity;
// Remember the current ID so we can log it
activityId = newActivity.ActivityId;
- if (etwLog.Debug)
+ if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStartRetActivityState", ActivityInfo.LiveActivities(newActivity));
etwLog.DebugFacilityMessage1("OnStartRet", activityId.ToString(), relatedActivityId.ToString());
/// <summary>
/// Called when a work item stops. The activity name = providerName + activityName without 'Stop' suffix.
- /// It updates CurrentActivityId to track this fact. The Stop event associated with stop should log the ActivityID associated with the event.
+ /// It updates m_current variable to track this fact. The Stop event associated with stop should log the ActivityID associated with the event.
///
/// If activity tracing is not on, then activityId and relatedActivityId are not set
/// </summary>
var fullActivityName = NormalizeActivityName(providerName, activityName, task);
var etwLog = TplEtwProvider.Log;
- if (etwLog.Debug)
+ if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStopEnter", fullActivityName);
etwLog.DebugFacilityMessage("OnStopEnterActivityState", ActivityInfo.LiveActivities(m_current.Value));
}
- for (; ;) // This is a retry loop.
+ for (; ; ) // This is a retry loop.
{
ActivityInfo currentActivity = m_current.Value;
ActivityInfo newCurrentActivity = null; // if we have seen any live activities (orphans), at he first one we have seen.
m_current.Value = newCurrentActivity;
- if (etwLog.Debug)
+ if (etwLog.Debug)
{
etwLog.DebugFacilityMessage("OnStopRetActivityState", ActivityInfo.LiveActivities(newCurrentActivity));
etwLog.DebugFacilityMessage("OnStopRet", activityId.ToString());
[System.Security.SecuritySafeCritical]
public void Enable()
{
- if (m_current == null)
+ if (m_current == null)
{
m_current = new AsyncLocal<ActivityInfo>(ActivityChanging);
}
}
-
+
/// <summary>
/// An activity tracker is a singleton, this is how you get the one and only instance.
/// </summary>
// *******************************************************************************
/// <summary>
- /// An ActivityInfo repesents a particular activity. It is almost read-only the only
+ /// An ActivityInfo represents a particular activity. It is almost read-only. The only
/// fields that change after creation are
/// m_lastChildID - used to generate unique IDs for the children activities and for the most part can be ignored.
/// m_stopped - indicates that this activity is dead
- /// This read-only ness is important because an activity's m_creator chain forms the
+ /// This read-only-ness is important because an activity's m_creator chain forms the
/// 'Path of creation' for the activity (which is also its unique ID) but is also used as
/// the 'list of live parents' which indicate of those ancestors, which are alive (if they
/// are not marked dead they are alive).
/// </summary>
private class ActivityInfo
{
- public ActivityInfo(string name, long uniqueId, ActivityInfo creator, EventActivityOptions options)
+ public ActivityInfo(string name, long uniqueId, ActivityInfo creator, Guid activityIDToRestore, EventActivityOptions options)
{
m_name = name;
m_eventOptions = options;
m_creator = creator;
m_uniqueId = uniqueId;
m_level = creator != null ? creator.m_level + 1 : 0;
+ m_activityIdToRestore = activityIDToRestore;
// Create a nice GUID that encodes the chain of activities that started this one.
CreateActivityPathGuid(out m_guid, out m_activityPathGuidOffset);
}
}
- public static string Path(ActivityInfo activityInfo)
+ public static string Path(ActivityInfo activityInfo)
{
if (activityInfo == null)
- return("");
+ return ("");
return Path(activityInfo.m_creator) + "/" + activityInfo.m_uniqueId;
}
- public override string ToString()
+ public override string ToString()
{
string dead = "";
if (m_stopped != 0)
- dead = ",DEAD";
- return m_name + "(" + Path(this) + dead + ")";
+ dead = ",DEAD";
+ return m_name + "(" + Path(this) + dead + ")";
}
public static string LiveActivities(ActivityInfo list)
/// (rooted in an activity that predates activity tracking.
///
/// We wish to encode this path in the Guid to the extent that we can. Many of the paths have
- /// many small numbers in them and we take advatage of this in the encoding to output as long
+ /// many small numbers in them and we take advantage of this in the encoding to output as long
/// a path in the GUID as possible.
///
- /// Because of the possiblility of GUID collistion, we only use 96 of the 128 bits of the GUID
+ /// Because of the possibility of GUID collision, we only use 96 of the 128 bits of the GUID
/// for encoding the path. The last 32 bits are a simple checksum (and random number) that
/// identifies this as using the convention defined here.
///
[System.Security.SecuritySafeCritical]
private unsafe void CreateActivityPathGuid(out Guid idRet, out int activityPathGuidOffset)
{
- fixed (Guid* outPtr = &idRet)
+ fixed (Guid* outPtr = &idRet)
{
int activityPathGuidOffsetStart = 0;
if (m_creator != null)
activityPathGuidOffsetStart = m_creator.m_activityPathGuidOffset;
idRet = m_creator.m_guid;
}
- else
+ else
{
- // We start with the appdomain number to make this unique among appdomains.
- activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint) System.Threading.Thread.GetDomainID());
+ //
+ int appDomainID = 0;
+#if !ES_BUILD_PCL
+ appDomainID = System.Threading.Thread.GetDomainID();
+#endif
+ // We start with the appdomain number to make this unique among appdomains.
+ activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)appDomainID);
}
- activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint) m_uniqueId);
+ activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)m_uniqueId);
// If the path does not fit, Make a GUID by incrementing rather than as a path, keeping as much of the path as possible
/// <summary>
/// If we can't fit the activity Path into the GUID we come here. What we do is simply
- /// generate a 4 byte number (s_nextOverflowId). Then look for an anscesor that has
+ /// generate a 4 byte number (s_nextOverflowId). Then look for an ancestor that has
/// sufficient space for this ID. By doing this, we preserve the fact that this activity
/// is a child (of unknown depth) from that ancestor.
/// </summary>
[System.Security.SecurityCritical]
private unsafe void CreateOverflowGuid(Guid* outPtr)
{
- // Seach backwards for an ancestor that has sufficient space to put the ID.
- for(ActivityInfo ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator)
+ // Search backwards for an ancestor that has sufficient space to put the ID.
+ for (ActivityInfo ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator)
{
if (ancestor.m_activityPathGuidOffset <= 10) // we need at least 2 bytes.
{
- uint id = (uint) Interlocked.Increment(ref ancestor.m_lastChildID); // Get a unique ID
+ uint id = unchecked((uint)Interlocked.Increment(ref ancestor.m_lastChildID)); // Get a unique ID
// Try to put the ID into the GUID
*outPtr = ancestor.m_guid;
int endId = AddIdToGuid(outPtr, ancestor.m_activityPathGuidOffset, id, true);
}
/// <summary>
- /// The encoding for a list of numbers used to make Activity Guids. Basically
- /// we operate on nibbles (which are nice becase they show up as hex digits). The
+ /// The encoding for a list of numbers used to make Activity GUIDs. Basically
+ /// we operate on nibbles (which are nice because they show up as hex digits). The
/// list is ended with a end nibble (0) and depending on the nibble value (Below)
/// the value is either encoded into nibble itself or it can spill over into the
/// bytes that follow.
LastImmediateValue = 0xA,
PrefixCode = 0xB, // all the 'long' encodings go here. If the next nibble is MultiByte1-4
- // than this is a 'overflow' id. Unlike the hierarchitcal IDs these are
- // allocated densly but don't tell you anything about nesting. we use
- // these when we run out of space in the GUID to store the path.
+ // than this is a 'overflow' id. Unlike the hierarchical IDs these are
+ // allocated densely but don't tell you anything about nesting. we use
+ // these when we run out of space in the GUID to store the path.
MultiByte1 = 0xC, // 1 byte follows. If this Nibble is in the high bits, it the high bits of the number are stored in the low nibble.
// commented out because the code does not explicitly reference the names (but they are logically defined).
- // MultiByte2 = 0xD, // 2 bytes follow (we don't bother with the nibble optimzation)
- // MultiByte3 = 0xE, // 3 bytes follow (we don't bother with the nibble optimzation)
- // MultiByte4 = 0xF, // 4 bytes follow (we don't bother with the nibble optimzation)
+ // MultiByte2 = 0xD, // 2 bytes follow (we don't bother with the nibble optimization)
+ // MultiByte3 = 0xE, // 3 bytes follow (we don't bother with the nibble optimization)
+ // MultiByte4 = 0xF, // 4 bytes follow (we don't bother with the nibble optimization)
}
- /// Add the acivity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId'
+ /// Add the activity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId'
/// Thus if this number is 6 that is where 'id' will be added. This will return 13 (12
/// is the maximum number of bytes that fit in a GUID) if the path did not fit.
/// If 'overflow' is true, then the number is encoded as an 'overflow number (which has a
{
if (endPtr <= ptr + 2) // I need at least 2 bytes
return 13;
-
+
// Write out the prefix code nibble and the length nibble
- WriteNibble(ref ptr, endPtr, (uint) NumberListCodes.PrefixCode);
+ WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.PrefixCode);
}
// The rest is the same for overflow and non-overflow case
WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.MultiByte1 + (len - 1));
// Do we have an odd nibble? If so flush it or use it for the 12 byte case.
if (ptr < endPtr && *ptr != 0)
{
- // If the value < 4096 we can use the nibble we are otherwise just outputing as padding.
+ // If the value < 4096 we can use the nibble we are otherwise just outputting as padding.
if (id < 4096)
{
// Indicate this is a 1 byte multicode with 4 high order bits in the lower nibble.
}
// Write out the bytes.
- while(0 < len)
+ while (0 < len)
{
if (endPtr <= ptr)
{
#endregion // CreateGuidForActivityPath
readonly internal string m_name; // The name used in the 'start' and 'stop' APIs to help match up
- readonly long m_uniqueId; // a small number that makes this activity unique among its siblings
- internal readonly Guid m_guid; // Activity Guid, it is bascially an encoding of the Path() (see CreateActivityPathGuid)
+ readonly long m_uniqueId; // a small number that makes this activity unique among its siblings
+ internal readonly Guid m_guid; // Activity Guid, it is basically an encoding of the Path() (see CreateActivityPathGuid)
internal readonly int m_activityPathGuidOffset; // Keeps track of where in m_guid the causality path stops (used to generated child GUIDs)
internal readonly int m_level; // current depth of the Path() of the activity (used to keep recursion under control)
readonly internal EventActivityOptions m_eventOptions; // Options passed to start.
internal long m_lastChildID; // used to create a unique ID for my children activities
internal int m_stopped; // This work item has stopped
readonly internal ActivityInfo m_creator; // My parent (creator). Forms the Path() for the activity.
+ readonly internal Guid m_activityIdToRestore; // The Guid to restore after a stop.
#endregion
}
// with m_current.ActivityID
void ActivityChanging(AsyncLocalValueChangedArgs<ActivityInfo> args)
{
- if (args.PreviousValue == args.CurrentValue)
- return;
+ ActivityInfo cur = args.CurrentValue;
+ ActivityInfo prev = args.PreviousValue;
- if (args.CurrentValue != null)
+ // Are we popping off a value? (we have a prev, and it creator is cur)
+ // Then check if we should use the GUID at the time of the start event
+ if (prev != null && prev.m_creator == cur)
{
- // Allow subsequent activities inside this thread to automatically get the current activity ID.
- EventSource.SetCurrentThreadActivityId(args.CurrentValue.ActivityId);
+ // If the saved activity ID is not the same as the creator activity
+ // that takes precedence (it means someone explicitly did a SetActivityID)
+ // Set it to that and get out
+ if (cur == null || prev.m_activityIdToRestore != cur.ActivityId)
+ {
+ EventSource.SetCurrentThreadActivityId(prev.m_activityIdToRestore);
+ return;
+ }
}
- else
- EventSource.SetCurrentThreadActivityId(Guid.Empty);
+
+ // OK we did not have an explicit SetActivityID set. Then we should be
+ // setting the activity to current ActivityInfo. However that activity
+ // might be dead, in which case we should skip it, so we never set
+ // the ID to dead things.
+ while(cur != null)
+ {
+ // We found a live activity (typically the first time), set it to that.
+ if (cur.m_stopped == 0)
+ {
+ EventSource.SetCurrentThreadActivityId(cur.ActivityId);
+ return;
+ }
+ cur = cur.m_creator;
+ }
+ // we can get here if there is no information on our activity stack (everything is dead)
+ // currently we do nothing, as that seems better than setting to Guid.Emtpy.
}
/// <summary>
- /// Async local variables have the propery that the are automatically copied whenever a task is created and used
+ /// Async local variables have the properly that the are automatically copied whenever a task is created and used
/// while that task is running. Thus m_current 'flows' to any task that is caused by the current thread that
/// last set it.
///
/// This variable points a a linked list that represents all Activities that have started but have not stopped.
/// </summary>
AsyncLocal<ActivityInfo> m_current;
+ bool m_checkedForEnable;
// Singleton
private static ActivityTracker s_activityTrackerInstance = new ActivityTracker();
// Used to create unique IDs at the top level. Not used for nested Ids (each activity has its own id generator)
static long m_nextId = 0;
private const ushort MAX_ACTIVITY_DEPTH = 100; // Limit maximum depth of activities to be tracked at 100.
- // This will avoid leaking memory in case of activities that are never stopped.
+ // This will avoid leaking memory in case of activities that are never stopped.
#endregion
}
+
+#if ES_BUILD_STANDALONE
+ /******************************** SUPPORT *****************************/
+ /// <summary>
+ /// This is supplied by the framework. It is has the semantics that the value is copied to any new Tasks that is created
+ /// by the current task. Thus all causally related code gets this value. Note that reads and writes to this VARIABLE
+ /// (not what it points it) to this does not need to be protected by locks because it is inherently thread local (you always
+ /// only get your thread local copy which means that you never have ----s.
+ /// </summary>
+ ///
+ [EventSource(Name="Microsoft.Tasks.Nuget")]
+ internal class TplEtwProvider : EventSource
+ {
+ public class Keywords
+ {
+ public const EventKeywords Debug = (EventKeywords) 1;
+ }
+
+ public static TplEtwProvider Log = new TplEtwProvider();
+ public bool Debug { get { return IsEnabled(EventLevel.Verbose, Keywords.Debug); } }
+
+ public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(1, Facility, Message); }
+ public void DebugFacilityMessage1(string Facility, string Message, string Arg) { WriteEvent(2, Facility, Message, Arg); }
+ public void SetActivityId(Guid Id) { WriteEvent(3, Id); }
+ }
+#endif
+
+#if ES_BUILD_AGAINST_DOTNET_V35 || ES_BUILD_PCL || NO_ASYNC_LOCAL
+
+ internal sealed class AsyncLocalValueChangedArgs<T>
+ {
+ public AsyncLocalValueChangedArgs()
+ {
+ }
+
+ public T PreviousValue { get { return default(T); } }
+ public T CurrentValue { get { return default(T); } }
+
+ }
+
+ internal sealed class AsyncLocal<T>
+ {
+ public AsyncLocal()
+ {
+ }
+
+ public AsyncLocal(Action<AsyncLocalValueChangedArgs<T>> valueChangedHandler)
+ {
+
+ }
+
+ public T Value
+ {
+ get
+ {
+ object obj = null; //
+ return (obj == null) ? default(T) : (T)obj;
+ }
+ set
+ {
+ //
+ }
+ }
+ }
+#endif
+
}
private static WriteEventErrorCode s_returnCode; // The last return code
private const int s_basicTypeAllocationBufferSize = 16;
- private const int s_etwMaxNumberArguments = 32;
+ private const int s_etwMaxNumberArguments = 128;
private const int s_etwAPIMaxRefObjCount = 8;
private const int s_maxEventDataDescriptors = 128;
private const int s_traceEventMaximumSize = 65482;
-// Copyright (c) Microsoft Corporation. All rights reserved
-// Copyright (c) Microsoft Corporation. All rights reserved
+// Copyright (c) Microsoft Corporation. All rights reserved
// This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in.
// It is available from http://www.codeplex.com/hyperAddin
#define FEATURE_MANAGED_ETW
// #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS
#endif
-/* DESIGN NOTES DESIGN NOTES DESIGN NOTES DESIGN NOTES */
+/* DESIGN NOTES DESIGN NOTES DESIGN NOTES DESIGN NOTES */
// DESIGN NOTES
// Over the years EventSource has become more complex and so it is important to understand
// the basic structure of the code to insure that it does not grow more complex.
using System;
+using System.Runtime.CompilerServices;
#if FEATURE_ACTIVITYSAMPLING
using System.Collections.Concurrent;
#endif
#if FEATURE_ACTIVITYSAMPLING
Guid newId = activityId;
#endif // FEATURE_ACTIVITYSAMPLING
+
// We ignore errors to keep with the convention that EventSources do not throw errors.
// Note we can't access m_throwOnWrites because this is a static method.
if (UnsafeNativeMethods.ManifestEtw.EventActivityIdControl(
/// </summary>
public static Guid CurrentThreadActivityId
{
- [System.Security.SecurityCritical]
+ [System.Security.SecuritySafeCritical]
get
{
// We ignore errors to keep with the convention that EventSources do not throw
/// </summary>
public override string ToString() { return Environment.GetResourceString("EventSource_ToString", Name, Guid); }
+ /// <summary>
+ /// Fires when a Command (e.g. Enable) comes from a an EventListener.
+ /// </summary>
+ public event EventHandler<EventCommandEventArgs> EventCommandExecuted
+ {
+ add
+ {
+ m_eventCommandExecuted += value;
+
+ // If we have an EventHandler<EventCommandEventArgs> attached to the EventSource before the first command arrives
+ // It should get a chance to handle the deferred commands.
+ EventCommandEventArgs deferredCommands = m_deferredCommands;
+ while (deferredCommands != null)
+ {
+ value(this, deferredCommands);
+ deferredCommands = deferredCommands.nextCommand;
+ }
+ }
+ remove
+ {
+ m_eventCommandExecuted -= value;
+ }
+ }
+
#region protected
/// <summary>
/// This is the constructor that most users will use to create their eventSource. It takes
{
Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source.
if (relatedActivityId != null)
- ValidateEventOpcodeForTransfer(ref m_eventData[eventId]);
+ ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
#if FEATURE_MANAGED_ETW
if (m_eventData[eventId].EnabledForETW)
// mask set to 0x0f so, when all ETW sessions want the event we don't need to
// synthesize a new one
if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
- ThrowEventSourceException();
+ ThrowEventSourceException(m_eventData[eventId].Name);
}
else
{
unchecked((long)etwSessions.ToEventKeywords() | origKwd));
if (!m_provider.WriteEvent(ref desc, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
- ThrowEventSourceException();
+ ThrowEventSourceException(m_eventData[eventId].Name);
}
}
else
if (!SelfDescribingEvents)
{
if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data))
- ThrowEventSourceException();
+ ThrowEventSourceException(m_eventData[eventId].Name);
}
else
{
if (ex is EventSourceException)
throw;
else
- ThrowEventSourceException(ex);
+ ThrowEventSourceException(m_eventData[eventId].Name, ex);
}
}
}
#endif
[SecurityCritical]
private unsafe void WriteEventRaw(
+ string eventName,
ref EventDescriptor eventDescriptor,
Guid* activityID,
Guid* relatedActivityID,
{
if (m_provider == null)
{
- ThrowEventSourceException();
+ ThrowEventSourceException(eventName);
}
else
{
if (!m_provider.WriteEventRaw(ref eventDescriptor, activityID, relatedActivityID, dataCount, data))
- ThrowEventSourceException();
+ ThrowEventSourceException(eventName);
}
}
{
// If there are any deferred commands, we can do them now.
// This is the most likely place for exceptions to happen.
- while (m_deferredCommands != null)
+ // Note that we are NOT resetting m_deferredCommands to NULL here,
+ // We are giving for EventHandler<EventCommandEventArgs> that will be attached later
+ EventCommandEventArgs deferredCommands = m_deferredCommands;
+ while (deferredCommands != null)
{
- DoCommand(m_deferredCommands); // This can never throw, it catches them and reports the errors.
- m_deferredCommands = m_deferredCommands.nextCommand;
+ DoCommand(deferredCommands); // This can never throw, it catches them and reports the errors.
+ deferredCommands = deferredCommands.nextCommand;
}
}
}
dataPointer = data->DataPointer;
data++;
for (int i = 0; i < cbSize; ++i)
- blob[i] = *((byte*)dataPointer);
+ blob[i] = *((byte*)dataPointer + i);
return blob;
}
else if (dataType == typeof(byte*))
{
Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source.
if (childActivityID != null)
- ValidateEventOpcodeForTransfer(ref m_eventData[eventId]);
-
+ {
+ ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name);
+
+ // If you use WriteEventWithRelatedActivityID you MUST declare the first argument to be a GUID
+ // with the name 'relatedActivityID, and NOT pass this argument to the WriteEvent method.
+ // During manifest creation we modify the ParameterInfo[] that we store to strip out any
+ // first parameter that is of type Guid and named "relatedActivityId." Thus, if you call
+ // WriteEventWithRelatedActivityID from a method that doesn't name its first parameter correctly
+ // we can end up in a state where the ParameterInfo[] doesn't have its first parameter stripped,
+ // and this leads to a mismatch between the number of arguments and the number of ParameterInfos,
+ // which would cause a cryptic IndexOutOfRangeException later if we don't catch it here.
+ if (!m_eventData[eventId].HasRelatedActivityID)
+ {
+ throw new ArgumentException(Environment.GetResourceString("EventSource_NoRelatedActivityId"));
+ }
+ }
+
+ LogEventArgsMismatches(m_eventData[eventId].Parameters, args);
#if FEATURE_MANAGED_ETW
if (m_eventData[eventId].EnabledForETW)
{
// mask set to 0x0f so, when all ETW sessions want the event we don't need to
// synthesize a new one
if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
- ThrowEventSourceException();
+ ThrowEventSourceException(m_eventData[eventId].Name);
}
else
{
unchecked((long)(ulong)etwSessions | origKwd));
if (!m_provider.WriteEvent(ref desc, pActivityId, childActivityID, args))
- ThrowEventSourceException();
+ ThrowEventSourceException(m_eventData[eventId].Name);
}
}
else
if (!SelfDescribingEvents)
{
if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args))
- ThrowEventSourceException();
+ ThrowEventSourceException(m_eventData[eventId].Name);
}
else
{
if (ex is EventSourceException)
throw;
else
- ThrowEventSourceException(ex);
+ ThrowEventSourceException(m_eventData[eventId].Name, ex);
}
}
}
return eventData;
}
+ /// <summary>
+ /// We expect that the arguments to the Event method and the arguments to WriteEvent match. This function
+ /// checks that they in fact match and logs a warning to the debugger if they don't.
+ /// </summary>
+ /// <param name="infos"></param>
+ /// <param name="args"></param>
+ private void LogEventArgsMismatches(ParameterInfo[] infos, object[] args)
+ {
+ // It would be nice to have this on PCL builds, but it would be pointless since there isn't support for
+ // writing to the debugger log on PCL.
+ bool typesMatch = args.Length == infos.Length;
+
+ int i = 0;
+ while (typesMatch && i < args.Length)
+ {
+ Type pType = infos[i].ParameterType;
+
+ // Checking to see if the Parameter types (from the Event method) match the supplied argument types.
+ // Fail if one of two things hold : either the argument type is not equal to the parameter type, or the
+ // argument is null and the parameter type is non-nullable.
+ if ((args[i] != null && (args[i].GetType() != pType))
+ || (args[i] == null && (!(pType.IsGenericType && pType.GetGenericTypeDefinition() == typeof(Nullable<>))))
+ )
+ {
+ typesMatch = false;
+ break;
+ }
+
+ ++i;
+ }
+
+ if (!typesMatch)
+ {
+ System.Diagnostics.Debugger.Log(0, null, Environment.GetResourceString("EventSource_VarArgsParameterMismatch") + "\r\n");
+ }
+ }
+
+ private int GetParamLengthIncludingByteArray(ParameterInfo[] parameters)
+ {
+ int sum = 0;
+ foreach(ParameterInfo info in parameters)
+ {
+ if(info.ParameterType == typeof(byte[]))
+ {
+ sum += 2;
+ }
+ else
+ {
+ sum++;
+ }
+ }
+
+ return sum;
+ }
+
[SecurityCritical]
unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data)
{
+ // We represent a byte[] as a integer denoting the length and then a blob of bytes in the data pointer. This causes a spurious
+ // warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check
+ // that the number of parameters is correct against the byte[] case, but also we the args array would be one too long if
+ // we just used the modifiedParamCount here -- so we need both.
int paramCount = m_eventData[eventId].Parameters.Length;
- if (eventDataCount != paramCount)
+ int modifiedParamCount = GetParamLengthIncludingByteArray(m_eventData[eventId].Parameters);
+ if (eventDataCount != modifiedParamCount)
{
ReportOutOfBandMessage(Environment.GetResourceString("EventSource_EventParametersMismatch", eventId, eventDataCount, paramCount), true);
paramCount = Math.Min(paramCount, eventDataCount);
eventCallbackArgs.Message = m_eventData[eventId].Message;
eventCallbackArgs.Payload = new ReadOnlyCollection<object>(args);
- DisptachToAllListeners(eventId, childActivityID, eventCallbackArgs);
+ DispatchToAllListeners(eventId, childActivityID, eventCallbackArgs);
}
[SecurityCritical]
- private unsafe void DisptachToAllListeners(int eventId, Guid* childActivityID, EventWrittenEventArgs eventCallbackArgs)
+ private unsafe void DispatchToAllListeners(int eventId, Guid* childActivityID, EventWrittenEventArgs eventCallbackArgs)
{
Exception lastThrownException = null;
for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next)
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
- private void ThrowEventSourceException(Exception innerEx = null)
+ private void ThrowEventSourceException(string eventName, Exception innerEx = null)
{
- // If we fail during ouf of band logging we may end up trying
+ // If we fail during out of band logging we may end up trying
// to throw another EventSourceException, thus hitting a StackOverflowException.
// Avoid StackOverflow by making sure we do not recursively call this method.
if (m_EventSourceExceptionRecurenceCount > 0)
{
m_EventSourceExceptionRecurenceCount++;
+ string errorPrefix = "EventSourceException";
+ if(eventName != null)
+ {
+ errorPrefix += " while processing event \"" + eventName + "\"";
+ }
+
//
switch (EventProvider.GetLastWriteEventError())
{
case EventProvider.WriteEventErrorCode.EventTooBig:
- ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_EventTooBig"), true);
+ ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_EventTooBig"), true);
if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_EventTooBig"), innerEx);
break;
case EventProvider.WriteEventErrorCode.NoFreeBuffers:
- ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_NoFreeBuffers"), true);
+ ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_NoFreeBuffers"), true);
if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_NoFreeBuffers"), innerEx);
break;
case EventProvider.WriteEventErrorCode.NullInput:
- ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_NullInput"), true);
+ ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_NullInput"), true);
if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_NullInput"), innerEx);
break;
case EventProvider.WriteEventErrorCode.TooManyArgs:
- ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_TooManyArgs"), true);
+ ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_TooManyArgs"), true);
if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_TooManyArgs"), innerEx);
break;
default:
if (innerEx != null)
- ReportOutOfBandMessage("EventSourceException: " + innerEx.GetType() + ":" + innerEx.Message, true);
+ ReportOutOfBandMessage(errorPrefix + ": " + innerEx.GetType() + ":" + innerEx.Message, true);
else
- ReportOutOfBandMessage("EventSourceException", true);
+ ReportOutOfBandMessage(errorPrefix, true);
if (ThrowOnEventWriteErrors) throw new EventSourceException(innerEx);
break;
}
}
}
- private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData)
+ private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData, string eventName)
{
if ((EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Send &&
- (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive)
+ (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive &&
+ (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Start)
+
{
- ThrowEventSourceException();
+ ThrowEventSourceException(eventName);
}
}
internal static EventOpcode GetOpcodeWithDefault(EventOpcode opcode, string eventName)
{
- if (opcode == EventOpcode.Info)
+ if (opcode == EventOpcode.Info && eventName != null)
{
if (eventName.EndsWith(s_ActivityStartSuffix))
{
public EventTags Tags;
public bool EnabledForAnyListener; // true if any dispatcher has this event turned on
public bool EnabledForETW; // is this event on for the OS ETW data dispatcher?
+
+ public bool HasRelatedActivityID; // Set if the event method's first parameter is a Guid named 'relatedActivityId'
#if !FEATURE_ACTIVITYSAMPLING
#pragma warning disable 0649
#endif
var commandArgs = new EventCommandEventArgs(command, commandArguments, this, listener, perEventSourceSessionId, etwSessionId, enable, level, matchAnyKeyword);
lock (EventListener.EventListenersLock)
{
- if (m_completelyInited) // We are fully initialized, do the command
+ if (m_completelyInited)
+ {
+ // After the first command arrive after construction, we are ready to get rid of the deferred commands
+ this.m_deferredCommands = null;
+ // We are fully initialized, do the command
DoCommand(commandArgs);
+ }
else
{
// We can't do the command, simply remember it and we do it when we are fully constructed.
Contract.Assert(m_eventData != null);
m_eventSourceEnabled = true;
}
-
+
this.OnEventCommand(commandArgs);
-
+ var eventCommandCallback = this.m_eventCommandExecuted;
+ if (eventCommandCallback != null)
+ eventCommandCallback(this, commandArgs);
+
#if FEATURE_ACTIVITYSAMPLING
if (commandArgs.listener == null && !bSessionEnable && commandArgs.perEventSourceSessionId != -1)
{
// Contract.Assert(enable == true);
// Contract.Assert(level == EventLevel.LogAlways);
// Contract.Assert(matchAnyKeyword == EventKeywords.None);
-
+
this.OnEventCommand(commandArgs);
+ var eventCommandCallback = m_eventCommandExecuted;
+ if (eventCommandCallback != null)
+ eventCommandCallback(this, commandArgs);
}
#if FEATURE_ACTIVITYSAMPLING
}
success = false;
if (ThrowOnEventWriteErrors)
- ThrowEventSourceException();
+ ThrowEventSourceException("SendManifest");
break;
}
}
manifest.AddKeyword("Session0", (long)0x8000 << 32);
}
- if (eventSourceType.Name != "EventSource")
+ if (eventSourceType != typeof(EventSource))
{
for (int i = 0; i < methods.Length; i++)
{
// Get the EventDescriptor (from the Custom attributes)
EventAttribute eventAttribute = (EventAttribute)GetCustomAttributeHelper(method, typeof(EventAttribute), flags);
+
+ // Visual Studio online bug #222067 - we can't add a dependency in System.Web on EventSource features that
+ // didn't exist in 4.5. We have to manually set the disable flag here since the ActivityOptions
+ // falls in to that category.
+ //
+ // The check for <= 3 is to only disable Activity tracking for the RequestStarted and RequestCompleted
+ // events.
+ if (eventAttribute != null
+ && source != null
+ && eventAttribute.EventId <= 3
+ && source.Guid.Equals(AspNetEventSourceGuid))
+ {
+ eventAttribute.ActivityOptions |= EventActivityOptions.Disable;
+ }
// Compat: until v4.5.1 we ignored any non-void returning methods as well as virtual methods for
// the only reason of limiting the number of methods considered to be events. This broke a common
eventId++;
string eventName = method.Name;
- if (!eventAttribute.IsOpcodeSet)
+ if (eventAttribute.Opcode == EventOpcode.Info) // We are still using the default opcode.
{
// By default pick a task ID derived from the EventID, starting with the highest task number and working back
bool noTask = (eventAttribute.Task == EventTask.None);
- if (eventAttribute.Task == EventTask.None)
+ if (noTask)
eventAttribute.Task = (EventTask)(0xFFFE - eventAttribute.EventId);
- // pick a default opcode (either Info or start or stop if the name ends with that suffix.
- eventAttribute.Opcode = GetOpcodeWithDefault(EventOpcode.Info, eventName);
+ // Unless we explicitly set the opcode to Info (to override the auto-generate of Start or Stop opcodes,
+ // pick a default opcode based on the event name (either Info or start or stop if the name ends with that suffix).
+ if (!eventAttribute.IsOpcodeSet)
+ eventAttribute.Opcode = GetOpcodeWithDefault(EventOpcode.Info, eventName);
// Make the stop opcode have the same task as the start opcode.
if (noTask)
}
else if (eventAttribute.Opcode == EventOpcode.Stop)
{
- // Find the start associated with this stop event. We require start to be immediately before the stop
+ // Find the start associated with this stop event. We requre start to be immediately before the stop
int startEventId = eventAttribute.EventId - 1;
if (eventData != null && startEventId < eventData.Length)
{
}
}
- RemoveFirstArgIfRelatedActivityId(ref args);
+ bool hasRelatedActivityID = RemoveFirstArgIfRelatedActivityId(ref args);
if (!(source != null && source.SelfDescribingEvents))
{
manifest.StartEvent(eventName, eventAttribute);
if (source != null || (flags & EventManifestOptions.Strict) != 0)
{
// Do checking for user errors (optional, but not a big deal so we do it).
- DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute, manifest);
+ DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute, manifest, flags);
#if FEATURE_MANAGED_ETW_CHANNELS
// add the channel keyword for Event Viewer channel based filters. This is added for creating the EventDescriptors only
// overwrite inline message with the localized message
if (msg != null) eventAttribute.Message = msg;
- AddEventDescriptor(ref eventData, eventName, eventAttribute, args);
+ AddEventDescriptor(ref eventData, eventName, eventAttribute, args, hasRelatedActivityID);
}
}
}
{
bNeedsManifest = (flags & EventManifestOptions.OnlyIfNeededForRegistration) == 0
#if FEATURE_MANAGED_ETW_CHANNELS
- || manifest.GetChannelData().Length > 0
+ || manifest.GetChannelData().Length > 0
#endif
;
return bNeedsManifest ? res : null;
}
- private static void RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args)
+ private static bool RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args)
{
// If the first parameter is (case insensitive) 'relatedActivityId' then skip it.
if (args.Length > 0 && args[0].ParameterType == typeof(Guid) &&
var newargs = new ParameterInfo[args.Length - 1];
Array.Copy(args, 1, newargs, 0, args.Length - 1);
args = newargs;
+
+ return true;
}
+
+ return false;
}
// adds a enumeration (keyword, opcode, task or channel) represented by 'staticField'
// with the code:EventAttribute 'eventAttribute'. resourceManger may be null in which case we populate it
// it is populated if we need to look up message resources
private static void AddEventDescriptor(ref EventMetadata[] eventData, string eventName,
- EventAttribute eventAttribute, ParameterInfo[] eventParameters)
+ EventAttribute eventAttribute, ParameterInfo[] eventParameters,
+ bool hasRelatedActivityID)
{
if (eventData == null || eventData.Length <= eventAttribute.EventId)
{
eventAttribute.EventId,
eventAttribute.Version,
#if FEATURE_MANAGED_ETW_CHANNELS
- (byte)eventAttribute.Channel,
+ (byte)eventAttribute.Channel,
#else
(byte)0,
#endif
eventData[eventAttribute.EventId].Parameters = eventParameters;
eventData[eventAttribute.EventId].Message = eventAttribute.Message;
eventData[eventAttribute.EventId].ActivityOptions = eventAttribute.ActivityOptions;
+ eventData[eventAttribute.EventId].HasRelatedActivityID = hasRelatedActivityID;
}
// Helper used by code:CreateManifestAndDescriptors that trims the m_eventData array to the correct
// index for two distinct events etc. Throws exceptions when it finds something wrong.
private static void DebugCheckEvent(ref Dictionary<string, string> eventsByName,
EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute,
- ManifestBuilder manifest)
+ ManifestBuilder manifest, EventManifestOptions options)
{
int evtId = eventAttribute.EventId;
string evtName = method.Name;
{
manifest.ManifestError(Environment.GetResourceString("EventSource_TaskOpcodePairReused",
evtName, evtId, eventData[idx].Name, idx));
+
+ // If we are not strict stop on first error. We have had problems with really large providers taking forever. because of many errors.
+ if ((options & EventManifestOptions.Strict) == 0)
+ break;
}
}
// for non-default event opcodes the user must define a task!
- if (eventAttribute.Opcode != EventOpcode.Info &&
- (eventAttribute.Task == EventTask.None || eventAttribute.Task == (EventTask)(0xFFFE - evtId)))
+ if (eventAttribute.Opcode != EventOpcode.Info)
{
- manifest.ManifestError(Environment.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId));
+ bool failure = false;
+ if (eventAttribute.Task == EventTask.None)
+ failure = true;
+ else
+ {
+ // If you have the auto-assigned Task, then you did not explicitly set one.
+ // This is OK for Start events because we have special logic to assign the task to a prefix derived from the event name
+ // But all other cases we want to catch the omission.
+ var autoAssignedTask = (EventTask)(0xFFFE - evtId);
+ if ((eventAttribute.Opcode != EventOpcode.Start && eventAttribute.Opcode != EventOpcode.Stop) && eventAttribute.Task == autoAssignedTask)
+ failure = true;
+ }
+ if (failure)
+ manifest.ManifestError(Environment.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId));
}
// If we ever want to enforce the rule: MethodName = TaskName + OpcodeName here's how:
eventsByName = new Dictionary<string, string>();
if (eventsByName.ContainsKey(evtName))
- manifest.ManifestError(Environment.GetResourceString("EventSource_EventNameReused", evtName));
+ manifest.ManifestError(Environment.GetResourceString("EventSource_EventNameReused", evtName), true);
eventsByName[evtName] = evtName;
}
#endif
// Send it to all listeners.
- if (m_outOfBandMessageCount < 254) // Note this is only if size byte
+ if (m_outOfBandMessageCount < 16-1) // Note this is only if size byte
m_outOfBandMessageCount++;
else
{
- if (m_outOfBandMessageCount == 255)
+ if (m_outOfBandMessageCount == 16)
return;
- m_outOfBandMessageCount = 255; // Mark that we hit the limit. Notify them that this is the case.
+ m_outOfBandMessageCount = 16; // Mark that we hit the limit. Notify them that this is the case.
msg = "Reached message limit. End of EventSource error messages.";
}
internal volatile EventMetadata[] m_eventData; // None per-event data
private volatile byte[] m_rawManifest; // Bytes to send out representing the event schema
+ private EventHandler<EventCommandEventArgs> m_eventCommandExecuted;
+
private EventSourceSettings m_config; // configuration information
// Enabling bits
0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
};
+ // Visual Studio Online 222067 - This is only needed for a compatibility hack. We need to check to see
+ // if an EventSource is the AspNetEventSource to override the ActivityTracking for it.
+ private static readonly Guid AspNetEventSourceGuid = new Guid("ee799f41-cfa5-550b-bf2c-344747c1c668");
+
#endregion
}
/// created.
/// </para>
/// </summary>
- public abstract class EventListener : IDisposable
+ public class EventListener : IDisposable
{
+ private static readonly object s_EventSourceCreatedLock = new object();
+
+ private event EventHandler<EventSourceCreatedEventArgs> _EventSourceCreated;
+
/// <summary>
- /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn
- /// them on).
+ /// This event is raised whenever a new eventSource is 'attached' to the dispatcher.
+ /// This can happen for all existing EventSources when the EventListener is created
+ /// as well as for any EventSources that come into existence after the EventListener
+ /// has been created.
+ ///
+ /// These 'catch up' events are called during the construction of the EventListener.
+ /// Subclasses need to be prepared for that.
+ ///
+ /// In a multi-threaded environment, it is possible that 'EventSourceEventWrittenCallback'
+ /// events for a particular eventSource to occur BEFORE the EventSourceCreatedCallback is issued.
/// </summary>
- protected EventListener()
- {
- lock (EventListenersLock)
+ public event EventHandler<EventSourceCreatedEventArgs> EventSourceCreated
+ {
+ add
{
- // Disallow creating EventListener reentrancy.
- if (s_CreatingListener)
- throw new InvalidOperationException(Environment.GetResourceString("EventSource_ListenerCreatedInsideCallback"));
-
- try
+ lock (s_EventSourceCreatedLock)
{
- s_CreatingListener = true;
-
- // Add to list of listeners in the system, do this BEFORE firing the 'OnEventSourceCreated' so that
- // Those added sources see this listener.
- this.m_Next = s_Listeners;
- s_Listeners = this;
-
- // Find all existing eventSources call OnEventSourceCreated to 'catchup'
- // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback)
- // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves
- // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source
- // is created.
- WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray();
-
- for (int i = 0; i < eventSourcesSnapshot.Length; i++)
- {
- WeakReference eventSourceRef = eventSourcesSnapshot[i];
- EventSource eventSource = eventSourceRef.Target as EventSource;
- if (eventSource != null)
- eventSource.AddListener(this); // This will cause the OnEventSourceCreated callback to fire.
- }
+ CallBackForExistingEventSources(false, value);
- Validate();
+ this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>)Delegate.Combine(_EventSourceCreated, value);
}
- finally
+ }
+ remove
+ {
+ lock (s_EventSourceCreatedLock)
{
- s_CreatingListener = false;
+ this._EventSourceCreated = (EventHandler<EventSourceCreatedEventArgs>)Delegate.Remove(_EventSourceCreated, value);
}
}
}
+
+ /// <summary>
+ /// This event is raised whenever an event has been written by a EventSource for which
+ /// the EventListener has enabled events.
+ /// </summary>
+ public event EventHandler<EventWrittenEventArgs> EventWritten;
+
+ /// <summary>
+ /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn
+ /// them on).
+ /// </summary>
+ public EventListener()
+ {
+ // This will cause the OnEventSourceCreated callback to fire.
+ CallBackForExistingEventSources(true, (obj, args) => args.EventSource.AddListener(this) );
+ }
+
/// <summary>
/// Dispose should be called when the EventListener no longer desires 'OnEvent*' callbacks. Because
/// there is an internal list of strong references to all EventListeners, calling 'Dispose' directly
/// for a particular eventSource to occur BEFORE the OnEventSourceCreated is issued.
/// </summary>
/// <param name="eventSource"></param>
- internal protected virtual void OnEventSourceCreated(EventSource eventSource) { }
+ internal protected virtual void OnEventSourceCreated(EventSource eventSource)
+ {
+ EventHandler<EventSourceCreatedEventArgs> callBack = this._EventSourceCreated;
+ if(callBack != null)
+ {
+ EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
+ args.EventSource = eventSource;
+ callBack(this, args);
+ }
+ }
+
/// <summary>
/// This method is called whenever an event has been written by a EventSource for which
/// the EventListener has enabled events.
/// </summary>
- internal protected abstract void OnEventWritten(EventWrittenEventArgs eventData);
+ /// <param name="eventData"></param>
+ internal protected virtual void OnEventWritten(EventWrittenEventArgs eventData)
+ {
+ EventHandler<EventWrittenEventArgs> callBack = this.EventWritten;
+ if (callBack != null)
+ {
+ callBack(this, eventData);
+ }
+ }
+
/// <summary>
/// EventSourceIndex is small non-negative integer (suitable for indexing in an array)
/// identifying EventSource. It is unique per-appdomain. Some EventListeners might find
// See bug 724140 for more
private static void DisposeOnShutdown(object sender, EventArgs e)
{
- foreach (var esRef in s_EventSources)
+ lock(EventListenersLock)
{
- EventSource es = esRef.Target as EventSource;
- if (es != null)
- es.Dispose();
+ foreach (var esRef in s_EventSources)
+ {
+ EventSource es = esRef.Target as EventSource;
+ if (es != null)
+ es.Dispose();
+ }
}
}
/// </summary>
private static void RemoveReferencesToListenerInEventSources(EventListener listenerToRemove)
{
+#if !ES_BUILD_STANDALONE
+ Contract.Assert(Monitor.IsEntered(EventListener.EventListenersLock));
+#endif
// Foreach existing EventSource in the appdomain
foreach (WeakReference eventSourceRef in s_EventSources)
{
return s_EventSources;
}
}
+
+ private void CallBackForExistingEventSources(bool addToListenersList, EventHandler<EventSourceCreatedEventArgs> callback)
+ {
+ lock (EventListenersLock)
+ {
+ // Disallow creating EventListener reentrancy.
+ if (s_CreatingListener)
+ throw new InvalidOperationException(Environment.GetResourceString("EventSource_ListenerCreatedInsideCallback"));
+
+ try
+ {
+ s_CreatingListener = true;
+
+ if (addToListenersList)
+ {
+ // Add to list of listeners in the system, do this BEFORE firing the 'OnEventSourceCreated' so that
+ // Those added sources see this listener.
+ this.m_Next = s_Listeners;
+ s_Listeners = this;
+ }
+
+ // Find all existing eventSources call OnEventSourceCreated to 'catchup'
+ // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback)
+ // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves
+ // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source
+ // is created.
+ WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray();
+
+ for (int i = 0; i < eventSourcesSnapshot.Length; i++)
+ {
+ WeakReference eventSourceRef = eventSourcesSnapshot[i];
+ EventSource eventSource = eventSourceRef.Target as EventSource;
+ if (eventSource != null)
+ {
+ EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs();
+ args.EventSource = eventSource;
+ callback(this, args);
+ }
+ }
+
+ Validate();
+ }
+ finally
+ {
+ s_CreatingListener = false;
+ }
+ }
+
+ }
// Instance fields
internal volatile EventListener m_Next; // These form a linked list in s_Listeners
#endregion
}
+ /// <summary>
+ /// EventSourceCreatedEventArgs is passed to <see cref="EventListener.EventSourceCreated"/>
+ /// </summary>
+ public class EventSourceCreatedEventArgs : EventArgs
+ {
+ /// <summary>
+ /// The EventSource that is attaching to the listener.
+ /// </summary>
+ public EventSource EventSource
+ {
+ get;
+ internal set;
+ }
+ }
+
/// <summary>
/// EventWrittenEventArgs is passed to the user-provided override for
/// <see cref="EventListener.OnEventWritten"/> when an event is fired.
}
}
- #region private
+ #region private
/// <summary>
/// Creates a new ActivityFilter that is triggered by 'eventId' from 'source' ever
ActivityFilter m_next; // We create a linked list of these
Action<Guid> m_myActivityDelegate;
- #endregion
+ #endregion
};
cultures.Add(CultureInfo.CurrentUICulture);
}
#if ES_BUILD_STANDALONE
- var sortedStrings = new List<string>(stringTab.Keys);
- sortedStrings.Sort();
+ var sortedStrings = new List<string>(stringTab.Keys);
+ sortedStrings.Sort();
#else
// DD 947936
var sortedStrings = new string[stringTab.Keys.Count];
stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\"");
string prevValue;
- if (stringTab.TryGetValue(key, out prevValue))
+ if (stringTab.TryGetValue(key, out prevValue) && !prevValue.Equals(value))
+ {
ManifestError(Environment.GetResourceString("EventSource_DuplicateStringKey", key), true);
- else
- stringTab.Add(key, value);
+ return;
+ }
+
+ stringTab[key] = value;
}
internal string GetLocalizedMessage(string key, CultureInfo ci, bool etwFormat)
{
// rest get names Channel<N>. This allows users to modify the Manifest if they want more advanced features.
if (channelTab == null)
channelTab = new Dictionary<int, ChannelInfo>(4);
-
+
string channelName = channel.ToString(); // For well know channels this is a nice name, otherwise a number
if (EventChannel.Debug < channel)
channelName = "Channel" + channelName; // Add a 'Channel' prefix for numbers.
#if !FEATURE_CORECLR
// Do security check
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, path);
#endif
return path;
** Gregorian 1912/01/01 9999/12/31
** Taiwan 01/01/01 8088/12/31
============================================================================*/
-
+
[System.Runtime.InteropServices.ComVisible(true)]
[Serializable] public class TaiwanCalendar: Calendar {
[System.Security.SecurityCritical] // auto-generated
internal static String GetDisplayablePath(String path, bool isInvalidPath)
{
-
if (String.IsNullOrEmpty(path))
return String.Empty;
- // Is it a fully qualified path?
- bool isFullyQualified = false;
if (path.Length < 2)
return path;
- if (Path.IsDirectorySeparator(path[0]) && Path.IsDirectorySeparator(path[1]))
- isFullyQualified = true;
- else if (path[1] == Path.VolumeSeparatorChar) {
- isFullyQualified = true;
- }
- if (!isFullyQualified && !isInvalidPath)
+ // Return the path as is if we're relative (not fully qualified) and not a bad path
+ if (PathInternal.IsPartiallyQualified(path) && !isInvalidPath)
return path;
-#if FEATURE_MONO_CAS
bool safeToReturn = false;
try {
if (!isInvalidPath) {
-#if !FEATURE_CORECLR
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { path }, false, false).Demand();
+#if !FEATURE_CORECLR && FEATURE_MONO_CAS
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, path, false, false);
#endif
safeToReturn = true;
}
// from Security.Util.StringExpressionSet.CanonicalizePath when ':' is found in the path
// beyond string index position 1.
}
-#else
- bool safeToReturn = !isInvalidPath;
-#endif // FEATURE_MONO_CAS
+
if (!safeToReturn) {
if (Path.IsDirectorySeparator(path[path.Length - 1]))
path = Environment.GetResourceString("IO.IO_NoPermissionToDirectoryName");
}
Contract.Assert(byteBuffer != null, "expected byteBuffer to be non-null");
- unsafe {
- fixed (byte* pBytes = byteBuffer)
- fixed (char* pChars = buffer) {
- charsRead = m_decoder.GetChars(pBytes + position, numBytes, pChars + index, charsRemaining, false);
+
+ checked {
+
+ if (position < 0 || numBytes < 0 || position + numBytes > byteBuffer.Length) {
+ throw new ArgumentOutOfRangeException("byteCount");
+ }
+
+ if (index < 0 || charsRemaining < 0 || index + charsRemaining > buffer.Length) {
+ throw new ArgumentOutOfRangeException("charsRemaining");
+ }
+
+ unsafe {
+ fixed (byte* pBytes = byteBuffer) {
+ fixed (char* pChars = buffer) {
+ charsRead = m_decoder.GetChars(pBytes + position, numBytes, pChars + index, charsRemaining, false);
+ }
+ }
}
}
Contract.Assert(_encoding.GetMaxByteCount(1) <= 16, "_encoding.GetMaxByteCount(1) <= 16)");
int numBytes = 0;
fixed(byte * pBytes = _buffer) {
- numBytes = _encoder.GetBytes(&ch, 1, pBytes, 16, true);
+ numBytes = _encoder.GetBytes(&ch, 1, pBytes, _buffer.Length, true);
}
OutStream.Write(_buffer, 0, numBytes);
}
if (_largeByteBuffer == null) {
_largeByteBuffer = new byte[LargeByteBufferSize];
- _maxChars = LargeByteBufferSize / _encoding.GetMaxByteCount(1);
+ _maxChars = _largeByteBuffer.Length / _encoding.GetMaxByteCount(1);
}
- if (len <= LargeByteBufferSize) {
+ if (len <= _largeByteBuffer.Length) {
//Contract.Assert(len == _encoding.GetBytes(chars, 0, chars.Length, _largeByteBuffer, 0), "encoding's GetByteCount & GetBytes gave different answers! encoding type: "+_encoding.GetType().Name);
_encoding.GetBytes(value, 0, value.Length, _largeByteBuffer, 0);
OutStream.Write(_largeByteBuffer, 0, len);
// Figure out how many chars to process this round.
int charCount = (numLeft > _maxChars) ? _maxChars : numLeft;
int byteLen;
- fixed(char* pChars = value) {
- fixed(byte* pBytes = _largeByteBuffer) {
- byteLen = _encoder.GetBytes(pChars + charStart, charCount, pBytes, LargeByteBufferSize, charCount == numLeft);
+
+ checked {
+ if (charStart < 0 || charCount < 0 || charStart + charCount > value.Length) {
+ throw new ArgumentOutOfRangeException("charCount");
+ }
+
+ fixed(char* pChars = value) {
+ fixed(byte* pBytes = _largeByteBuffer) {
+ byteLen = _encoder.GetBytes(pChars + charStart, charCount, pBytes, _largeByteBuffer.Length, charCount == numLeft);
+ }
}
}
#if _DEBUG
totalBytes += byteLen;
- Contract.Assert (totalBytes <= len && byteLen <= LargeByteBufferSize, "BinaryWriter::Write(String) - More bytes encoded than expected!");
+ Contract.Assert (totalBytes <= len && byteLen <= _largeByteBuffer.Length, "BinaryWriter::Write(String) - More bytes encoded than expected!");
#endif
OutStream.Write(_largeByteBuffer, 0, byteLen);
charStart += charCount;
int count = stackDir.Count;
- if (stackDir.Count != 0)
+ if (stackDir.Count != 0
+#if FEATURE_CAS_POLICY
+ // All demands in full trust domains are no-ops, so skip
+ //
+ // The full path went through validity checks by being passed through FileIOPermissions already.
+ // As a sub string of the full path can't fail the checks if the full path passes.
+ && !CodeAccessSecurityEngine.QuickCheckForAllDemands()
+#endif
+ )
{
- String [] securityList = new String[stackDir.Count];
+ String[] securityList = new String[stackDir.Count];
stackDir.CopyTo(securityList, 0);
for (int j = 0 ; j < securityList.Length; j++)
securityList[j] += "\\."; // leaf will never have a slash at the end
// Security check for all directories not present only.
-#if !FEATURE_PAL && FEATURE_MACL
+#if !FEATURE_PAL && FEATURE_MACL
AccessControlActions control = (dirSecurity == null) ? AccessControlActions.None : AccessControlActions.Change;
- new FileIOPermission(FileIOPermissionAccess.Write, control, securityList, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, control, securityList, false, false);
#else
#if FEATURE_CORECLR
if (checkHost)
}
}
#else
- new FileIOPermission(FileIOPermissionAccess.Write, securityList, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, securityList, false, false );
#endif
#endif //!FEATURE_PAL && FEATURE_MACL
}
while (stackDir.Count > 0) {
String name = stackDir[stackDir.Count - 1];
stackDir.RemoveAt(stackDir.Count - 1);
- if (name.Length >= Path.MAX_DIRECTORY_PATH)
+ if (PathInternal.IsDirectoryTooLong(name))
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
+
r = Win32Native.CreateDirectory(name, secAttrs);
if (!r && (firstError == 0)) {
int currentError = Marshal.GetLastWin32Error();
state.EnsureState();
}
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true)).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true));
#endif // FEATURE_CORECLR
errorString = name;
}
return InternalGetCurrentDirectory(false);
}
+ [System.Security.SecuritySafeCritical]
+ [ResourceExposure(ResourceScope.Machine)]
+ [ResourceConsumption(ResourceScope.Machine)]
+ private static string InternalGetCurrentDirectory(bool checkHost)
+ {
+ string currentDirectory = AppContextSwitches.UseLegacyPathHandling ? LegacyGetCurrentDirectory() : NewGetCurrentDirectory();
+ string demandPath = GetDemandDir(currentDirectory, true);
+
+#if FEATURE_CORECLR
+ if (checkHost)
+ {
+ FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath);
+ state.EnsureState();
+ }
+#else
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPath, false, false);
+#endif
+ return currentDirectory;
+ }
+
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- private static String InternalGetCurrentDirectory(bool checkHost)
+ private static string LegacyGetCurrentDirectory()
{
- StringBuilder sb = StringBuilderCache.Acquire(Path.MAX_PATH + 1);
+ StringBuilder sb = StringBuilderCache.Acquire(PathInternal.MaxShortPath + 1);
if (Win32Native.GetCurrentDirectory(sb.Capacity, sb) == 0)
__Error.WinIOError();
- String currentDirectory = sb.ToString();
+ string currentDirectory = sb.ToString();
// Note that if we have somehow put our command prompt into short
// file name mode (ie, by running edlin or a DOS grep, etc), then
// this will return a short file name.
- if (currentDirectory.IndexOf('~') >= 0) {
+ if (currentDirectory.IndexOf('~') >= 0)
+ {
int r = Win32Native.GetLongPathName(currentDirectory, sb, sb.Capacity);
- if (r == 0 || r >= Path.MAX_PATH) {
+ if (r == 0 || r >= PathInternal.MaxShortPath)
+ {
int errorCode = Marshal.GetLastWin32Error();
- if (r >= Path.MAX_PATH)
+ if (r >= PathInternal.MaxShortPath)
errorCode = Win32Native.ERROR_FILENAME_EXCED_RANGE;
if (errorCode != Win32Native.ERROR_FILE_NOT_FOUND &&
errorCode != Win32Native.ERROR_PATH_NOT_FOUND &&
errorCode != Win32Native.ERROR_INVALID_FUNCTION && // by design - enough said.
errorCode != Win32Native.ERROR_ACCESS_DENIED)
- __Error.WinIOError(errorCode, String.Empty);
+ __Error.WinIOError(errorCode, string.Empty);
}
currentDirectory = sb.ToString();
}
StringBuilderCache.Release(sb);
- String demandPath = GetDemandDir(currentDirectory, true);
+ return currentDirectory;
+ }
-
-#if FEATURE_CORECLR
- if (checkHost)
+ [System.Security.SecurityCritical]
+ [ResourceExposure(ResourceScope.Machine)]
+ [ResourceConsumption(ResourceScope.Machine)]
+ private static string NewGetCurrentDirectory()
+ {
+ using (StringBuffer buffer = new StringBuffer(PathInternal.MaxShortPath))
{
- FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath);
- state.EnsureState();
+ uint result = 0;
+ while ((result = Win32Native.GetCurrentDirectoryW(buffer.CharCapacity, buffer.GetHandle())) > buffer.CharCapacity)
+ {
+ // Reported size is greater than the buffer size. Increase the capacity.
+ // The size returned includes the null only if more space is needed (this case).
+ buffer.EnsureCharCapacity(result);
+ }
+
+ if (result == 0)
+ {
+ __Error.WinIOError();
+ }
+
+ buffer.Length = result;
+ if (buffer.Contains('~'))
+ {
+ return LongPathHelper.GetLongPathName(buffer);
+ }
+
+ return buffer.ToString();
}
-#else
- new FileIOPermission( FileIOPermissionAccess.PathDiscovery, new String[] { demandPath }, false, false ).Demand();
-#endif
- return currentDirectory;
}
-
#if FEATURE_CORECLR
[System.Security.SecurityCritical] // auto-generated
#else
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
public static void SetCurrentDirectory(String path)
- {
+ {
if (path==null)
throw new ArgumentNullException("value");
if (path.Length==0)
throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty"));
Contract.EndContractBlock();
- if (path.Length >= Path.MAX_PATH)
+
+ if (PathInternal.IsPathTooLong(path))
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
-
+
// This will have some large effects on the rest of the runtime
// and other appdomains in this process. Demand unmanaged code.
#pragma warning disable 618
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- internal static void UnsafeMove(String sourceDirName,String destDirName) {
+ internal static void UnsafeMove(String sourceDirName, String destDirName) {
InternalMove(sourceDirName, destDirName, false);
}
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- private static void InternalMove(String sourceDirName,String destDirName,bool checkHost) {
+ private static void InternalMove(String sourceDirName, String destDirName, bool checkHost) {
if (sourceDirName==null)
throw new ArgumentNullException("sourceDirName");
if (sourceDirName.Length==0)
throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "sourceDirName");
-
+
if (destDirName==null)
throw new ArgumentNullException("destDirName");
if (destDirName.Length==0)
String fullsourceDirName = Path.GetFullPathInternal(sourceDirName);
String sourcePath = GetDemandDir(fullsourceDirName, false);
-
- if (sourcePath.Length >= Path.MAX_DIRECTORY_PATH)
+
+ if (PathInternal.IsDirectoryTooLong(sourcePath))
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
String fulldestDirName = Path.GetFullPathInternal(destDirName);
String destPath = GetDemandDir(fulldestDirName, false);
- if (destPath.Length >= Path.MAX_DIRECTORY_PATH)
+ if (PathInternal.IsDirectoryTooLong(sourcePath))
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
-
+
#if FEATURE_CORECLR
if (checkHost) {
FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Write | FileSecurityStateAccess.Read, sourceDirName, sourcePath);
}
#else
// Make sure we have write permission to this directory
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandPath }, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, demandPath, false, false);
#endif
// Do not recursively delete through reparse points. Perhaps in a
state.EnsureState();
}
#else
- new FileIOPermission(FileIOPermissionAccess.Read, demandDir, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false);
#endif
FullPath = fullPath;
{
#if !FEATURE_CORECLR
demandDir = new String[] {Directory.GetDemandDir(FullPath, true)};
- new FileIOPermission(FileIOPermissionAccess.Read, demandDir, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false );
#endif
DisplayPath = GetDisplayName(OriginalPath, FullPath);
}
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery | FileSecurityStateAccess.Read, String.Empty, dir.demandDir[0]);
state.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, dir.demandDir, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, dir.demandDir, false, false);
#endif
return dir;
}
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Write, OriginalPath, demandDirForCreation);
state.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandDirForCreation }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, demandDirForCreation, false, false);
#endif
Directory.InternalCreateDirectory(fullPath, path, directorySecurity);
FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath);
sourceState.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { demandPath }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPath, false, false);
#endif
return new DirectoryInfo(rootPath);
}
FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Write | FileSecurityStateAccess.Read, DisplayPath, Directory.GetDemandDir(FullPath, true));
sourceState.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandDir, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandDir, false, false);
#endif
String fullDestDirName = Path.GetFullPathInternal(destDirName);
String demandPath;
FileSecurityState destState = new FileSecurityState(FileSecurityStateAccess.Write, destDirName, demandPath);
destState.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandPath).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandPath);
#endif
-
+
String fullSourcePath;
if (FullPath.EndsWith(Path.DirectorySeparatorChar))
fullSourcePath = FullPath;
destState.EnsureState();
backupState.EnsureState();
#else
- FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, new String[] { fullSrcPath, fullDestPath});
- if (destinationBackupFileName != null)
- perm.AddPathList(FileIOPermissionAccess.Write, fullBackupPath);
- perm.Demand();
+#if FEATURE_CAS_POLICY
+ // All demands in full trust domains are no-ops, just do additional checks
+ if (CodeAccessSecurityEngine.QuickCheckForAllDemands())
+ {
+ FileIOPermission.EmulateFileIOPermissionChecks(fullSrcPath);
+ FileIOPermission.EmulateFileIOPermissionChecks(fullDestPath);
+ if (fullBackupPath != null)
+ FileIOPermission.EmulateFileIOPermissionChecks(fullBackupPath);
+ }
+ else
+#endif
+ {
+ FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, new String[] { fullSrcPath, fullDestPath });
+ if (fullBackupPath != null)
+ perm.AddPathList(FileIOPermissionAccess.Write, fullBackupPath);
+ perm.Demand();
+ }
#endif
int flags = Win32Native.REPLACEFILE_WRITE_THROUGH;
{
#if FEATURE_MONO_CAS
#if !FEATURE_CORECLR
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { FullPath }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, FullPath, false, false);
#endif
#endif
_name = Path.GetFileName(OriginalPath);
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, DisplayPath, FullPath);
state.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { directoryName }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, directoryName, false, false);
#endif
#endif
}
state.EnsureState();
#else
// For security check, path should be resolved to an absolute path.
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { FullPath }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, FullPath, false, false);
#endif
#endif
sourceState.EnsureState();
destState.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new String[] { FullPath }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, FullPath, false, false);
FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullDestFileName, false, false);
#endif
#endif
// Get absolute path - Security needs this to prevent something
// like trying to create a file in c:\tmp with the name
// "..\WinNT\System32\ntoskrnl.exe". Store it for user convenience.
- int maxPath = useLongPath ? Path.MaxLongPath : Path.MaxPath;
- String filePath = Path.NormalizePath(path, true, maxPath);
+ int maxPath = useLongPath
+ ? PathInternal.MaxLongPath
+ : AppContextSwitches.BlockLongPaths ? PathInternal.MaxShortPath : PathInternal.MaxLongPath;
+
+ string filePath = Path.NormalizePath(path, true, maxPath);
_fileName = filePath;
// Prevent access to your disk drives as raw block devices.
- if (filePath.StartsWith("\\\\.\\", StringComparison.Ordinal))
+ //
+ // We'll allow if in full trust and not in legacy mode. You can also get device access via \\?\ and \??\ so there isn't
+ // much point in making users jump through these hoops. Blocking is pointless in full trust as well.
+ if (
+#if FEATURE_CAS_POLICY
+ (!CodeAccessSecurityEngine.QuickCheckForAllDemands() || AppContextSwitches.UseLegacyPathHandling)
+ &&
+#endif
+ filePath.StartsWith("\\\\.\\", StringComparison.Ordinal))
throw new ArgumentException(Environment.GetResourceString("Arg_DevicesNotSupported"));
- // In 4.0, we always construct a FileIOPermission object below.
- // If filePath contained a ':', we would throw a NotSupportedException in
- // System.Security.Util.StringExpressionSet.CanonicalizePath.
- // If filePath contained other illegal characters, we would throw an ArgumentException in
- // FileIOPermission.CheckIllegalCharacters.
- // In 4.5 we on longer construct the FileIOPermission object in full trust.
- // To preserve the 4.0 behavior we do an explicit check for ':' here and also call Path.CheckInvalidPathChars.
- // Note that we need to call CheckInvalidPathChars before checking for ':' because that is what FileIOPermission does.
-
- Path.CheckInvalidPathChars(filePath, true);
-
- if (filePath.IndexOf( ':', 2 ) != -1)
- throw new NotSupportedException( Environment.GetResourceString( "Argument_PathFormatNotSupported" ) );
-
bool read = false;
#if FEATURE_MACL
// All demands in full trust domains are no-ops, so skip
#if FEATURE_CAS_POLICY
- if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
+ if (CodeAccessSecurityEngine.QuickCheckForAllDemands())
+ {
+ // Need to throw the same exceptions that are thrown if we actually called QuickDemand() below.
+ FileIOPermission.EmulateFileIOPermissionChecks(filePath);
+ }
+ else
#endif // FEATURE_CAS_POLICY
{
// Build up security permissions required, as well as validate we
}
AccessControlActions control = specifiedAcl ? AccessControlActions.Change : AccessControlActions.None;
- new FileIOPermission(secAccess, control, new String[] { filePath }, false, false).Demand();
+ FileIOPermission.QuickDemand(secAccess, control, new String[] { filePath }, false, false);
#else
#if FEATURE_CORECLR
if (checkHost) {
state.EnsureState();
}
#else
- new FileIOPermission(secAccess, new String[] { filePath }, false, false).Demand();
+ FileIOPermission.QuickDemand(secAccess, filePath, false, false);
#endif // FEATURE_CORECLR
#endif
}
{
try {
#if !FEATURE_CORECLR
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, _fileName, false, false);
#endif
canGiveFullPath = true;
}
FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, _fileName);
sourceState.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, _fileName, false, false);
#endif
return _fileName;
}
state2.EnsureState();
}
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false);
#endif
// normalize search criteria
state2.EnsureState();
}
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false);
#endif
searchData = new Directory.SearchData(normalizedSearchPath, userPath, searchOption);
CommonInit();
}
#else
String demandDir = Directory.GetDemandDir(fullPathToDemand, true);
- String[] demandPaths = new String[] { demandDir };
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandDir, false, false);
#endif
}
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, name);
state.EnsureState();
#else
- String[] names = new String[] { name };
- new FileIOPermission(FileIOPermissionAccess.Read, names, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, name, false, false);
#endif
FileInfo fi = new FileInfo(name, false);
fi.InitializeFrom(result.FindData);
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName);
state.EnsureState();
#else
- String[] permissionNames = new String[] { permissionName };
- new FileIOPermission(FileIOPermissionAccess.Read, permissionNames, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, permissionName, false, false);
#endif
DirectoryInfo di = new DirectoryInfo(name, false);
di.InitializeFrom(result.FindData);
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName);
state.EnsureState();
#else
- String[] permissionNames = new String[] { permissionName };
- new FileIOPermission(FileIOPermissionAccess.Read, permissionNames, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, permissionName, false, false);
#endif
DirectoryInfo di = new DirectoryInfo(name, false);
di.InitializeFrom(result.FindData);
FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, name);
state.EnsureState();
#else
- String[] names = new String[] { name };
- new FileIOPermission(FileIOPermissionAccess.Read, names, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, name, false, false);
#endif
FileInfo fi = new FileInfo(name, false);
fi.InitializeFrom(result.FindData);
FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandDir);
sourceState.EnsureState();
#else
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandDir).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandDir);
#endif
#endif
return FullPath;
demandDir = FullPath;
#if FEATURE_MONO_CAS
#if !FEATURE_CORECLR
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandDir).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandDir);
#endif
#endif
return FullPath;
set {
#if FEATURE_MONO_CAS
#if !FEATURE_CORECLR
- new FileIOPermission(FileIOPermissionAccess.Write, FullPath).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, FullPath);
#endif
#endif
#if MONO
{
#if FEATURE_MONO_CAS
#if !FEATURE_CORECLR
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, FullPath).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, FullPath);
#endif
#endif
Contract.Requires(destFileName.Length > 0);
String fullSourceFileName = LongPath.NormalizePath(sourceFileName);
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullSourceFileName }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullSourceFileName, false, false);
String fullDestFileName = LongPath.NormalizePath(destFileName);
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { fullDestFileName }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullDestFileName, false, false);
InternalCopy(fullSourceFileName, fullDestFileName, sourceFileName, destFileName, overwrite);
}
String fullPath = LongPath.NormalizePath(path);
// For security check, path should be resolved to an absolute path.
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { fullPath }, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullPath, false, false);
String tempPath = Path.AddLongPathPrefix(fullPath);
bool r = Win32Native.DeleteFile(tempPath);
if (path.Length > 0 && Path.IsDirectorySeparator(path[path.Length - 1])) {
return false;
}
-
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { path }, false, false ).Demand();
+
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, path, false, false );
return InternalExists(path);
}
Contract.Requires(path != null);
String fullPath = LongPath.NormalizePath(path);
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false);
String tempPath = Path.AddLongPathPrefix(fullPath);
Contract.Requires(path != null);
String fullPath = LongPath.NormalizePath(path);
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false);
String tempPath = Path.AddLongPathPrefix(fullPath);
Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
Contract.Requires(path != null);
String fullPath = LongPath.NormalizePath(path);
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false);
String tempPath = Path.AddLongPathPrefix(fullPath);
Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
Contract.Requires(destFileName.Length > 0);
String fullSourceFileName = LongPath.NormalizePath(sourceFileName);
- new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new String[] { fullSourceFileName }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, fullSourceFileName, false, false);
String fullDestFileName = LongPath.NormalizePath(destFileName);
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { fullDestFileName }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullDestFileName, false, false);
if (!LongPathFile.InternalExists(fullSourceFileName))
__Error.WinIOError(Win32Native.ERROR_FILE_NOT_FOUND, fullSourceFileName);
Contract.Requires(path != null);
String fullPath = LongPath.NormalizePath(path);
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false);
String tempPath = Path.AddLongPathPrefix(fullPath);
Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
__Error.WinIOError(Win32Native.ERROR_FILE_NOT_FOUND, path);
return ((long)data.fileSizeHigh) << 32 | ((long)data.fileSizeLow & 0xFFFFFFFFL);
-
}
// Defined in WinError.h
// We attempt to create directories only after all the security checks have passed. This is avoid doing
// a demand at every level.
String demandDir = GetDemandDir(fullPath, true);
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { demandDir }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false);
InternalCreateDirectory(fullPath, path, null);
}
int count = stackDir.Count;
- if (stackDir.Count != 0)
+ if (stackDir.Count != 0
+#if FEATURE_CAS_POLICY
+ // All demands in full trust domains are no-ops, so skip
+ //
+ // The full path went through validity checks by being passed through FileIOPermissions already.
+ // As a sub string of the full path can't fail the checks if the full path passes.
+ && !CodeAccessSecurityEngine.QuickCheckForAllDemands()
+#endif
+ )
{
String[] securityList = new String[stackDir.Count];
stackDir.CopyTo(securityList, 0);
// Security check for all directories not present only.
#if !FEATURE_PAL && FEATURE_MACL
AccessControlActions control = (dirSecurity == null) ? AccessControlActions.None : AccessControlActions.Change;
- new FileIOPermission(FileIOPermissionAccess.Write, control, securityList, false, false ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, control, securityList, false, false);
#else
- new FileIOPermission(FileIOPermissionAccess.Write, securityList, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, securityList, false, false);
#endif
}
{
String name = stackDir[stackDir.Count - 1];
stackDir.RemoveAt(stackDir.Count - 1);
+
if (name.Length >= Path.MaxLongPath)
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
- r = Win32Native.CreateDirectory(Path.AddLongPathPrefix(name), secAttrs);
+
+ r = Win32Native.CreateDirectory(PathInternal.EnsureExtendedPrefix(name), secAttrs);
if (!r && (firstError == 0))
{
int currentError = Marshal.GetLastWin32Error();
// Give the user a nice error message, but don't leak path information.
try
{
- new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { GetDemandDir(name, true) }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true), false, false);
errorString = name;
}
catch (SecurityException) { }
if (destPath.Length >= Path.MaxLongPath)
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
- new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new String[] { sourcePath }, false, false).Demand();
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { destPath }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, sourcePath, false, false);
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, destPath, false, false);
if (String.Compare(sourcePath, destPath, StringComparison.OrdinalIgnoreCase) == 0)
throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustBeDifferent"));
throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustHaveSameRoot"));
- String tempSourceDirName = Path.AddLongPathPrefix(sourceDirName);
- String tempDestDirName = Path.AddLongPathPrefix(destDirName);
+ String tempSourceDirName = PathInternal.EnsureExtendedPrefix(sourceDirName);
+ String tempDestDirName = PathInternal.EnsureExtendedPrefix(destDirName);
if (!Win32Native.MoveFile(tempSourceDirName, tempDestDirName))
{
demandPath = GetDemandDir(fullPath, !recursive);
// Make sure we have write permission to this directory
- new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandPath }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, demandPath, false, false);
String longPath = Path.AddLongPathPrefix(fullPath);
// Do not recursively delete through reparse points. Perhaps in a
String fullPath = LongPath.NormalizePath(path);
String demandPath = GetDemandDir(fullPath, true);
- new FileIOPermission(FileIOPermissionAccess.Read, new String[] { demandPath }, false, false).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandPath, false, false);
return InternalExists(fullPath);
}
//
public static readonly char DirectorySeparatorChar = '\\';
internal const string DirectorySeparatorCharAsString = "\\";
-
+
// Platform specific alternate directory separator character.
// This is backslash ('\') on Unix, and slash ('/') on Windows
// and MacOS.
//
public static readonly char AltDirectorySeparatorChar = '/';
-
+
// Platform specific volume separator character. This is colon (':')
// on Windows and MacOS, and slash ('/') on Unix. This is mostly
- // useful for parsing paths like "c:\windows" or "MacVolume:System Folder".
+ // useful for parsing paths like "c:\windows" or "MacVolume:System Folder".
//
public static readonly char VolumeSeparatorChar = ':';
-
+
// Platform specific invalid list of characters in a path.
// See the "Naming a File" MSDN conceptual docs for more details on
// what is valid in a file name (which is slightly different from what
public static readonly char[] InvalidPathChars = { '\"', '<', '>', '|', '\0', (Char)1, (Char)2, (Char)3, (Char)4, (Char)5, (Char)6, (Char)7, (Char)8, (Char)9, (Char)10, (Char)11, (Char)12, (Char)13, (Char)14, (Char)15, (Char)16, (Char)17, (Char)18, (Char)19, (Char)20, (Char)21, (Char)22, (Char)23, (Char)24, (Char)25, (Char)26, (Char)27, (Char)28, (Char)29, (Char)30, (Char)31 };
// Trim trailing white spaces, tabs etc but don't be aggressive in removing everything that has UnicodeCategory of trailing space.
- // String.WhitespaceChars will trim aggressively than what the underlying FS does (for ex, NTFS, FAT).
- internal static readonly char[] TrimEndChars = { (char) 0x9, (char) 0xA, (char) 0xB, (char) 0xC, (char) 0xD, (char) 0x20, (char) 0x85, (char) 0xA0};
-
- private static readonly char[] RealInvalidPathChars = { '\"', '<', '>', '|', '\0', (Char)1, (Char)2, (Char)3, (Char)4, (Char)5, (Char)6, (Char)7, (Char)8, (Char)9, (Char)10, (Char)11, (Char)12, (Char)13, (Char)14, (Char)15, (Char)16, (Char)17, (Char)18, (Char)19, (Char)20, (Char)21, (Char)22, (Char)23, (Char)24, (Char)25, (Char)26, (Char)27, (Char)28, (Char)29, (Char)30, (Char)31 };
+ // String.WhitespaceChars will trim aggressively than what the underlying FS does (for ex, NTFS, FAT).
+ internal static readonly char[] TrimEndChars = LongPathHelper.s_trimEndChars;
+
+ private static readonly char[] RealInvalidPathChars = PathInternal.InvalidPathChars;
// This is used by HasIllegalCharacters
private static readonly char[] InvalidPathCharsWithAdditionalChecks = { '\"', '<', '>', '|', '\0', (Char)1, (Char)2, (Char)3, (Char)4, (Char)5, (Char)6, (Char)7, (Char)8, (Char)9, (Char)10, (Char)11, (Char)12, (Char)13, (Char)14, (Char)15, (Char)16, (Char)17, (Char)18, (Char)19, (Char)20, (Char)21, (Char)22, (Char)23, (Char)24, (Char)25, (Char)26, (Char)27, (Char)28, (Char)29, (Char)30, (Char)31, '*', '?' };
public static readonly char PathSeparator = ';';
-
// Make this public sometime.
// The max total path is 260, and the max individual component length is 255.
// For example, D:\<256 char file name> isn't legal, even though it's under 260 chars.
- internal static readonly int MaxPath = 260;
- private static readonly int MaxDirectoryLength = 255;
+ internal static readonly int MaxPath = PathInternal.MaxShortPath;
+ private static readonly int MaxDirectoryLength = PathInternal.MaxComponentLength;
// Windows API definitions
- internal const int MAX_PATH = 260; // From WinDef.h
- internal const int MAX_DIRECTORY_PATH = 248; // cannot create directories greater than 248 characters
+ internal const int MAX_PATH = PathInternal.MaxShortPath; // From WinDef.h
+ internal const int MAX_DIRECTORY_PATH = PathInternal.MaxShortDirectoryPath; // cannot create directories greater than 248 characters
// Changes the extension of a file path. The path parameter
// specifies a file path, and the extension parameter
return null;
}
-
// Returns the directory path of a file path. This method effectively
// removes the last element of the given file path, i.e. it returns a
// string consisting of all characters up to but not including the last
//
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
- public static String GetDirectoryName(String path) {
+ public static string GetDirectoryName(string path)
+ {
+ return InternalGetDirectoryName(path);
+ }
+
+ [ResourceExposure(ResourceScope.None)]
+ [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
+ [System.Security.SecuritySafeCritical]
+
+ private static string InternalGetDirectoryName(string path)
+ {
if (path != null) {
CheckInvalidPathChars(path);
if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
#endif
- string normalizedPath = NormalizePath(path, false);
+ // Expanding short paths is dangerous in this case as the results will change with the current directory.
+ //
+ // Suppose you have a path called "PICTUR~1\Foo". Now suppose you have two folders on disk "C:\Mine\Pictures Of Me"
+ // and "C:\Yours\Pictures of You". If the current directory is neither you'll get back "PICTUR~1". If it is "C:\Mine"
+ // get back "Pictures Of Me". "C:\Yours" would give back "Pictures of You".
+ //
+ // Because of this and as it isn't documented that short paths are expanded we will not expand short names unless
+ // we're in legacy mode.
+ string normalizedPath = NormalizePath(path, fullCheck: false, expandShortPaths: AppContextSwitches.UseLegacyPathHandling);
// If there are no permissions for PathDiscovery to this path, we should NOT expand the short paths
// as this would leak information about paths to which the user would not have access to.
- if (path.Length > 0)
+ if (path.Length > 0
+#if FEATURE_CAS_POLICY
+ // Only do the extra logic if we're not in full trust
+ && !CodeAccessSecurityEngine.QuickCheckForAllDemands()
+#endif
+ )
{
try
{
// If we were passed in a path with \\?\ we need to remove it as FileIOPermission does not like it.
- string tempPath = Path.RemoveLongPathPrefix(path);
+ string tempPath = RemoveLongPathPrefix(path);
// FileIOPermission cannot handle paths that contain ? or *
// So we only pass to FileIOPermission the text up to them.
// While we don't use the result of this call we are using it as a consistent way of
// doing the security checks.
if (pos > 0)
- Path.GetFullPath(tempPath.Substring(0, pos));
+ GetFullPath(tempPath.Substring(0, pos));
}
catch (SecurityException) {
// If the user did not have permissions to the path, make sure that we don't leak expanded short paths
// Only re-normalize if the original path had a ~ in it.
if (path.IndexOf("~", StringComparison.Ordinal) != -1)
{
- normalizedPath = NormalizePath(path, /*fullCheck*/ false, /*expandShortPaths*/ false);
+ normalizedPath = NormalizePath(path, fullCheck: false, expandShortPaths: false);
}
}
catch (PathTooLongException) { }
if (i > root) {
i = path.Length;
if (i == root) return null;
- while (i > root && path[--i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar);
+ while (i > root && path[--i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar);
String dir = path.Substring(0, i);
#if FEATURE_LEGACYNETCF
- if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
+ if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) {
if (dir.Length >= MAX_PATH - 1)
throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
- }
+ }
#endif
return dir;
}
// Gets the length of the root DirectoryInfo or whatever DirectoryInfo markers
// are specified for the first part of the DirectoryInfo name.
//
- internal static int GetRootLength(String path) {
+ internal static int GetRootLength(string path)
+ {
CheckInvalidPathChars(path);
-
+
+ if (AppContextSwitches.UseLegacyPathHandling)
+ {
+ return LegacyGetRootLength(path);
+ }
+ else
+ {
+ return PathInternal.GetRootLength(path);
+ }
+ }
+
+ private static int LegacyGetRootLength(string path)
+ {
int i = 0;
int length = path.Length;
return (c==DirectorySeparatorChar || c == AltDirectorySeparatorChar);
}
-
public static char[] GetInvalidPathChars()
{
return (char[]) RealInvalidPathChars.Clone();
throw new ArgumentNullException("path");
Contract.EndContractBlock();
- String newPath = NormalizePath(path, true);
+ string newPath = NormalizePath(path, fullCheck: true);
return newPath;
}
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- internal unsafe static String NormalizePath(String path, bool fullCheck) {
- return NormalizePath(path, fullCheck, MaxPath);
+ internal unsafe static String NormalizePath(String path, bool fullCheck)
+ {
+ return NormalizePath(path, fullCheck, AppContextSwitches.BlockLongPaths ? PathInternal.MaxShortPath : PathInternal.MaxLongPath);
}
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceConsumption(ResourceScope.Machine)]
internal unsafe static String NormalizePath(String path, bool fullCheck, bool expandShortPaths)
{
- return NormalizePath(path, fullCheck, MaxPath, expandShortPaths);
+ return NormalizePath(path, fullCheck, MaxPath, expandShortPaths: expandShortPaths);
}
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
internal unsafe static String NormalizePath(String path, bool fullCheck, int maxPathLength) {
- return NormalizePath(path, fullCheck, maxPathLength, true);
+ return NormalizePath(path, fullCheck, maxPathLength, expandShortPaths: true);
}
- [System.Security.SecurityCritical] // auto-generated
+ [System.Security.SecuritySafeCritical]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- internal unsafe static String NormalizePath(String path, bool fullCheck, int maxPathLength, bool expandShortPaths) {
+ internal static string NormalizePath(string path, bool fullCheck, int maxPathLength, bool expandShortPaths)
+ {
+ if (AppContextSwitches.UseLegacyPathHandling)
+ {
+ return LegacyNormalizePath(path, fullCheck, maxPathLength, expandShortPaths);
+ }
+ else
+ {
+ if (PathInternal.IsExtended(path))
+ {
+ // We can't really know what is valid for all cases of extended paths.
+ //
+ // - object names can include other characters as well (':', '/', etc.)
+ // - even file objects have different rules (pipe names can contain most characters)
+ //
+ // As such we will do no further analysis of extended paths to avoid blocking known and unknown
+ // scenarios as well as minimizing compat breaks should we block now and need to unblock later.
+ return path;
+ }
+
+ string normalizedPath = null;
+ if (fullCheck == false)
+ {
+ // Disabled fullCheck is only called by GetDirectoryName and GetPathRoot.
+ // Avoid adding addtional callers and try going direct to lighter weight NormalizeDirectorySeparators.
+ normalizedPath = NewNormalizePathLimitedChecks(path, maxPathLength, expandShortPaths);
+ }
+ else
+ {
+ normalizedPath = NewNormalizePath(path, maxPathLength, expandShortPaths: true);
+ }
+
+ if (string.IsNullOrWhiteSpace(normalizedPath))
+ throw new ArgumentException(Environment.GetResourceString("Arg_PathIllegal"));
+ return normalizedPath;
+ }
+ }
+
+ [System.Security.SecuritySafeCritical]
+ private static string NewNormalizePathLimitedChecks(string path, int maxPathLength, bool expandShortPaths)
+ {
+ string normalized = PathInternal.NormalizeDirectorySeparators(path);
+
+ if (PathInternal.IsPathTooLong(normalized) || PathInternal.AreSegmentsTooLong(normalized))
+ throw new PathTooLongException();
+
+ if (!PathInternal.IsDevice(normalized) && PathInternal.HasInvalidVolumeSeparator(path))
+ throw new ArgumentException(Environment.GetResourceString("Arg_PathIllegal"));
+
+ if (expandShortPaths && normalized.IndexOf('~') != -1)
+ {
+ try
+ {
+ return LongPathHelper.GetLongPathName(normalized);
+ }
+ catch
+ {
+ // Don't care if we can't get the long path- might not exist, etc.
+ }
+ }
+
+ return normalized;
+ }
+
+ /// <summary>
+ /// Normalize the path and check for bad characters or other invalid syntax.
+ /// </summary>
+ [System.Security.SecuritySafeCritical]
+ [ResourceExposure(ResourceScope.Machine)]
+ [ResourceConsumption(ResourceScope.Machine)]
+ private static string NewNormalizePath(string path, int maxPathLength, bool expandShortPaths)
+ {
Contract.Requires(path != null, "path can't be null");
- // If we're doing a full path check, trim whitespace and look for
- // illegal path characters.
- if (fullCheck) {
+
+ // Embedded null characters are the only invalid character case we want to check up front.
+ // This is because the nulls will signal the end of the string to Win32 and therefore have
+ // unpredictable results. Other invalid characters we give a chance to be normalized out.
+ if (path.IndexOf('\0') != -1)
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
+
+ // Note that colon and wildcard checks happen in FileIOPermissions
+
+ // Technically this doesn't matter but we used to throw for this case
+ if (string.IsNullOrWhiteSpace(path))
+ throw new ArgumentException(Environment.GetResourceString("Arg_PathIllegal"));
+
+ // We don't want to check invalid characters for device format- see comments for extended above
+ return LongPathHelper.Normalize(path, (uint)maxPathLength, checkInvalidCharacters: !PathInternal.IsDevice(path), expandShortPaths: expandShortPaths);
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [ResourceExposure(ResourceScope.Machine)]
+ [ResourceConsumption(ResourceScope.Machine)]
+ internal unsafe static string LegacyNormalizePath(string path, bool fullCheck, int maxPathLength, bool expandShortPaths)
+ {
+ Contract.Requires(path != null, "path can't be null");
+
+ // If we're doing a full path check, trim whitespace and look for illegal path characters.
+ if (fullCheck)
+ {
// Trim whitespace off the end of the string.
// Win32 normalization trims only U+0020.
path = path.TrimEnd(TrimEndChars);
// Look for illegal path characters.
- CheckInvalidPathChars(path);
+ if (PathInternal.AnyPathHasIllegalCharacters(path))
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
}
int index = 0;
return returnVal;
}
- internal const int MaxLongPath = 32000;
- private const string LongPathPrefix = @"\\?\";
- private const string UNCPathPrefix = @"\\";
- private const string UNCLongPathPrefixToInsert = @"?\UNC\";
- private const string UNCLongPathPrefix = @"\\?\UNC\";
+ internal const int MaxLongPath = PathInternal.MaxLongPath;
- internal unsafe static bool HasLongPathPrefix(String path)
+ private const string LongPathPrefix = PathInternal.ExtendedPathPrefix;
+ private const string UNCPathPrefix = PathInternal.UncPathPrefix;
+ private const string UNCLongPathPrefixToInsert = PathInternal.UncExtendedPrefixToInsert;
+ private const string UNCLongPathPrefix = PathInternal.UncExtendedPathPrefix;
+
+ internal static bool HasLongPathPrefix(string path)
{
- return path.StartsWith(LongPathPrefix, StringComparison.Ordinal);
+ if (AppContextSwitches.UseLegacyPathHandling)
+ return path.StartsWith(LongPathPrefix, StringComparison.Ordinal);
+ else
+ return PathInternal.IsExtended(path);
}
- internal unsafe static String AddLongPathPrefix(String path)
+ internal static string AddLongPathPrefix(string path)
{
- if (path.StartsWith(LongPathPrefix, StringComparison.Ordinal))
- return path;
+ if (AppContextSwitches.UseLegacyPathHandling)
+ {
+ if (path.StartsWith(LongPathPrefix, StringComparison.Ordinal))
+ return path;
- if (path.StartsWith(UNCPathPrefix, StringComparison.Ordinal))
- return path.Insert(2, UNCLongPathPrefixToInsert); // Given \\server\share in longpath becomes \\?\UNC\server\share => UNCLongPathPrefix + path.SubString(2); => The actual command simply reduces the operation cost.
+ if (path.StartsWith(UNCPathPrefix, StringComparison.Ordinal))
+ return path.Insert(2, UNCLongPathPrefixToInsert); // Given \\server\share in longpath becomes \\?\UNC\server\share => UNCLongPathPrefix + path.SubString(2); => The actual command simply reduces the operation cost.
- return LongPathPrefix + path;
+ return LongPathPrefix + path;
+ }
+ else
+ {
+ return PathInternal.EnsureExtendedPrefix(path);
+ }
}
- internal unsafe static String RemoveLongPathPrefix(String path)
+ internal static string RemoveLongPathPrefix(string path)
{
- if (!path.StartsWith(LongPathPrefix, StringComparison.Ordinal))
- return path;
+ if (AppContextSwitches.UseLegacyPathHandling)
+ {
+ if (!path.StartsWith(LongPathPrefix, StringComparison.Ordinal))
+ return path;
- if (path.StartsWith(UNCLongPathPrefix, StringComparison.OrdinalIgnoreCase))
- return path.Remove(2, 6); // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost.
+ if (path.StartsWith(UNCLongPathPrefix, StringComparison.OrdinalIgnoreCase))
+ return path.Remove(2, 6); // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost.
- return path.Substring(4);
+ return path.Substring(4);
+ }
+ else
+ {
+ return PathInternal.RemoveExtendedPrefix(path);
+ }
}
- internal unsafe static StringBuilder RemoveLongPathPrefix(StringBuilder pathSB)
+ internal static StringBuilder RemoveLongPathPrefix(StringBuilder pathSB)
{
- string path = pathSB.ToString();
- if (!path.StartsWith(LongPathPrefix, StringComparison.Ordinal))
- return pathSB;
+ if (AppContextSwitches.UseLegacyPathHandling)
+ {
+ if (!PathInternal.StartsWithOrdinal(pathSB, LongPathPrefix))
+ return pathSB;
- if (path.StartsWith(UNCLongPathPrefix, StringComparison.OrdinalIgnoreCase))
- return pathSB.Remove(2, 6); // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost.
+ // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost.
+ if (PathInternal.StartsWithOrdinal(pathSB, UNCLongPathPrefix, ignoreCase: true))
+ return pathSB.Remove(2, 6);
- return pathSB.Remove(0, 4);
+ return pathSB.Remove(0, 4);
+ }
+ else
+ {
+ return PathInternal.RemoveExtendedPrefix(pathSB);
+ }
}
// Returns the name and extension parts of the given path. The resulting
return null;
}
-
-
// Returns the root portion of the given path. The resulting string
// consists of those rightmost characters of the path that constitute the
// root of the path. Possible patterns for the resulting string are: An
[ResourceConsumption(ResourceScope.Machine)]
public static String GetPathRoot(String path) {
if (path == null) return null;
- path = NormalizePath(path, false);
+
+ // Expanding short paths has no impact on the path root- there is no such thing as an
+ // 8.3 volume or server/share name.
+ path = NormalizePath(path, fullCheck: false, expandShortPaths: false);
return path.Substring(0, GetRootLength(path));
}
internal static bool IsRelative(string path)
{
Contract.Assert(path != null, "path can't be null");
- if ((path.Length >= 3 && path[1] == VolumeSeparatorChar && path[2] == DirectorySeparatorChar &&
- ((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'))) ||
- (path.Length >= 2 && path[0] == '\\' && path[1] == '\\'))
- return false;
- else
- return true;
-
+ return PathInternal.IsPartiallyQualified(path);
}
-
+
// Returns a cryptographically strong random 8.3 string that can be
// used as either a folder name or a file name.
public static String GetRandomFileName()
state.EnsureState();
}
#else
- new FileIOPermission(FileIOPermissionAccess.Write, path).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, path);
#endif
StringBuilder sb = new StringBuilder(MAX_PATH);
uint r = Win32Native.GetTempFileName(path, "tmp", 0, sb);
searchPattern = searchPattern.Substring(index + 2);
}
-
- }
-
- internal static bool HasIllegalCharacters(String path, bool checkAdditional)
- {
- Contract.Requires(path != null);
-
- if (checkAdditional)
- {
- return path.IndexOfAny(InvalidPathCharsWithAdditionalChecks) >= 0;
- }
-
- return path.IndexOfAny(RealInvalidPathChars) >= 0;
}
- internal static void CheckInvalidPathChars(String path, bool checkAdditional = false)
+ internal static void CheckInvalidPathChars(string path, bool checkAdditional = false)
{
if (path == null)
throw new ArgumentNullException("path");
- if (Path.HasIllegalCharacters(path, checkAdditional))
+ if (PathInternal.HasIllegalCharacters(path, checkAdditional))
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
}
-
internal static String InternalCombine(String path1, String path2) {
if (path1==null || path2==null)
throw new ArgumentNullException((path1==null) ? "path1" : "path2");
}
}
else {
- int seekPos = unchecked(4 * _numResources);
- if (seekPos < 0) {
+ // The hexadecimal E translates to binary 1110
+ // So, with this & condition we are checking that none of the highest 3 bits are
+ // set before multiplying, as that would cause an overflow.
+ if ((_numResources & 0xE0000000) != 0){
+
throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
}
+
+ int seekPos = unchecked(4 * _numResources);
unsafe {
_nameHashesPtr = (int*)_ums.PositionPointer;
// Skip over the array of nameHashes.
}
}
else {
- int seekPos = unchecked(4 * _numResources);
- if (seekPos < 0) {
+ // The hexadecimal E translates to binary 1110
+ // So, with this & condition we are checking that none of the highest 3 bits are
+ // set before multiplying, as that would cause an overflow.
+ if ((_numResources & 0xE0000000) != 0){
throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted"));
}
+
+ int seekPos = unchecked(4 * _numResources);
unsafe {
_namePositionsPtr = (int*)_ums.PositionPointer;
// Skip over the array of namePositions.
[DllImport("api-ms-win-core-winrt-error-l1-1-1.dll", PreserveSig = false)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern IRestrictedErrorInfo GetRestrictedErrorInfo();
[DllImport("api-ms-win-core-winrt-error-l1-1-1.dll")]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern bool RoOriginateLanguageException(int error, [MarshalAs(UnmanagedType.HString)]string message, IntPtr languageException);
[DllImport("api-ms-win-core-winrt-error-l1-1-1.dll", PreserveSig = false)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern void RoReportUnhandledError(IRestrictedErrorInfo error);
[DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static unsafe extern int WindowsCreateString([MarshalAs(UnmanagedType.LPWStr)] string sourceString,
int length,
[Out] IntPtr *hstring);
[DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static unsafe extern int WindowsCreateStringReference(char *sourceString,
int length,
[Out] HSTRING_HEADER *hstringHeader,
[DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern int WindowsDeleteString(IntPtr hstring);
[DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)]
[SecurityCritical]
[SuppressUnmanagedCodeSecurity]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static unsafe extern char* WindowsGetStringRawBuffer(IntPtr hstring, [Out] uint *length);
}
}
[SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- internal void Persist( String fullPath )
+ internal void Persist(string fullPath)
{
- new FileIOPermission( FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath ).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath);
WriteLock();
[System.Security.SecuritySafeCritical] // auto-generated
[SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)]
- internal void Persist( SafeFileHandle handle, String fullPath )
+ internal void Persist(SafeFileHandle handle, string fullPath)
{
- if ( fullPath != null )
- new FileIOPermission( FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath ).Demand();
+ if (fullPath != null)
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath);
else
- new FileIOPermission( PermissionState.Unrestricted ).Demand();
+ FileIOPermission.QuickDemand(PermissionState.Unrestricted);
WriteLock();
public sealed class FileSecurity : FileSystemSecurity
{
- #region Constructors
-
[System.Security.SecuritySafeCritical] // auto-generated
public FileSecurity()
- : base( false )
+ : base(false)
{
}
[SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- public FileSecurity( String fileName, AccessControlSections includeSections )
+ public FileSecurity(string fileName, AccessControlSections includeSections)
: base(false, fileName, includeSections, false)
{
- String fullPath = Path.GetFullPathInternal(fileName);
- new FileIOPermission(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath).Demand();
+ string fullPath = Path.GetFullPathInternal(fileName);
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath, checkForDuplicates: false, needFullPath: false);
}
// Warning! Be exceedingly careful with this constructor. Do not make
[SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- internal FileSecurity( SafeFileHandle handle, String fullPath, AccessControlSections includeSections )
- : base( false, handle, includeSections, false )
+ internal FileSecurity(SafeFileHandle handle, string fullPath, AccessControlSections includeSections)
+ : base(false, handle, includeSections, false)
{
if (fullPath != null)
- new FileIOPermission(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath).Demand();
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath);
else
- new FileIOPermission(PermissionState.Unrestricted).Demand();
+ FileIOPermission.QuickDemand(PermissionState.Unrestricted);
}
-
- #endregion
}
-
public sealed class DirectorySecurity : FileSystemSecurity
{
- #region Constructors
-
[System.Security.SecuritySafeCritical] // auto-generated
public DirectorySecurity()
- : base( true )
+ : base(true)
{
}
[SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)]
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- public DirectorySecurity( String name, AccessControlSections includeSections )
- : base( true, name, includeSections, true )
+ public DirectorySecurity(string name, AccessControlSections includeSections)
+ : base(true, name, includeSections, true)
{
- String fullPath = Path.GetFullPathInternal(name);
- new FileIOPermission(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath).Demand();
+ string fullPath = Path.GetFullPathInternal(name);
+ FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath, checkForDuplicates: false, needFullPath: false);
}
-
- #endregion
}
}
//
if(!IsCircular(claimsIdentity.Actor))
{
- m_actor = claimsIdentity.Actor;
+ if (!AppContextSwitches.SetActorAsReferenceWhenCopyingClaimsIdentity)
+ {
+ m_actor = claimsIdentity.Actor.Clone();
+ }
+ else
+ {
+ m_actor = claimsIdentity.Actor;
+ }
}
else
{
else
SafeAddClaims(claimsIdentity.m_instanceClaims);
+ if (claimsIdentity.m_userSerializationData != null)
+ {
+ m_userSerializationData = claimsIdentity.m_userSerializationData.Clone() as byte[];
+ }
}
else
{
// the Actor property and so not really needed here. But checking just for sanity sake
if(!IsCircular(this.Actor))
{
- newIdentity.Actor = this.Actor;
+ if (!AppContextSwitches.SetActorAsReferenceWhenCopyingClaimsIdentity)
+ {
+ newIdentity.Actor = this.Actor.Clone();
+ }
+ else
+ {
+ newIdentity.Actor = this.Actor;
+ }
}
else
{
return;
m_instanceClaims = new List<Claim>();
+
m_externalClaims = new Collection<IEnumerable<Claim>>();
}
#endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
#if FEATURE_CRYPTO
ht.Add("System.Security.Cryptography.SHA1CryptoServiceProvider", Constants.OID_OIWSEC_SHA1);
+ ht.Add("System.Security.Cryptography.SHA1Cng", Constants.OID_OIWSEC_SHA1);
#endif //FEATURE_CRYPTO
#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
ht.Add("System.Security.Cryptography.SHA1Managed", Constants.OID_OIWSEC_SHA1);
#if FEATURE_CRYPTO
Type SHA1CryptoServiceProviderType = typeof(System.Security.Cryptography.SHA1CryptoServiceProvider);
Type MD5CryptoServiceProviderType = typeof(System.Security.Cryptography.MD5CryptoServiceProvider);
-#endif //FEATURE_CRYPTO
-#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
- Type SHA256ManagedType = typeof(SHA256Managed);
-#endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
-#if FEATURE_CRYPTO
- Type SHA384ManagedType = typeof(SHA384Managed);
- Type SHA512ManagedType = typeof(SHA512Managed);
Type RIPEMD160ManagedType = typeof(System.Security.Cryptography.RIPEMD160Managed);
Type HMACMD5Type = typeof(System.Security.Cryptography.HMACMD5);
Type HMACRIPEMD160Type = typeof(System.Security.Cryptography.HMACRIPEMD160);
#if FEATURE_CRYPTO
Type DSASignatureDescriptionType = typeof(System.Security.Cryptography.DSASignatureDescription);
Type RSAPKCS1SHA1SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA1SignatureDescription);
+ Type RSAPKCS1SHA256SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA256SignatureDescription);
+ Type RSAPKCS1SHA384SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA384SignatureDescription);
+ Type RSAPKCS1SHA512SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA512SignatureDescription);
#endif //FEATURE_CRYPTO
#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
Type RNGCryptoServiceProviderType = typeof(System.Security.Cryptography.RNGCryptoServiceProvider);
string SHA384CryptoSerivceProviderType = "System.Security.Cryptography.SHA384CryptoServiceProvider, " + AssemblyRef.SystemCore;
string SHA512CngType = "System.Security.Cryptography.SHA512Cng, " + AssemblyRef.SystemCore;
string SHA512CryptoServiceProviderType = "System.Security.Cryptography.SHA512CryptoServiceProvider, " + AssemblyRef.SystemCore;
+#endif //FEATURE_CRYPTO
+
+
+#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
+ bool fipsOnly = AllowOnlyFipsAlgorithms;
+ object SHA256DefaultType = typeof(SHA256Managed);
+#endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
+
+#if FEATURE_CRYPTO
+ if (fipsOnly)
+ {
+ SHA256DefaultType = SHA256CngType;
+ }
+ object SHA384DefaultType = fipsOnly ? (object)SHA384CngType : (object)typeof(SHA384Managed);
+ object SHA512DefaultType = fipsOnly ? (object)SHA512CngType : (object)typeof(SHA512Managed);
// Cryptography algorithms in System.Security
string DpapiDataProtectorType = "System.Security.Cryptography.DpapiDataProtector, " + AssemblyRef.SystemSecurity;
-
#endif //FEATURE_CRYPTO
+
#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
// Random number generator
ht.Add("RandomNumberGenerator", RNGCryptoServiceProviderType);
ht.Add("System.Security.Cryptography.MD5Cng", MD5CngType);
#endif //FEATURE_CRYPTO
#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
- ht.Add("SHA256", SHA256ManagedType);
- ht.Add("SHA-256", SHA256ManagedType);
- ht.Add("System.Security.Cryptography.SHA256", SHA256ManagedType);
+ ht.Add("SHA256", SHA256DefaultType);
+ ht.Add("SHA-256", SHA256DefaultType);
+ ht.Add("System.Security.Cryptography.SHA256", SHA256DefaultType);
#endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
#if FEATURE_CRYPTO
ht.Add("System.Security.Cryptography.SHA256Cng", SHA256CngType);
ht.Add("System.Security.Cryptography.SHA256CryptoServiceProvider", SHA256CryptoServiceProviderType);
- ht.Add("SHA384", SHA384ManagedType);
- ht.Add("SHA-384", SHA384ManagedType);
- ht.Add("System.Security.Cryptography.SHA384", SHA384ManagedType);
+ ht.Add("SHA384", SHA384DefaultType);
+ ht.Add("SHA-384", SHA384DefaultType);
+ ht.Add("System.Security.Cryptography.SHA384", SHA384DefaultType);
ht.Add("System.Security.Cryptography.SHA384Cng", SHA384CngType);
ht.Add("System.Security.Cryptography.SHA384CryptoServiceProvider", SHA384CryptoSerivceProviderType);
- ht.Add("SHA512", SHA512ManagedType);
- ht.Add("SHA-512", SHA512ManagedType);
- ht.Add("System.Security.Cryptography.SHA512", SHA512ManagedType);
+ ht.Add("SHA512", SHA512DefaultType);
+ ht.Add("SHA-512", SHA512DefaultType);
+ ht.Add("System.Security.Cryptography.SHA512", SHA512DefaultType);
ht.Add("System.Security.Cryptography.SHA512Cng", SHA512CngType);
ht.Add("System.Security.Cryptography.SHA512CryptoServiceProvider", SHA512CryptoServiceProviderType);
ht.Add("RIPEMD160", RIPEMD160ManagedType);
ht.Add("System.Security.Cryptography.DSASignatureDescription", DSASignatureDescriptionType);
ht.Add("http://www.w3.org/2000/09/xmldsig#rsa-sha1", RSAPKCS1SHA1SignatureDescriptionType);
ht.Add("System.Security.Cryptography.RSASignatureDescription", RSAPKCS1SHA1SignatureDescriptionType);
+ ht.Add("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", RSAPKCS1SHA256SignatureDescriptionType);
+ ht.Add("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", RSAPKCS1SHA384SignatureDescriptionType);
+ ht.Add("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", RSAPKCS1SHA512SignatureDescriptionType);
// Xml Dsig/Enc Hash algorithms
ht.Add("http://www.w3.org/2000/09/xmldsig#sha1", SHA1CryptoServiceProviderType);
// Add the other hash algorithms introduced with XML Encryption
#endif //FEATURE_CRYPTO
#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
- ht.Add("http://www.w3.org/2001/04/xmlenc#sha256", SHA256ManagedType);
+ ht.Add("http://www.w3.org/2001/04/xmlenc#sha256", SHA256DefaultType);
#endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO
#if FEATURE_CRYPTO && !FEATURE_CORECLR
- ht.Add("http://www.w3.org/2001/04/xmlenc#sha512", SHA512ManagedType);
+ ht.Add("http://www.w3.org/2001/04/xmlenc#sha512", SHA512DefaultType);
ht.Add("http://www.w3.org/2001/04/xmlenc#ripemd160", RIPEMD160ManagedType);
// Xml Encryption symmetric keys
// Xml Dsig-more Uri's as defined in http://www.ietf.org/rfc/rfc4051.txt
ht.Add("http://www.w3.org/2001/04/xmldsig-more#md5", MD5CryptoServiceProviderType);
- ht.Add("http://www.w3.org/2001/04/xmldsig-more#sha384", SHA384ManagedType);
+ ht.Add("http://www.w3.org/2001/04/xmldsig-more#sha384", SHA384DefaultType);
ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-md5", HMACMD5Type);
ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160", HMACRIPEMD160Type);
#endif //FEATURE_CRYPTO
using System.Runtime.Serialization;
using System.Security.Util;
using System.Globalization;
+ using System.IO;
using System.Diagnostics.Contracts;
// DSAParameters is serializable so that one could pass the public parameters
return (DSA) CryptoConfig.CreateFromName(algName);
}
+ // DSA does not encode the algorithm identifier into the signature blob, therefore CreateSignature and
+ // VerifySignature do not need the HashAlgorithmName value, only SignData and VerifyData do.
abstract public byte[] CreateSignature(byte[] rgbHash);
abstract public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature);
+ protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
+ {
+ throw DerivedClassMustOverride();
+ }
+
+ public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm)
+ {
+ if (data == null) { throw new ArgumentNullException("data"); }
+
+ return SignData(data, 0, data.Length, hashAlgorithm);
+ }
+
+ public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
+ {
+ if (data == null) { throw new ArgumentNullException("data"); }
+ if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException("offset"); }
+ if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException("count"); }
+ if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
+
+ byte[] hash = HashData(data, offset, count, hashAlgorithm);
+ return CreateSignature(hash);
+ }
+
+ public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm)
+ {
+ if (data == null) { throw new ArgumentNullException("data"); }
+ if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
+
+ byte[] hash = HashData(data, hashAlgorithm);
+ return CreateSignature(hash);
+ }
+
+ public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm)
+ {
+ if (data == null) { throw new ArgumentNullException("data"); }
+
+ return VerifyData(data, 0, data.Length, signature, hashAlgorithm);
+ }
+
+ public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm)
+ {
+ if (data == null) { throw new ArgumentNullException("data"); }
+ if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException("offset"); }
+ if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException("count"); }
+ if (signature == null) { throw new ArgumentNullException("signature"); }
+ if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
+
+ byte[] hash = HashData(data, offset, count, hashAlgorithm);
+ return VerifySignature(hash, signature);
+ }
+
+ public virtual bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm)
+ {
+ if (data == null) { throw new ArgumentNullException("data"); }
+ if (signature == null) { throw new ArgumentNullException("signature"); }
+ if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); }
+
+ byte[] hash = HashData(data, hashAlgorithm);
+ return VerifySignature(hash, signature);
+ }
+
// We can provide a default implementation of FromXmlString because we require
// every DSA implementation to implement ImportParameters
// All we have to do here is parse the XML.
abstract public DSAParameters ExportParameters(bool includePrivateParameters);
abstract public void ImportParameters(DSAParameters parameters);
+
+ private static Exception DerivedClassMustOverride()
+ {
+ return new NotImplementedException(Environment.GetResourceString("NotSupported_SubclassOverride"));
+ }
+
+ internal static Exception HashAlgorithmNameNullOrEmpty()
+ {
+ return new ArgumentException(Environment.GetResourceString("Cryptography_HashAlgorithmNameNullOrEmpty"), "hashAlgorithm");
+ }
}
}
return VerifyHash(rgbHash, null, rgbSignature);
}
+ protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
+ {
+ // we're sealed and the base should have checked this before calling us
+ Contract.Assert(data != null);
+ Contract.Assert(offset >= 0 && offset <= data.Length);
+ Contract.Assert(count >= 0 && count <= data.Length - offset);
+ Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
+
+ if (hashAlgorithm != HashAlgorithmName.SHA1)
+ {
+ throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name));
+ }
+
+ return _sha1.ComputeHash(data, offset, count);
+ }
+
+ protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
+ {
+ // we're sealed and the base should have checked this before calling us
+ Contract.Assert(data != null);
+ Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
+
+ if (hashAlgorithm != HashAlgorithmName.SHA1)
+ {
+ throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name));
+ }
+
+ return _sha1.ComputeHash(data);
+ }
+
[System.Security.SecuritySafeCritical] // auto-generated
public byte[] SignHash(byte[] rgbHash, string str) {
if (rgbHash == null)
}
[System.Runtime.InteropServices.ComVisible(true)]
- public sealed class RSACryptoServiceProvider : RSA
+ public sealed partial class RSACryptoServiceProvider : RSA
, ICspAsymmetricAlgorithm
{
+#if !MONO
private int _dwKeySize;
private CspParameters _parameters;
private bool _randomKeyContainer;
private SafeProvHandle _safeProvHandle;
[System.Security.SecurityCritical] // auto-generated
private SafeKeyHandle _safeKeyHandle;
-
+#endif
private static volatile CspProviderFlags s_UseMachineKeyStore = 0;
//
// QCalls
//
-
+#if !MONO
[System.Security.SecurityCritical] // auto-generated
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
return null;
}
}
-
+#endif
public override string SignatureAlgorithm {
get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; }
}
get { return (s_UseMachineKeyStore == CspProviderFlags.UseMachineKeyStore); }
set { s_UseMachineKeyStore = (value ? CspProviderFlags.UseMachineKeyStore : 0); }
}
-
+#if !MONO
public bool PersistKeyInCsp {
[System.Security.SecuritySafeCritical] // auto-generated
get {
private static bool IsPublic(RSAParameters rsaParams) {
return (rsaParams.P == null);
}
-
+#endif
//
// Adapt new RSA abstraction to legacy RSACryptoServiceProvider surface area.
//
Contract.Assert(count >= 0 && count <= data.Length);
Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
+#if MONO
+ throw new NotImplementedException ();
+#else
using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) {
Utils.HashData(hashHandle, data, offset, count);
return Utils.EndHash(hashHandle);
}
+#endif
}
[SecuritySafeCritical]
Contract.Assert(data != null);
Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
+#if MONO
+ throw new NotImplementedException ();
+#else
using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) {
// Read the data 4KB at a time, providing similar read characteristics to a standard HashAlgorithm
byte[] buffer = new byte[4096];
return Utils.EndHash(hashHandle);
}
+#endif
}
private static int GetAlgorithmId(HashAlgorithmName hashAlgorithm) {
[System.Runtime.InteropServices.ComVisible(true)]
public class RSAOAEPKeyExchangeDeformatter : AsymmetricKeyExchangeDeformatter {
private RSA _rsaKey; // RSA Key value to do decrypt operation
+ private bool? _rsaOverridesDecrypt;
//
// public constructors
if (_rsaKey == null)
throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey"));
- if (_rsaKey is RSACryptoServiceProvider) {
- return ((RSACryptoServiceProvider) _rsaKey).Decrypt(rgbData, true);
+ if (OverridesDecrypt) {
+ return _rsaKey.Decrypt(rgbData, RSAEncryptionPadding.OaepSHA1);
} else {
return Utils.RsaOaepDecrypt(_rsaKey, SHA1.Create(), new PKCS1MaskGenerationMethod(), rgbData);
}
throw new ArgumentNullException("key");
Contract.EndContractBlock();
_rsaKey = (RSA) key;
+ _rsaOverridesDecrypt = default(bool?);
+ }
+
+ private bool OverridesDecrypt {
+ get {
+ if (!_rsaOverridesDecrypt.HasValue) {
+ _rsaOverridesDecrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Decrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) });
+ }
+ return _rsaOverridesDecrypt.Value;
+ }
}
}
}
public class RSAOAEPKeyExchangeFormatter : AsymmetricKeyExchangeFormatter {
private byte[] ParameterValue;
private RSA _rsaKey;
+ private bool? _rsaOverridesEncrypt;
private RandomNumberGenerator RngValue;
//
throw new ArgumentNullException("key");
Contract.EndContractBlock();
_rsaKey = (RSA) key;
+ _rsaOverridesEncrypt = default(bool?);
}
[System.Security.SecuritySafeCritical] // auto-generated
if (_rsaKey == null)
throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey"));
- if (_rsaKey is RSACryptoServiceProvider) {
- return ((RSACryptoServiceProvider) _rsaKey).Encrypt(rgbData, true);
+ if (OverridesEncrypt) {
+ return _rsaKey.Encrypt(rgbData, RSAEncryptionPadding.OaepSHA1);
} else {
return Utils.RsaOaepEncrypt(_rsaKey, SHA1.Create(), new PKCS1MaskGenerationMethod(), RandomNumberGenerator.Create(), rgbData);
}
public override byte[] CreateKeyExchange(byte[] rgbData, Type symAlgType) {
return CreateKeyExchange(rgbData);
}
+
+ private bool OverridesEncrypt {
+ get {
+ if (!_rsaOverridesEncrypt.HasValue) {
+ _rsaOverridesEncrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Encrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) });
+ }
+ return _rsaOverridesEncrypt.Value;
+ }
+ }
}
}
[System.Runtime.InteropServices.ComVisible(true)]
public class RSAPKCS1KeyExchangeDeformatter : AsymmetricKeyExchangeDeformatter {
RSA _rsaKey;
+ bool? _rsaOverridesDecrypt;
RandomNumberGenerator RngValue;
// Constructors
throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey"));
byte[] rgbOut;
- if (_rsaKey is RSACryptoServiceProvider) {
- rgbOut = ((RSACryptoServiceProvider) _rsaKey).Decrypt(rgbIn, false);
+ if (OverridesDecrypt) {
+ rgbOut = _rsaKey.Decrypt(rgbIn, RSAEncryptionPadding.Pkcs1);
}
else {
int i;
throw new ArgumentNullException("key");
Contract.EndContractBlock();
_rsaKey = (RSA) key;
+ _rsaOverridesDecrypt = default(bool?);
+ }
+
+ private bool OverridesDecrypt {
+ get {
+ if (!_rsaOverridesDecrypt.HasValue) {
+ _rsaOverridesDecrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Decrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) });
+ }
+ return _rsaOverridesDecrypt.Value;
+ }
}
}
}
public class RSAPKCS1KeyExchangeFormatter : AsymmetricKeyExchangeFormatter {
RandomNumberGenerator RngValue;
RSA _rsaKey;
+ bool? _rsaOverridesEncrypt;
//
// public constructors
throw new ArgumentNullException("key");
Contract.EndContractBlock();
_rsaKey = (RSA) key;
+ _rsaOverridesEncrypt = default(bool?);
}
public override byte[] CreateKeyExchange(byte[] rgbData) {
throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey"));
byte[] rgbKeyEx;
- if (_rsaKey is RSACryptoServiceProvider) {
- rgbKeyEx = ((RSACryptoServiceProvider) _rsaKey).Encrypt(rgbData, false);
+ if (OverridesEncrypt) {
+ rgbKeyEx = _rsaKey.Encrypt(rgbData, RSAEncryptionPadding.Pkcs1);
}
else {
int cb = _rsaKey.KeySize/8;
public override byte[] CreateKeyExchange(byte[] rgbData, Type symAlgType) {
return CreateKeyExchange(rgbData);
}
+
+ private bool OverridesEncrypt {
+ get {
+ if (!_rsaOverridesEncrypt.HasValue) {
+ _rsaOverridesEncrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Encrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) });
+ }
+ return _rsaOverridesEncrypt.Value;
+ }
+ }
}
}
private RSA _rsaKey; // RSA Key value to do decrypt operation
private String _strOID; // OID value for the HASH algorithm
+ private bool? _rsaOverridesVerifyHash;
//
// public constructors
throw new ArgumentNullException("key");
Contract.EndContractBlock();
_rsaKey = (RSA) key;
+ _rsaOverridesVerifyHash = default(bool?);
}
public override void SetHashAlgorithm(String strName) {
// Two cases here -- if we are talking to the CSP version or if we are talking to some other RSA provider.
if (_rsaKey is RSACryptoServiceProvider) {
+ // This path is kept around for desktop compat: in case someone is using this with a hash algorithm that's known to GetAlgIdFromOid but
+ // not from OidToHashAlgorithmName.
int calgHash = X509Utils.GetAlgIdFromOid(_strOID, OidGroup.HashAlgorithm);
return ((RSACryptoServiceProvider)_rsaKey).VerifyHash(rgbHash, calgHash, rgbSignature);
}
+ else if (OverridesVerifyHash) {
+ HashAlgorithmName hashAlgorithmName = Utils.OidToHashAlgorithmName(_strOID);
+ return _rsaKey.VerifyHash(rgbHash, rgbSignature, hashAlgorithmName, RSASignaturePadding.Pkcs1);
+ }
else {
+ // Fallback compat path for 3rd-party RSA classes that don't override VerifyHash()
+
byte[] pad = Utils.RsaPkcs1Padding(_rsaKey, CryptoConfig.EncodeOID(_strOID), rgbHash);
// Apply the public key to the signature data to get back the padded buffer actually signed.
// Compare the two buffers to see if they match; ignoring any leading zeros
return Utils.CompareBigIntArrays(_rsaKey.EncryptValue(rgbSignature), pad);
}
}
+
+ private bool OverridesVerifyHash {
+ get {
+ if (!_rsaOverridesVerifyHash.HasValue) {
+ _rsaOverridesVerifyHash = Utils.DoesRsaKeyOverride(_rsaKey, "VerifyHash", new Type[] { typeof(byte[]), typeof(byte[]), typeof(HashAlgorithmName), typeof(RSASignaturePadding) });
+ }
+ return _rsaOverridesVerifyHash.Value;
+ }
+ }
}
}
public class RSAPKCS1SignatureFormatter : AsymmetricSignatureFormatter {
private RSA _rsaKey;
private String _strOID;
+ private bool? _rsaOverridesSignHash;
//
// public constructors
throw new ArgumentNullException("key");
Contract.EndContractBlock();
_rsaKey = (RSA) key;
+ _rsaOverridesSignHash = default(bool?);
}
public override void SetHashAlgorithm(String strName) {
// Two cases here -- if we are talking to the CSP version or if we are talking to some other RSA provider.
if (_rsaKey is RSACryptoServiceProvider) {
+ // This path is kept around for desktop compat: in case someone is using this with a hash algorithm that's known to GetAlgIdFromOid but
+ // not from OidToHashAlgorithmName.
int calgHash = X509Utils.GetAlgIdFromOid(_strOID, OidGroup.HashAlgorithm);
return ((RSACryptoServiceProvider)_rsaKey).SignHash(rgbHash, calgHash);
}
+ else if (OverridesSignHash) {
+ HashAlgorithmName hashAlgorithmName = Utils.OidToHashAlgorithmName(_strOID);
+ return _rsaKey.SignHash(rgbHash, hashAlgorithmName, RSASignaturePadding.Pkcs1);
+ }
else {
+ // Fallback compat path for 3rd-party RSA classes that don't override SignHash()
+
byte[] pad = Utils.RsaPkcs1Padding(_rsaKey, CryptoConfig.EncodeOID(_strOID), rgbHash);
// Create the signature by applying the private key to the padded buffer we just created.
return _rsaKey.DecryptValue(pad);
}
}
+
+ private bool OverridesSignHash {
+ get {
+ if (!_rsaOverridesSignHash.HasValue) {
+ _rsaOverridesSignHash = Utils.DoesRsaKeyOverride(_rsaKey, "SignHash", new Type[] { typeof(byte[]), typeof(HashAlgorithmName), typeof(RSASignaturePadding) });
+ }
+ return _rsaOverridesSignHash.Value;
+ }
+ }
}
}
}
}
- internal class RSAPKCS1SHA1SignatureDescription : SignatureDescription {
- public RSAPKCS1SHA1SignatureDescription() {
- KeyAlgorithm = "System.Security.Cryptography.RSACryptoServiceProvider";
- DigestAlgorithm = "System.Security.Cryptography.SHA1CryptoServiceProvider";
+ internal abstract class RSAPKCS1SignatureDescription : SignatureDescription {
+ protected RSAPKCS1SignatureDescription(string hashAlgorithm, string digestAlgorithm) {
+ KeyAlgorithm = "System.Security.Cryptography.RSA";
+ DigestAlgorithm = digestAlgorithm;
FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter";
DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter";
+ _hashAlgorithm = hashAlgorithm;
+ }
+
+ public sealed override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) {
+ AsymmetricSignatureDeformatter item = base.CreateDeformatter(key);
+ item.SetHashAlgorithm(_hashAlgorithm);
+ return item;
}
- public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) {
- AsymmetricSignatureDeformatter item = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm);
- item.SetKey(key);
- item.SetHashAlgorithm("SHA1");
+ public sealed override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) {
+ AsymmetricSignatureFormatter item = base.CreateFormatter(key);
+ item.SetHashAlgorithm(_hashAlgorithm);
return item;
}
+
+ private string _hashAlgorithm;
+ }
+
+ internal class RSAPKCS1SHA1SignatureDescription : RSAPKCS1SignatureDescription {
+ public RSAPKCS1SHA1SignatureDescription()
+ : base("SHA1", "System.Security.Cryptography.SHA1Cng") {
+ }
+ }
+
+ internal class RSAPKCS1SHA256SignatureDescription : RSAPKCS1SignatureDescription {
+ public RSAPKCS1SHA256SignatureDescription()
+ : base("SHA256", "System.Security.Cryptography.SHA256Cng") {
+ }
+ }
+
+ internal class RSAPKCS1SHA384SignatureDescription : RSAPKCS1SignatureDescription {
+ public RSAPKCS1SHA384SignatureDescription()
+ : base("SHA384", "System.Security.Cryptography.SHA384Cng") {
+ }
+ }
+
+ internal class RSAPKCS1SHA512SignatureDescription : RSAPKCS1SignatureDescription {
+ public RSAPKCS1SHA512SignatureDescription()
+ : base("SHA512", "System.Security.Cryptography.SHA512Cng") {
+ }
}
internal class DSASignatureDescription : SignatureDescription {
{
using Microsoft.Win32;
using System.IO;
+ using System.Reflection;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[ResourceExposure(ResourceScope.None)] // Creates a process resource, but it can't be scoped.
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
internal static extern SafeHashHandle CreateHash(SafeProvHandle hProv, int algid);
+#endif
+ internal static HashAlgorithmName OidToHashAlgorithmName(string oid)
+ {
+ switch (oid)
+ {
+ case Constants.OID_OIWSEC_SHA1:
+ return HashAlgorithmName.SHA1;
+
+ case Constants.OID_OIWSEC_SHA256:
+ return HashAlgorithmName.SHA256;
+ case Constants.OID_OIWSEC_SHA384:
+ return HashAlgorithmName.SHA384;
+
+ case Constants.OID_OIWSEC_SHA512:
+ return HashAlgorithmName.SHA512;
+
+ default:
+ throw new NotSupportedException();
+ }
+ }
+
+ //
+ // Backward-compat hack for third-party RSA-derived classes:
+ //
+ // Because the SignHash()/VerifyHash()/Encrypt()/Decrypt() methods are new on RSA, we may
+ // encounter older third-party RSA-derived classes that don't override them
+ // (and if they don't override them, these methods will throw since they are effectively abstract methods that had to declared non-abstract
+ // for backward compat reasons.)
+ //
+ internal static bool DoesRsaKeyOverride(RSA rsaKey, string methodName, Type[] parameterTypes)
+ {
+ // A fast-path check for the common cases where we know we implemented the overrides.
+ Type t = rsaKey.GetType();
+ if (rsaKey is RSACryptoServiceProvider)
+ {
+#if DEBUG
+ // On checked builds, do the slow-path check anyway so it gets exercised.
+ bool foundOverride = DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes);
+ BCLDebug.Assert(foundOverride, "RSACryptoServiceProvider expected to override " + methodName);
+#endif
+ return true;
+ }
+
+ string fullName = t.FullName;
+ if (fullName == "System.Security.Cryptography.RSACng")
+ {
+#if DEBUG
+ // On checked builds, do the slow-path check anyway so it gets exercised.
+ bool foundOverride = DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes);
+ BCLDebug.Assert(foundOverride, "RSACng expected to override " + methodName);
+#endif
+ return true;
+ }
+ return DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes);
+ }
+
+ private static bool DoesRsaKeyOverrideSlowPath(Type t, string methodName, Type[] parameterTypes)
+ {
+ MethodInfo method = t.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance, null, parameterTypes, null);
+ BCLDebug.Assert(method != null, "method != null");
+ Type declaringType = method.DeclaringType;
+ if (declaringType == typeof(RSA))
+ return false;
+
+ return true;
+ }
+#if !MONO
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
if (group != OidGroup.AllGroups) {
IntPtr allGroupOidInfo = CryptFindOIDInfo(keyType, rawKey, OidGroup.AllGroups);
if (allGroupOidInfo != IntPtr.Zero) {
- return (CRYPT_OID_INFO)Marshal.PtrToStructure(fullOidInfo, typeof(CRYPT_OID_INFO));
+ return (CRYPT_OID_INFO)Marshal.PtrToStructure(allGroupOidInfo, typeof(CRYPT_OID_INFO));
}
}
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
-[Serializable]
+ [Serializable]
[Flags]
-[System.Runtime.InteropServices.ComVisible(true)]
+ [System.Runtime.InteropServices.ComVisible(true)]
public enum FileIOPermissionAccess
{
NoAccess = 0x00,
PathDiscovery = 0x08,
AllAccess = 0x0F,
}
-
-
-[System.Runtime.InteropServices.ComVisible(true)]
+
+ [System.Runtime.InteropServices.ComVisible(true)]
[Serializable]
sealed public class FileIOPermission : CodeAccessPermission, IUnrestrictedPermission, IBuiltInPermission
{
[OptionalField(VersionAdded = 2)]
private FileIOAccess m_changeAcl;
private bool m_unrestricted;
-
+
public FileIOPermission(PermissionState state)
{
if (state == PermissionState.Unrestricted)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPermissionState"));
}
}
-
+
[System.Security.SecuritySafeCritical] // auto-generated
- public FileIOPermission( FileIOPermissionAccess access, String path )
+ public FileIOPermission(FileIOPermissionAccess access, String path)
{
- VerifyAccess( access );
-
+ VerifyAccess(access);
+
String[] pathList = new String[] { path };
- AddPathList( access, pathList, false, true, false );
+ AddPathList(access, pathList, false, true, false);
}
-
+
[System.Security.SecuritySafeCritical] // auto-generated
- public FileIOPermission( FileIOPermissionAccess access, String[] pathList )
+ public FileIOPermission(FileIOPermissionAccess access, String[] pathList)
{
- VerifyAccess( access );
-
- AddPathList( access, pathList, false, true, false );
+ VerifyAccess(access);
+
+ AddPathList(access, pathList, false, true, false);
}
#if FEATURE_MACL
[System.Security.SecuritySafeCritical] // auto-generated
- public FileIOPermission( FileIOPermissionAccess access, AccessControlActions control, String path )
+ public FileIOPermission(FileIOPermissionAccess access, AccessControlActions control, String path)
{
- VerifyAccess( access );
-
+ VerifyAccess(access);
+
String[] pathList = new String[] { path };
- AddPathList( access, control, pathList, false, true, false );
+ AddPathList(access, control, pathList, false, true, false);
}
-
+
[System.Security.SecuritySafeCritical] // auto-generated
- public FileIOPermission( FileIOPermissionAccess access, AccessControlActions control, String[] pathList )
- : this( access, control, pathList, true, true )
+ public FileIOPermission(FileIOPermissionAccess access, AccessControlActions control, String[] pathList)
+ : this(access, control, pathList, true, true)
{
}
#endif
[System.Security.SecurityCritical] // auto-generated
- internal FileIOPermission( FileIOPermissionAccess access, String[] pathList, bool checkForDuplicates, bool needFullPath )
+ internal FileIOPermission(FileIOPermissionAccess access, String[] pathList, bool checkForDuplicates, bool needFullPath)
{
- VerifyAccess( access );
-
- AddPathList( access, pathList, checkForDuplicates, needFullPath, true );
+ VerifyAccess(access);
+
+ AddPathList(access, pathList, checkForDuplicates, needFullPath, true);
}
#if FEATURE_MACL
[System.Security.SecurityCritical] // auto-generated
- internal FileIOPermission( FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates, bool needFullPath )
+ internal FileIOPermission(FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates, bool needFullPath)
{
- VerifyAccess( access );
-
- AddPathList( access, control, pathList, checkForDuplicates, needFullPath, true );
+ VerifyAccess(access);
+
+ AddPathList(access, control, pathList, checkForDuplicates, needFullPath, true);
}
#endif
- public void SetPathList( FileIOPermissionAccess access, String path )
+ public void SetPathList(FileIOPermissionAccess access, String path)
{
String[] pathList;
- if(path == null)
- pathList = new String[] {};
+ if (path == null)
+ pathList = new String[] { };
else
pathList = new String[] { path };
- SetPathList( access, pathList, false );
+ SetPathList(access, pathList, false);
}
-
- public void SetPathList( FileIOPermissionAccess access, String[] pathList )
+
+ public void SetPathList(FileIOPermissionAccess access, String[] pathList)
{
- SetPathList( access, pathList, true );
+ SetPathList(access, pathList, true);
}
- internal void SetPathList( FileIOPermissionAccess access,
- String[] pathList, bool checkForDuplicates )
+ internal void SetPathList(FileIOPermissionAccess access,
+ String[] pathList, bool checkForDuplicates)
{
- SetPathList( access, AccessControlActions.None, pathList, checkForDuplicates );
+ SetPathList(access, AccessControlActions.None, pathList, checkForDuplicates);
}
[System.Security.SecuritySafeCritical] // auto-generated
- internal void SetPathList( FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates )
+ internal void SetPathList(FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates)
{
- VerifyAccess( access );
-
+ VerifyAccess(access);
+
if ((access & FileIOPermissionAccess.Read) != 0)
m_read = null;
-
+
if ((access & FileIOPermissionAccess.Write) != 0)
m_write = null;
-
+
if ((access & FileIOPermissionAccess.Append) != 0)
m_append = null;
m_viewAcl = null;
m_changeAcl = null;
#endif
-
+
m_unrestricted = false;
#if FEATURE_MACL
- AddPathList( access, control, pathList, checkForDuplicates, true, true );
+ AddPathList(access, control, pathList, checkForDuplicates, true, true);
#else
AddPathList( access, pathList, checkForDuplicates, true, true );
#endif
}
[System.Security.SecuritySafeCritical] // auto-generated
- public void AddPathList( FileIOPermissionAccess access, String path )
+ public void AddPathList(FileIOPermissionAccess access, String path)
{
String[] pathList;
- if(path == null)
- pathList = new String[] {};
+ if (path == null)
+ pathList = new String[] { };
else
pathList = new String[] { path };
- AddPathList( access, pathList, false, true, false );
+ AddPathList(access, pathList, false, true, false);
}
[System.Security.SecuritySafeCritical] // auto-generated
- public void AddPathList( FileIOPermissionAccess access, String[] pathList )
+ public void AddPathList(FileIOPermissionAccess access, String[] pathList)
{
- AddPathList( access, pathList, true, true, true );
+ AddPathList(access, pathList, true, true, true);
}
[System.Security.SecurityCritical] // auto-generated
- internal void AddPathList( FileIOPermissionAccess access, String[] pathListOrig, bool checkForDuplicates, bool needFullPath, bool copyPathList )
+ internal void AddPathList(FileIOPermissionAccess access, String[] pathListOrig, bool checkForDuplicates, bool needFullPath, bool copyPathList)
{
- AddPathList( access, AccessControlActions.None, pathListOrig, checkForDuplicates, needFullPath, copyPathList );
+ AddPathList(access, AccessControlActions.None, pathListOrig, checkForDuplicates, needFullPath, copyPathList);
}
[System.Security.SecurityCritical] // auto-generated
{
if (pathListOrig == null)
{
- throw new ArgumentNullException( "pathList" );
+ throw new ArgumentNullException("pathList");
}
if (pathListOrig.Length == 0)
{
- throw new ArgumentException( Environment.GetResourceString("Argument_EmptyPath" ));
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
}
Contract.EndContractBlock();
// @
VerifyAccess(access);
-
+
if (m_unrestricted)
return;
String[] pathList = pathListOrig;
- if(copyPathList)
+ if (copyPathList)
{
// Make a copy of pathList (in case its value changes after we check for illegal chars)
pathList = new String[pathListOrig.Length];
Array.Copy(pathListOrig, pathList, pathListOrig.Length);
}
- CheckIllegalCharacters( pathList );
+ // If we need the full path the standard illegal characters will be checked in StringExpressionSet.
+ CheckIllegalCharacters(pathList, onlyCheckExtras: needFullPath);
+
+ // StringExpressionSet will do minor normalization, trimming spaces and replacing alternate
+ // directory separators. It will make an attemt to expand short file names and will check
+ // for standard colon placement.
+ //
+ // If needFullPath is true it will call NormalizePath- which performs short name expansion
+ // and does the normal validity checks.
ArrayList pathArrayList = StringExpressionSet.CreateListFromExpressions(pathList, needFullPath);
-
+
if ((access & FileIOPermissionAccess.Read) != 0)
{
if (m_read == null)
{
m_read = new FileIOAccess();
}
- m_read.AddExpressions( pathArrayList, checkForDuplicates);
+ m_read.AddExpressions(pathArrayList, checkForDuplicates);
}
-
+
if ((access & FileIOPermissionAccess.Write) != 0)
{
if (m_write == null)
{
m_write = new FileIOAccess();
}
- m_write.AddExpressions( pathArrayList, checkForDuplicates);
+ m_write.AddExpressions(pathArrayList, checkForDuplicates);
}
-
+
if ((access & FileIOPermissionAccess.Append) != 0)
{
if (m_append == null)
{
m_append = new FileIOAccess();
}
- m_append.AddExpressions( pathArrayList, checkForDuplicates);
+ m_append.AddExpressions(pathArrayList, checkForDuplicates);
}
if ((access & FileIOPermissionAccess.PathDiscovery) != 0)
{
if (m_pathDiscovery == null)
{
- m_pathDiscovery = new FileIOAccess( true );
+ m_pathDiscovery = new FileIOAccess(true);
}
- m_pathDiscovery.AddExpressions( pathArrayList, checkForDuplicates);
+ m_pathDiscovery.AddExpressions(pathArrayList, checkForDuplicates);
}
#if FEATURE_MACL
{
m_viewAcl = new FileIOAccess();
}
- m_viewAcl.AddExpressions( pathArrayList, checkForDuplicates);
+ m_viewAcl.AddExpressions(pathArrayList, checkForDuplicates);
}
if ((control & AccessControlActions.Change) != 0)
{
m_changeAcl = new FileIOAccess();
}
- m_changeAcl.AddExpressions( pathArrayList, checkForDuplicates);
+ m_changeAcl.AddExpressions(pathArrayList, checkForDuplicates);
}
#endif
}
-
+
[SecuritySafeCritical]
- public String[] GetPathList( FileIOPermissionAccess access )
+ public String[] GetPathList(FileIOPermissionAccess access)
{
- VerifyAccess( access );
- ExclusiveAccess( access );
-
- if (AccessIsSet( access, FileIOPermissionAccess.Read ))
+ VerifyAccess(access);
+ ExclusiveAccess(access);
+
+ if (AccessIsSet(access, FileIOPermissionAccess.Read))
{
if (m_read == null)
{
}
return m_read.ToStringArray();
}
-
- if (AccessIsSet( access, FileIOPermissionAccess.Write ))
+
+ if (AccessIsSet(access, FileIOPermissionAccess.Write))
{
if (m_write == null)
{
}
return m_write.ToStringArray();
}
-
- if (AccessIsSet( access, FileIOPermissionAccess.Append ))
+
+ if (AccessIsSet(access, FileIOPermissionAccess.Append))
{
if (m_append == null)
{
}
return m_append.ToStringArray();
}
-
- if (AccessIsSet( access, FileIOPermissionAccess.PathDiscovery ))
+
+ if (AccessIsSet(access, FileIOPermissionAccess.PathDiscovery))
{
if (m_pathDiscovery == null)
{
}
// not reached
-
+
return null;
}
-
+
public FileIOPermissionAccess AllLocalFiles
{
{
if (m_unrestricted)
return FileIOPermissionAccess.AllAccess;
-
+
FileIOPermissionAccess access = FileIOPermissionAccess.NoAccess;
-
+
if (m_read != null && m_read.AllLocalFiles)
{
access |= FileIOPermissionAccess.Read;
}
-
+
if (m_write != null && m_write.AllLocalFiles)
{
access |= FileIOPermissionAccess.Write;
}
-
+
if (m_append != null && m_append.AllLocalFiles)
{
access |= FileIOPermissionAccess.Append;
{
access |= FileIOPermissionAccess.PathDiscovery;
}
-
+
return access;
}
-
+
set
{
if ((value & FileIOPermissionAccess.Read) != 0)
{
if (m_read == null)
m_read = new FileIOAccess();
-
+
m_read.AllLocalFiles = true;
}
else
if (m_read != null)
m_read.AllLocalFiles = false;
}
-
+
if ((value & FileIOPermissionAccess.Write) != 0)
{
if (m_write == null)
m_write = new FileIOAccess();
-
+
m_write.AllLocalFiles = true;
}
else
if (m_write != null)
m_write.AllLocalFiles = false;
}
-
+
if ((value & FileIOPermissionAccess.Append) != 0)
{
if (m_append == null)
m_append = new FileIOAccess();
-
+
m_append.AllLocalFiles = true;
}
else
if ((value & FileIOPermissionAccess.PathDiscovery) != 0)
{
if (m_pathDiscovery == null)
- m_pathDiscovery = new FileIOAccess( true );
-
+ m_pathDiscovery = new FileIOAccess(true);
+
m_pathDiscovery.AllLocalFiles = true;
}
else
}
}
-
+
public FileIOPermissionAccess AllFiles
{
get
{
if (m_unrestricted)
return FileIOPermissionAccess.AllAccess;
-
+
FileIOPermissionAccess access = FileIOPermissionAccess.NoAccess;
-
+
if (m_read != null && m_read.AllFiles)
{
access |= FileIOPermissionAccess.Read;
}
-
+
if (m_write != null && m_write.AllFiles)
{
access |= FileIOPermissionAccess.Write;
}
-
+
if (m_append != null && m_append.AllFiles)
{
access |= FileIOPermissionAccess.Append;
}
-
+
if (m_pathDiscovery != null && m_pathDiscovery.AllFiles)
{
access |= FileIOPermissionAccess.PathDiscovery;
return access;
}
-
+
set
{
if (value == FileIOPermissionAccess.AllAccess)
m_unrestricted = true;
return;
}
-
+
if ((value & FileIOPermissionAccess.Read) != 0)
{
if (m_read == null)
m_read = new FileIOAccess();
-
+
m_read.AllFiles = true;
}
else
if (m_read != null)
m_read.AllFiles = false;
}
-
+
if ((value & FileIOPermissionAccess.Write) != 0)
{
if (m_write == null)
m_write = new FileIOAccess();
-
+
m_write.AllFiles = true;
}
else
if (m_write != null)
m_write.AllFiles = false;
}
-
+
if ((value & FileIOPermissionAccess.Append) != 0)
{
if (m_append == null)
m_append = new FileIOAccess();
-
+
m_append.AllFiles = true;
}
else
if ((value & FileIOPermissionAccess.PathDiscovery) != 0)
{
if (m_pathDiscovery == null)
- m_pathDiscovery = new FileIOAccess( true );
-
+ m_pathDiscovery = new FileIOAccess(true);
+
m_pathDiscovery.AllFiles = true;
}
else
}
}
- }
-
+ }
+
[Pure]
- private static void VerifyAccess( FileIOPermissionAccess access )
+ private static void VerifyAccess(FileIOPermissionAccess access)
{
if ((access & ~FileIOPermissionAccess.AllAccess) != 0)
throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)access));
}
-
+
[Pure]
- private static void ExclusiveAccess( FileIOPermissionAccess access )
+ private static void ExclusiveAccess(FileIOPermissionAccess access)
{
if (access == FileIOPermissionAccess.NoAccess)
{
- throw new ArgumentException( Environment.GetResourceString("Arg_EnumNotSingleFlag") );
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumNotSingleFlag"));
}
-
- if (((int) access & ((int)access-1)) != 0)
+
+ if (((int)access & ((int)access - 1)) != 0)
{
- throw new ArgumentException( Environment.GetResourceString("Arg_EnumNotSingleFlag") );
+ throw new ArgumentException(Environment.GetResourceString("Arg_EnumNotSingleFlag"));
}
}
- private static void CheckIllegalCharacters( String[] str )
+ private static void CheckIllegalCharacters(String[] str, bool onlyCheckExtras)
{
for (int i = 0; i < str.Length; ++i)
{
- Path.CheckInvalidPathChars(str[i], true);
+ // FileIOPermission doesn't allow for normalizing across various volume names. This means "C:\" and
+ // "\\?\C:\" won't be considered correctly. In addition there are many other aliases for the volume
+ // besides "C:" such as (in one concrete example) "\\?\Harddisk0Partition2\", "\\?\HarddiskVolume6\",
+ // "\\?\Volume{d1655348-0000-0000-0000-f01500000000}\", etc.
+ //
+ // We'll continue to explicitly block extended syntax here by disallowing wildcards no matter where
+ // they occur in the string (e.g. \\?\ isn't ok)
+ if (CheckExtraPathCharacters(str[i]))
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
+
+ if (!onlyCheckExtras)
+ Path.CheckInvalidPathChars(str[i]);
}
}
- private static bool AccessIsSet( FileIOPermissionAccess access, FileIOPermissionAccess question )
+ /// <summary>
+ /// Check for ?,* and null, ignoring extended syntax.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe static bool CheckExtraPathCharacters(string path)
+ {
+ char currentChar;
+ for (int i = 0; i < path.Length; i++)
+ {
+ currentChar = path[i];
+
+ // We also check for null here as StringExpressionSet will trim it out. (Ensuring we still throw as we always have.)
+ if (currentChar == '*' || currentChar == '?' || currentChar == '\0') return true;
+ }
+ return false;
+ }
+
+ private static bool AccessIsSet(FileIOPermissionAccess access, FileIOPermissionAccess question)
{
return (access & question) != 0;
}
-
+
private bool IsEmpty()
{
return (!m_unrestricted &&
(this.m_viewAcl == null || this.m_viewAcl.IsEmpty()) &&
(this.m_changeAcl == null || this.m_changeAcl.IsEmpty()));
}
-
+
//------------------------------------------------------
//
// CODEACCESSPERMISSION IMPLEMENTATION
//
//------------------------------------------------------
-
+
public bool IsUnrestricted()
{
return m_unrestricted;
}
-
+
//------------------------------------------------------
//
// IPERMISSION IMPLEMENTATION
//
//------------------------------------------------------
-
+
public override bool IsSubsetOf(IPermission target)
{
if (target == null)
else if (this.IsUnrestricted())
return false;
else
- return ((this.m_read == null || this.m_read.IsSubsetOf( operand.m_read )) &&
- (this.m_write == null || this.m_write.IsSubsetOf( operand.m_write )) &&
- (this.m_append == null || this.m_append.IsSubsetOf( operand.m_append )) &&
- (this.m_pathDiscovery == null || this.m_pathDiscovery.IsSubsetOf( operand.m_pathDiscovery )) &&
- (this.m_viewAcl == null || this.m_viewAcl.IsSubsetOf( operand.m_viewAcl )) &&
- (this.m_changeAcl == null || this.m_changeAcl.IsSubsetOf( operand.m_changeAcl )));
+ return ((this.m_read == null || this.m_read.IsSubsetOf(operand.m_read)) &&
+ (this.m_write == null || this.m_write.IsSubsetOf(operand.m_write)) &&
+ (this.m_append == null || this.m_append.IsSubsetOf(operand.m_append)) &&
+ (this.m_pathDiscovery == null || this.m_pathDiscovery.IsSubsetOf(operand.m_pathDiscovery)) &&
+ (this.m_viewAcl == null || this.m_viewAcl.IsSubsetOf(operand.m_viewAcl)) &&
+ (this.m_changeAcl == null || this.m_changeAcl.IsSubsetOf(operand.m_changeAcl)));
}
-
+
public override IPermission Intersect(IPermission target)
{
if (target == null)
{
return target.Copy();
}
-
+
if (operand.IsUnrestricted())
{
return this.Copy();
}
-
- FileIOAccess intersectRead = this.m_read == null ? null : this.m_read.Intersect( operand.m_read );
- FileIOAccess intersectWrite = this.m_write == null ? null : this.m_write.Intersect( operand.m_write );
- FileIOAccess intersectAppend = this.m_append == null ? null : this.m_append.Intersect( operand.m_append );
- FileIOAccess intersectPathDiscovery = this.m_pathDiscovery == null ? null : this.m_pathDiscovery.Intersect( operand.m_pathDiscovery );
- FileIOAccess intersectViewAcl = this.m_viewAcl == null ? null : this.m_viewAcl.Intersect( operand.m_viewAcl );
- FileIOAccess intersectChangeAcl = this.m_changeAcl == null ? null : this.m_changeAcl.Intersect( operand.m_changeAcl );
+
+ FileIOAccess intersectRead = this.m_read == null ? null : this.m_read.Intersect(operand.m_read);
+ FileIOAccess intersectWrite = this.m_write == null ? null : this.m_write.Intersect(operand.m_write);
+ FileIOAccess intersectAppend = this.m_append == null ? null : this.m_append.Intersect(operand.m_append);
+ FileIOAccess intersectPathDiscovery = this.m_pathDiscovery == null ? null : this.m_pathDiscovery.Intersect(operand.m_pathDiscovery);
+ FileIOAccess intersectViewAcl = this.m_viewAcl == null ? null : this.m_viewAcl.Intersect(operand.m_viewAcl);
+ FileIOAccess intersectChangeAcl = this.m_changeAcl == null ? null : this.m_changeAcl.Intersect(operand.m_changeAcl);
if ((intersectRead == null || intersectRead.IsEmpty()) &&
(intersectWrite == null || intersectWrite.IsEmpty()) &&
{
return null;
}
-
+
FileIOPermission intersectPermission = new FileIOPermission(PermissionState.None);
intersectPermission.m_unrestricted = false;
intersectPermission.m_read = intersectRead;
intersectPermission.m_pathDiscovery = intersectPathDiscovery;
intersectPermission.m_viewAcl = intersectViewAcl;
intersectPermission.m_changeAcl = intersectChangeAcl;
-
+
return intersectPermission;
}
-
+
public override IPermission Union(IPermission other)
{
if (other == null)
{
throw new ArgumentException(Environment.GetResourceString("Argument_WrongType", this.GetType().FullName));
}
-
+
if (this.IsUnrestricted() || operand.IsUnrestricted())
{
- return new FileIOPermission( PermissionState.Unrestricted );
+ return new FileIOPermission(PermissionState.Unrestricted);
}
-
- FileIOAccess unionRead = this.m_read == null ? operand.m_read : this.m_read.Union( operand.m_read );
- FileIOAccess unionWrite = this.m_write == null ? operand.m_write : this.m_write.Union( operand.m_write );
- FileIOAccess unionAppend = this.m_append == null ? operand.m_append : this.m_append.Union( operand.m_append );
- FileIOAccess unionPathDiscovery = this.m_pathDiscovery == null ? operand.m_pathDiscovery : this.m_pathDiscovery.Union( operand.m_pathDiscovery );
- FileIOAccess unionViewAcl = this.m_viewAcl == null ? operand.m_viewAcl : this.m_viewAcl.Union( operand.m_viewAcl );
- FileIOAccess unionChangeAcl = this.m_changeAcl == null ? operand.m_changeAcl : this.m_changeAcl.Union( operand.m_changeAcl );
-
+
+ FileIOAccess unionRead = this.m_read == null ? operand.m_read : this.m_read.Union(operand.m_read);
+ FileIOAccess unionWrite = this.m_write == null ? operand.m_write : this.m_write.Union(operand.m_write);
+ FileIOAccess unionAppend = this.m_append == null ? operand.m_append : this.m_append.Union(operand.m_append);
+ FileIOAccess unionPathDiscovery = this.m_pathDiscovery == null ? operand.m_pathDiscovery : this.m_pathDiscovery.Union(operand.m_pathDiscovery);
+ FileIOAccess unionViewAcl = this.m_viewAcl == null ? operand.m_viewAcl : this.m_viewAcl.Union(operand.m_viewAcl);
+ FileIOAccess unionChangeAcl = this.m_changeAcl == null ? operand.m_changeAcl : this.m_changeAcl.Union(operand.m_changeAcl);
+
if ((unionRead == null || unionRead.IsEmpty()) &&
(unionWrite == null || unionWrite.IsEmpty()) &&
(unionAppend == null || unionAppend.IsEmpty()) &&
{
return null;
}
-
+
FileIOPermission unionPermission = new FileIOPermission(PermissionState.None);
unionPermission.m_unrestricted = false;
unionPermission.m_read = unionRead;
unionPermission.m_viewAcl = unionViewAcl;
unionPermission.m_changeAcl = unionChangeAcl;
- return unionPermission;
+ return unionPermission;
}
-
+
public override IPermission Copy()
{
FileIOPermission copy = new FileIOPermission(PermissionState.None);
copy.m_changeAcl = this.m_changeAcl.Copy();
}
}
- return copy;
+ return copy;
}
-
+
#if FEATURE_CAS_POLICY
public override SecurityElement ToXml()
{
- SecurityElement esd = CodeAccessPermission.CreatePermissionElement( this, "System.Security.Permissions.FileIOPermission" );
+ SecurityElement esd = CodeAccessPermission.CreatePermissionElement(this, "System.Security.Permissions.FileIOPermission");
if (!IsUnrestricted())
{
if (this.m_read != null && !this.m_read.IsEmpty())
{
- esd.AddAttribute( "Read", SecurityElement.Escape( m_read.ToString() ) );
+ esd.AddAttribute("Read", SecurityElement.Escape(m_read.ToString()));
}
if (this.m_write != null && !this.m_write.IsEmpty())
{
- esd.AddAttribute( "Write", SecurityElement.Escape( m_write.ToString() ) );
+ esd.AddAttribute("Write", SecurityElement.Escape(m_write.ToString()));
}
if (this.m_append != null && !this.m_append.IsEmpty())
{
- esd.AddAttribute( "Append", SecurityElement.Escape( m_append.ToString() ) );
+ esd.AddAttribute("Append", SecurityElement.Escape(m_append.ToString()));
}
if (this.m_pathDiscovery != null && !this.m_pathDiscovery.IsEmpty())
{
- esd.AddAttribute( "PathDiscovery", SecurityElement.Escape( m_pathDiscovery.ToString() ) );
+ esd.AddAttribute("PathDiscovery", SecurityElement.Escape(m_pathDiscovery.ToString()));
}
if (this.m_viewAcl != null && !this.m_viewAcl.IsEmpty())
{
- esd.AddAttribute( "ViewAcl", SecurityElement.Escape( m_viewAcl.ToString() ) );
+ esd.AddAttribute("ViewAcl", SecurityElement.Escape(m_viewAcl.ToString()));
}
if (this.m_changeAcl != null && !this.m_changeAcl.IsEmpty())
{
- esd.AddAttribute( "ChangeAcl", SecurityElement.Escape( m_changeAcl.ToString() ) );
+ esd.AddAttribute("ChangeAcl", SecurityElement.Escape(m_changeAcl.ToString()));
}
}
else
{
- esd.AddAttribute( "Unrestricted", "true" );
+ esd.AddAttribute("Unrestricted", "true");
}
return esd;
}
-
+
[System.Security.SecuritySafeCritical] // auto-generated
public override void FromXml(SecurityElement esd)
{
- CodeAccessPermission.ValidateElement( esd, this );
+ CodeAccessPermission.ValidateElement(esd, this);
String et;
-
+
if (XMLUtil.IsUnrestricted(esd))
{
m_unrestricted = true;
return;
}
-
-
+
+
m_unrestricted = false;
-
- et = esd.Attribute( "Read" );
+
+ et = esd.Attribute("Read");
if (et != null)
{
- m_read = new FileIOAccess( et );
+ m_read = new FileIOAccess(et);
}
else
{
m_read = null;
}
-
- et = esd.Attribute( "Write" );
+
+ et = esd.Attribute("Write");
if (et != null)
{
- m_write = new FileIOAccess( et );
+ m_write = new FileIOAccess(et);
}
else
{
m_write = null;
}
-
- et = esd.Attribute( "Append" );
+
+ et = esd.Attribute("Append");
if (et != null)
{
- m_append = new FileIOAccess( et );
+ m_append = new FileIOAccess(et);
}
else
{
m_append = null;
}
- et = esd.Attribute( "PathDiscovery" );
+ et = esd.Attribute("PathDiscovery");
if (et != null)
{
- m_pathDiscovery = new FileIOAccess( et );
+ m_pathDiscovery = new FileIOAccess(et);
m_pathDiscovery.PathDiscovery = true;
}
else
m_pathDiscovery = null;
}
- et = esd.Attribute( "ViewAcl" );
+ et = esd.Attribute("ViewAcl");
if (et != null)
{
- m_viewAcl = new FileIOAccess( et );
+ m_viewAcl = new FileIOAccess(et);
}
else
{
m_viewAcl = null;
}
- et = esd.Attribute( "ChangeAcl" );
+ et = esd.Attribute("ChangeAcl");
if (et != null)
{
- m_changeAcl = new FileIOAccess( et );
+ m_changeAcl = new FileIOAccess(et);
}
else
{
public override bool Equals(Object obj)
{
FileIOPermission perm = obj as FileIOPermission;
- if(perm == null)
+ if (perm == null)
return false;
- if(m_unrestricted && perm.m_unrestricted)
+ if (m_unrestricted && perm.m_unrestricted)
return true;
- if(m_unrestricted != perm.m_unrestricted)
+ if (m_unrestricted != perm.m_unrestricted)
return false;
- if(m_read == null)
+ if (m_read == null)
{
- if(perm.m_read != null && !perm.m_read.IsEmpty())
+ if (perm.m_read != null && !perm.m_read.IsEmpty())
return false;
}
- else if(!m_read.Equals(perm.m_read))
+ else if (!m_read.Equals(perm.m_read))
return false;
- if(m_write == null)
+ if (m_write == null)
{
- if(perm.m_write != null && !perm.m_write.IsEmpty())
- return false;
+ if (perm.m_write != null && !perm.m_write.IsEmpty())
+ return false;
}
- else if(!m_write.Equals(perm.m_write))
+ else if (!m_write.Equals(perm.m_write))
return false;
- if(m_append == null)
+ if (m_append == null)
{
- if(perm.m_append != null && !perm.m_append.IsEmpty())
- return false;
+ if (perm.m_append != null && !perm.m_append.IsEmpty())
+ return false;
}
- else if(!m_append.Equals(perm.m_append))
+ else if (!m_append.Equals(perm.m_append))
return false;
- if(m_pathDiscovery == null)
+ if (m_pathDiscovery == null)
{
- if(perm.m_pathDiscovery != null && !perm.m_pathDiscovery.IsEmpty())
- return false;
+ if (perm.m_pathDiscovery != null && !perm.m_pathDiscovery.IsEmpty())
+ return false;
}
- else if(!m_pathDiscovery.Equals(perm.m_pathDiscovery))
+ else if (!m_pathDiscovery.Equals(perm.m_pathDiscovery))
return false;
- if(m_viewAcl == null)
+ if (m_viewAcl == null)
{
- if(perm.m_viewAcl != null && !perm.m_viewAcl.IsEmpty())
- return false;
+ if (perm.m_viewAcl != null && !perm.m_viewAcl.IsEmpty())
+ return false;
}
- else if(!m_viewAcl.Equals(perm.m_viewAcl))
+ else if (!m_viewAcl.Equals(perm.m_viewAcl))
return false;
- if(m_changeAcl == null)
+ if (m_changeAcl == null)
{
- if(perm.m_changeAcl != null && !perm.m_changeAcl.IsEmpty())
- return false;
+ if (perm.m_changeAcl != null && !perm.m_changeAcl.IsEmpty())
+ return false;
}
- else if(!m_changeAcl.Equals(perm.m_changeAcl))
+ else if (!m_changeAcl.Equals(perm.m_changeAcl))
return false;
return true;
/// IMPORTANT: This method should only be used after calling GetFullPath on the path to verify
///
/// </summary>
- /// <param name="access"></param>
- /// <param name="path"></param>
- /// <param name="checkForDuplicates"></param>
- /// <param name="needFullPath"></param>
[System.Security.SecuritySafeCritical]
- internal static void QuickDemand(FileIOPermissionAccess access, string fullPath, bool checkForDuplicates, bool needFullPath)
+ internal static void QuickDemand(FileIOPermissionAccess access, string fullPath, bool checkForDuplicates = false, bool needFullPath = true)
{
if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
{
}
else
{
- //Emulate FileIOPermission checks
- Path.CheckInvalidPathChars(fullPath, true);
+ EmulateFileIOPermissionChecks(fullPath);
+ }
+ }
+
+ /// <summary>
+ /// Call this method if you don't need a the FileIOPermission for anything other than calling Demand() once.
+ ///
+ /// This method tries to verify full access before allocating a FileIOPermission object.
+ /// If full access is there, then we still have to emulate the checks that creating the
+ /// FileIOPermission object would have performed.
+ ///
+ /// IMPORTANT: This method should only be used after calling GetFullPath on the path to verify
+ ///
+ /// </summary>
+ [System.Security.SecuritySafeCritical]
+ internal static void QuickDemand(FileIOPermissionAccess access, string[] fullPathList, bool checkForDuplicates = false, bool needFullPath = true)
+ {
+ if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
+ {
+ new FileIOPermission(access, fullPathList, checkForDuplicates, needFullPath).Demand();
+ }
+ else
+ {
+ foreach (string fullPath in fullPathList)
+ {
+ EmulateFileIOPermissionChecks(fullPath);
+ }
+ }
+ }
- if (fullPath.Length > 2 && fullPath.IndexOf(':', 2) != -1)
+ [System.Security.SecuritySafeCritical]
+ internal static void QuickDemand(PermissionState state)
+ {
+ if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
+ {
+ new FileIOPermission(state).Demand();
+ }
+ }
+
+#if FEATURE_MACL
+ [System.Security.SecuritySafeCritical]
+ internal static void QuickDemand(FileIOPermissionAccess access, AccessControlActions control, string fullPath, bool checkForDuplicates = false, bool needFullPath = true)
+ {
+ if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
+ {
+ new FileIOPermission(access, control, new string[] { fullPath }, checkForDuplicates, needFullPath).Demand();
+ }
+ else
+ {
+ EmulateFileIOPermissionChecks(fullPath);
+ }
+ }
+
+ [System.Security.SecuritySafeCritical]
+ internal static void QuickDemand(FileIOPermissionAccess access, AccessControlActions control, string[] fullPathList, bool checkForDuplicates = true, bool needFullPath = true)
+ {
+ if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
+ {
+ new FileIOPermission(access, control, fullPathList, checkForDuplicates, needFullPath).Demand();
+ }
+ else
+ {
+ foreach (string fullPath in fullPathList)
{
- throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported"));
+ EmulateFileIOPermissionChecks(fullPath);
}
}
}
+#endif
+
+ /// <summary>
+ /// Perform the additional path checks that would normally happen when creating a FileIOPermission object.
+ /// </summary>
+ /// <param name="fullPath">A path that has already gone through GetFullPath or Normalize</param>
+ internal static void EmulateFileIOPermissionChecks(string fullPath)
+ {
+ // Callers should have already made checks for invalid path format via normalization. This method will only make the
+ // additional checks needed to throw the same exceptions that would normally throw when using FileIOPermission.
+ // These checks are done via CheckIllegalCharacters() and StringExpressionSet in AddPathList() above.
+ //
+ // We have to check the beginning as some paths may be passed in as path + @"\.", which will be normalized away.
+ BCLDebug.Assert(
+ fullPath.StartsWith(Path.NormalizePath(fullPath, fullCheck: false), StringComparison.OrdinalIgnoreCase),
+ string.Format("path isn't normalized: {0}", fullPath));
+
+ // Checking for colon / invalid characters on device paths blocks legitimate access to objects such as named pipes.
+ if (AppContextSwitches.UseLegacyPathHandling || !PathInternal.IsDevice(fullPath))
+ {
+ // GetFullPath already checks normal invalid path characters. We need to just check additional (wildcard) characters here.
+ // (By calling the standard helper we can allow extended paths \\?\ through when the support is enabled.)
+ if (PathInternal.HasWildCardCharacters(fullPath))
+ {
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars"));
+ }
+ if (PathInternal.HasInvalidVolumeSeparator(fullPath))
+ {
+ throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported"));
+ }
+ }
+ }
}
-
+
[Serializable]
internal sealed class FileIOAccess
{
// Public methods.
//
[SecuritySafeCritical]
+ [DynamicSecurityMethodAttribute()]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public static void RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Action action)
{
if (action == null)
}
[SecuritySafeCritical]
+ [DynamicSecurityMethodAttribute()]
+ [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
public static T RunImpersonated<T>(SafeAccessTokenHandle safeAccessTokenHandle, Func<T> func)
{
if (func == null)
throw new ArgumentNullException( "str" );
}
Contract.EndContractBlock();
+
ArrayList retArrayList = new ArrayList();
for (int index = 0; index < str.Length; ++index)
{
if (str[index] == null)
throw new ArgumentNullException( "str" );
+ // Replace alternate directory separators
String oneString = StaticProcessWholeString( str[index] );
if (oneString != null && oneString.Length != 0)
{
- String temp = StaticProcessSingleString( oneString);
+ // Trim leading and trailing spaces
+ String temp = StaticProcessSingleString(oneString);
- int indexOfNull = temp.IndexOf( '\0' );
+ int indexOfNull = temp.IndexOf('\0');
if (indexOfNull != -1)
- temp = temp.Substring( 0, indexOfNull );
+ temp = temp.Substring(0, indexOfNull);
if (temp != null && temp.Length != 0)
{
- if (Path.IsRelative(temp))
+ if (PathInternal.IsPartiallyQualified(temp))
{
- throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) );
+ throw new ArgumentException(Environment.GetResourceString("Argument_AbsolutePathRequired"));
}
temp = CanonicalizePath( temp, needFullPath );
-
retArrayList.Add( temp );
}
}
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
- internal static String CanonicalizePath( String path, bool needFullPath )
+ internal static string CanonicalizePath(string path, bool needFullPath)
{
- if (path.IndexOf( '~' ) != -1)
- {
- string longPath = null;
- GetLongPathName(path, JitHelpers.GetStringHandleOnStack(ref longPath));
- path = (longPath != null) ? longPath : path;
- }
-
- if (path.IndexOf( ':', 2 ) != -1)
- throw new NotSupportedException( Environment.GetResourceString( "Argument_PathFormatNotSupported" ) );
-
if (needFullPath)
{
- String newPath = System.IO.Path.GetFullPathInternal( path );
- if (path.EndsWith( m_directorySeparator + ".", StringComparison.Ordinal ))
+ string newPath = Path.GetFullPathInternal(path);
+ if (path.EndsWith(m_directorySeparator + ".", StringComparison.Ordinal))
{
- if (newPath.EndsWith( m_directorySeparator ))
+ if (newPath.EndsWith(m_directorySeparator))
{
newPath += ".";
}
{
newPath += m_directorySeparator + ".";
}
- }
- return newPath;
+ }
+ path = newPath;
}
- else
- return path;
+ else if (path.IndexOf('~') != -1)
+ {
+ // GetFullPathInternal() will expand 8.3 file names
+ string longPath = null;
+ GetLongPathName(path, JitHelpers.GetStringHandleOnStack(ref longPath));
+ path = (longPath != null) ? longPath : path;
+ }
+
+ // This blocks usage of alternate data streams and some extended syntax paths (\\?\C:\). Checking after
+ // normalization allows valid paths such as " C:\" to be considered ok (as it will become "C:\").
+ if (path.IndexOf(':', 2) != -1)
+ throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported"));
+
+ return path;
}
}
}
// 3. Throws a PathTooLongException if the length of the resulting URL is >= MAX_PATH.
// This is done to prevent security issues due to canonicalization truncations.
// Remove this method when the Path class supports "\\?\"
- internal static String PreProcessForExtendedPathRemoval(String url, bool isFileUrl)
+ internal static string PreProcessForExtendedPathRemoval(string url, bool isFileUrl)
{
- bool uncShare = false;
- return PreProcessForExtendedPathRemoval(url, isFileUrl, ref uncShare);
+ return PreProcessForExtendedPathRemoval(checkPathLength: true, url: url, isFileUrl: isFileUrl);
}
- private static String PreProcessForExtendedPathRemoval(String url, bool isFileUrl, ref bool isUncShare)
+ internal static string PreProcessForExtendedPathRemoval(bool checkPathLength, string url, bool isFileUrl)
+ {
+ bool isUncShare = false;
+ return PreProcessForExtendedPathRemoval(checkPathLength: checkPathLength, url: url, isFileUrl: isFileUrl, isUncShare: ref isUncShare);
+ }
+
+ // Keeping this signature to avoid reflection breaks
+ private static string PreProcessForExtendedPathRemoval(string url, bool isFileUrl, ref bool isUncShare)
+ {
+ return PreProcessForExtendedPathRemoval(checkPathLength: true, url: url, isFileUrl: isFileUrl, isUncShare: ref isUncShare);
+ }
+
+ private static string PreProcessForExtendedPathRemoval(bool checkPathLength, string url, bool isFileUrl, ref bool isUncShare)
{
// This is the modified URL that we will return
StringBuilder modifiedUrl = new StringBuilder(url);
}
// ITEM 3 - If the path is greater than or equal (due to terminating NULL in windows) MAX_PATH, we throw.
- if (modifiedUrl.Length >= Path.MAX_PATH)
+ if (checkPathLength)
{
- throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
+ // This needs to be a separate method to avoid hitting the static constructor on AppContextSwitches
+ CheckPathTooLong(modifiedUrl);
}
// Create the result string from the StringBuilder
return modifiedUrl.ToString();
}
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void CheckPathTooLong(StringBuilder path)
+ {
+ if (path.Length >= (AppContextSwitches.BlockLongPaths ? PathInternal.MaxShortPath : PathInternal.MaxLongPath))
+ {
+ throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong"));
+ }
+ }
// Do any misc massaging of data in the URL
private String PreProcessURL(String url, bool isFileURL)
VerifyClassInvariant();
- if ((minBlockCharCount + Length) > m_MaxCapacity)
+ if (minBlockCharCount + Length < minBlockCharCount || (minBlockCharCount + Length) > m_MaxCapacity)
throw new ArgumentOutOfRangeException("requiredLength", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
// Compute the length of the new block we need
VerifyClassInvariant();
Contract.Assert(count > 0, "Count must be strictly positive");
Contract.Assert(index >= 0, "Index can't be negative");
- if (count + Length > m_MaxCapacity)
+
+ if (count + Length < count || count + Length > m_MaxCapacity)
throw new ArgumentOutOfRangeException("requiredLength", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
chunk = this;
ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction;
if (singleTaskCompletionAction != null)
{
- singleTaskCompletionAction.Invoke(this);
+ if (bCanInlineContinuations)
+ {
+ singleTaskCompletionAction.Invoke(this);
+ }
+ else
+ {
+ ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false);
+ }
LogFinishCompletionNotification();
return;
}
{
Contract.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction");
var action = (ITaskCompletionAction)currentContinuation;
- action.Invoke(this);
+
+ if (bCanInlineContinuations)
+ {
+ action.Invoke(this);
+ }
+ else
+ {
+ ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(action, this), forceGlobal: false);
+ }
}
}
}
}
}
+ internal sealed class CompletionActionInvoker : IThreadPoolWorkItem
+ {
+ private readonly ITaskCompletionAction m_action;
+ private readonly Task m_completingTask;
+
+ internal CompletionActionInvoker(ITaskCompletionAction action, Task completingTask)
+ {
+ m_action = action;
+ m_completingTask = completingTask;
+ }
+
+ [SecurityCritical]
+ public void ExecuteWorkItem()
+ {
+ m_action.Invoke(m_completingTask);
+ }
+
+ [SecurityCritical]
+ public void MarkAborted(ThreadAbortException tae)
+ {
+ /* NOP */
+ }
+ }
+
// Proxy class for better debugging experience
internal class SystemThreadingTasks_TaskDebugView
{
using System.Security.Permissions;
using Mono.Security.Cryptography;
using Mono.CompilerServices.SymbolWriter;
+using System.Linq;
#if STATIC
using IKVM.Reflection;
byte[] GetPublicKeyToken ();
bool IsFriendAssemblyTo (IAssemblyDefinition assembly);
}
+
+ public class AssemblyReferenceErrorInfo
+ {
+ public AssemblyReferenceErrorInfo (AssemblyName dependencyName, string location, string message)
+ {
+ this.DependencyName = dependencyName;
+ this.RequestingAssemblyLocation = location;
+ this.Message = message;
+ }
+
+ public AssemblyName DependencyName { get; private set; }
+ public string RequestingAssemblyLocation { get; private set; }
+ public string Message { get; private set; }
+ }
public abstract class AssemblyDefinition : IAssemblyDefinition
{
//
void CheckReferencesPublicToken ()
{
- foreach (var an in builder_extra.GetReferencedAssemblies ()) {
+ var references = builder_extra.GetReferencedAssemblies ();
+ foreach (var an in references) {
if (public_key != null && an.GetPublicKey ().Length == 0) {
Report.Error (1577, "Referenced assembly `{0}' does not have a strong name",
an.FullName);
if (ia == null)
continue;
- var references = GetNotUnifiedReferences (an);
- if (references != null) {
- foreach (var r in references) {
- Report.SymbolRelatedToPreviousError ( r[0]);
- Report.Error (1705, r [1]);
+ var an_references = GetNotUnifiedReferences (an);
+ if (an_references != null) {
+ foreach (var r in an_references) {
+ //
+ // Secondary check when assembly references is resolved but not used. For example
+ // due to type-forwarding
+ //
+ if (references.Any (l => l.Name == r.DependencyName.Name)) {
+ Report.SymbolRelatedToPreviousError (r.RequestingAssemblyLocation);
+ Report.Error (1705, r.Message);
+ }
}
}
return public_key_token;
}
- protected virtual List<string[]> GetNotUnifiedReferences (AssemblyName assemblyName)
+ protected virtual List<AssemblyReferenceErrorInfo> GetNotUnifiedReferences (AssemblyName assemblyName)
{
return null;
}
return Builder.__AddModule (moduleFile);
}
- protected override List<string[]> GetNotUnifiedReferences (AssemblyName assemblyName)
+ protected override List<AssemblyReferenceErrorInfo> GetNotUnifiedReferences (AssemblyName assemblyName)
{
return loader.GetNotUnifiedReferences (assemblyName);
}
Assembly corlib;
readonly List<Tuple<AssemblyName, string, Assembly>> loaded_names;
static readonly Dictionary<string, string[]> sdk_directory;
- Dictionary<AssemblyName, List<string[]>> resolved_version_mismatches;
+ Dictionary<AssemblyName, List<AssemblyReferenceErrorInfo>> resolved_version_mismatches;
static readonly TypeName objectTypeName = new TypeName ("System", "Object");
static StaticLoader ()
if (version_mismatch is AssemblyBuilder)
return version_mismatch;
- var v1 = new AssemblyName (refname).Version;
+ var ref_an = new AssemblyName (refname);
+ var v1 = ref_an.Version;
var v2 = version_mismatch.GetName ().Version;
if (v1 > v2) {
if (resolved_version_mismatches == null)
- resolved_version_mismatches = new Dictionary<AssemblyName, List<string[]>> ();
+ resolved_version_mismatches = new Dictionary<AssemblyName, List<AssemblyReferenceErrorInfo>> ();
var an = args.RequestingAssembly.GetName ();
- List<string[]> names;
+ List<AssemblyReferenceErrorInfo> names;
if (!resolved_version_mismatches.TryGetValue (an, out names)) {
- names = new List<string[]> ();
+ names = new List<AssemblyReferenceErrorInfo> ();
resolved_version_mismatches.Add (an, names);
}
- names.Add (new[] {
- args.RequestingAssembly.Location,
+ names.Add (new AssemblyReferenceErrorInfo (ref_an, args.RequestingAssembly.Location,
string.Format ("Assembly `{0}' depends on `{1}' which has a higher version number than referenced assembly `{2}'",
- args.RequestingAssembly.FullName, refname, version_mismatch.GetName ().FullName)
- });
+ args.RequestingAssembly.FullName, refname, version_mismatch.GetName ().FullName)));
return version_mismatch;
}
return default_references.ToArray ();
}
- public List<string[]> GetNotUnifiedReferences (AssemblyName assemblyName)
+ public List<AssemblyReferenceErrorInfo> GetNotUnifiedReferences (AssemblyName assemblyName)
{
- List<string[]> list = null;
+ List<AssemblyReferenceErrorInfo> list = null;
if (resolved_version_mismatches != null)
resolved_version_mismatches.TryGetValue (assemblyName, out list);
setup:
$(CSCOMPILE) -t:library dlls/test-679-2/test-679-lib-2.cs
$(CSCOMPILE) -t:library dlls/test-679-1/test-679-lib.cs -r:dlls/test-679-2/test-679-lib-2.dll
+ $(CSCOMPILE) -t:library dlls/test-939-common.cs -keyfile:key.snk -publicsign
+ $(CSCOMPILE) -t:library dlls/test-939-1/test-939-lib.cs -keyfile:key.snk -publicsign
+ $(CSCOMPILE) -t:library dlls/test-939-1/test-939-ref.cs -r:dlls/test-939-1/test-939-lib.dll -keyfile:key.snk -publicsign
+ $(CSCOMPILE) -t:library dlls/test-939-2/test-939-lib.cs -r:dlls/test-939-common.dll -keyfile:key.snk -publicsign
$(ILASM) -dll dlls/test-883.il
--- /dev/null
+[assembly:System.Reflection.AssemblyVersionAttribute ("2.1.0.0")]
+
+public class Common
+{
+ public static void Foo ()
+ {
+
+ }
+}
--- /dev/null
+[assembly:System.Reflection.AssemblyVersionAttribute ("4.0.0.0")]
+
+public class A : Common
+{
+}
+
+public class B
+{
+
+}
--- /dev/null
+using System.Runtime.CompilerServices;
+
+[assembly:System.Reflection.AssemblyVersionAttribute ("2.0.0.0")]
+
+[assembly:TypeForwardedTo (typeof (Common))]
--- /dev/null
+[assembly:System.Reflection.AssemblyVersionAttribute ("1.0.0.0")]
+
+public class Common
+{
+ public static void Foo ()
+ {
+
+ }
+}
--- /dev/null
+// Compiler options: -r:dlls/test-939-1/test-939-ref.dll -r:dlls/test-939-2/test-939-lib.dll -r:dlls/test-939-common.dll
+
+class X
+{
+ public static void Main ()
+ {
+ }
+
+ static void RealTest ()
+ {
+ A.Foo ();
+ new B ();
+ }
+}
\ No newline at end of file
class X
{
static ManualResetEvent dispose = new ManualResetEvent (false);
+ static ManualResetEvent wait = new ManualResetEvent (false);
static IEnumerable GetIt2 ()
{
static int Delay ()
{
dispose.Set ();
- Thread.Sleep (10);
+ wait.WaitOne ();
return 1;
}
ThreadPool.QueueUserWorkItem (l => {
dispose.WaitOne ();
((IDisposable) e).Dispose ();
+ wait.Set ();
});
if (!e.MoveNext ())
</method>
</type>
</test>
+ <test name="test-939.cs">
+ <type name="X">
+ <method name="Void Main()" attrs="150">
+ <size>2</size>
+ </method>
+ <method name="Void RealTest()" attrs="145">
+ <size>13</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-94.cs">
<type name="Base">
<method name="Int32 IVehicle.Start()" attrs="481">
<test name="test-iter-23.cs">
<type name="X">
<method name="Int32 Delay()" attrs="145">
- <size>28</size>
+ <size>32</size>
</method>
<method name="Int32 Main()" attrs="150">
<size>141</size>
<size>7</size>
</method>
<method name="Void .cctor()" attrs="6289">
- <size>12</size>
+ <size>23</size>
</method>
</type>
<type name="X+<GetIt2>c__Iterator0">
</type>
<type name="X+<Main>c__AnonStorey1">
<method name="Void <>m__0(System.Object)" attrs="131">
- <size>29</size>
+ <size>40</size>
</method>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-addNonGeneric-v2.dll
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-addNonGeneric-v2.dll
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-addNonGeneric-v2.dll
- diff --exclude=.svn -rup Test/en.expected-addNonGeneric Test/en.actual
+ diff -rup Test/en.expected-addNonGeneric Test/en.actual
check-monodocer-dropns-classic: $(PROGRAM)
# tests the simplest --dropns case, a single class where the root namespace was dropped.
$(MAKE) Test/DocTest-DropNS-classic.dll
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic.dll --api-style=classic
$(MAKE) update-monodocer-dropns-unified
- diff --exclude=.svn -rup Test/en.expected-dropns-classic-v1 Test/en.actual
+ diff -rup Test/en.expected-dropns-classic-v1 Test/en.actual
check-monodocer-dropns-multi: $(PROGRAM)
-rm -Rf Test/en.actual
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual $(MULTI-CLASSIC) --api-style=classic
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual $(MULTI-UNIFIED) --api-style=unified --dropns Test/DocTest-DropNS-unified.dll=MyFramework --dropns Test/DocTest-DropNS-unified-multitest.dll=MyFramework
- diff --exclude=.svn -rup Test/en.expected-dropns-multi Test/en.actual
+ diff -rup Test/en.expected-dropns-multi Test/en.actual
check-monodocer-dropns-multi-withexisting: $(PROGRAM)
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual $(MULTI-CLASSIC) --api-style=classic
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual $(MULTI-UNIFIED) --api-style=unified --dropns Test/DocTest-DropNS-unified.dll=MyFramework --dropns Test/DocTest-DropNS-unified-multitest.dll=MyFramework
- diff --exclude=.svn -rup Test/en.expected-dropns-multi-withexisting Test/en.actual
+ diff -rup Test/en.expected-dropns-multi-withexisting Test/en.actual
check-monodocer-dropns-delete: $(PROGRAM)
-rm -Rf Test/en.actual
$(MONO) $(PROGRAM) update --delete --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic-deletetest.dll --api-style=classic
$(MAKE) Test/DocTest-DropNS-unified-deletetest-V2.dll
$(MONO) $(PROGRAM) update --delete --exceptions=all -o Test/en.actual Test/DocTest-DropNS-unified-deletetest.dll --api-style=unified --dropns Test/DocTest-DropNS-unified-deletetest.dll=MyFramework
- diff --exclude=.dvn -rup Test/en.expected-dropns-delete Test/en.actual
+ diff -rup Test/en.expected-dropns-delete Test/en.actual
check-monodocer-dropns-classic-withsecondary: $(PROGRAM)
# tests case where a secondary assembly is included with a --dropns parameter
$(MAKE) Test/DocTest-DropNS-classic-secondary.dll
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-DropNS-classic.dll Test/DocTest-DropNS-classic-secondary.dll --api-style=classic
$(MAKE) update-monodocer-dropns-unified-withsecondary
- diff --exclude=.svn -rup Test/en.expected-dropns-classic-withsecondary Test/en.actual
+ diff -rup Test/en.expected-dropns-classic-withsecondary Test/en.actual
update-monodocer-dropns-unified: $(PROGRAM)
$(MAKE) Test/DocTest-DropNS-unified.dll
-rm -Rf Test/en.actual
$(MAKE) Test/DocTest-InternalInterface.dll
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-InternalInterface.dll
- diff --exclude=.svn -rup Test/en.expected-internal-interface Test/en.actual
+ diff -rup Test/en.expected-internal-interface Test/en.actual
check-monodocer-enumerations: $(PROGRAM)
-rm -Rf Test/en.actual
$(MAKE) Test/DocTest-enumerations.dll
$(MONO) $(PROGRAM) update --exceptions=all -o Test/en.actual Test/DocTest-enumerations.dll
- diff --exclude=.svn -rup Test/en.expected-enumerations Test/en.actual
+ diff -rup Test/en.expected-enumerations Test/en.actual
check-monodocer-update: $(PROGRAM)
find Test/en.expected -name \*.xml -exec rm "{}" \;
-rm -Rf Test/en.actual
$(MAKE) Test/DocTest.dll-v1
$(MONO) $(PROGRAM) update --debug --exceptions=all -o Test/en.actual Test/DocTest.dll
- diff --exclude=.svn -rup Test/en.expected Test/en.actual
+ diff -rup Test/en.expected Test/en.actual
$(MONO) $(PROGRAM) update --debug --exceptions=all -o Test/en.actual Test/DocTest.dll
- diff --exclude=.svn -rup Test/en.expected Test/en.actual
+ diff -rup Test/en.expected Test/en.actual
check-monodocer-since-update: $(PROGRAM)
find Test/en.expected.since -name \*.xml -exec rm "{}" \;
$(MAKE) Test/DocTest.dll-v2
$(MONO) $(PROGRAM) --debug update --exceptions=all --since="Version 2.0" \
-o Test/en.actual Test/DocTest.dll
- diff --exclude=.svn -rup Test/en.expected.since Test/en.actual
+ diff -rup Test/en.expected.since Test/en.actual
check-monodocer-delete-update: $(PROGRAM)
find Test/en.expected.delete -type f -exec rm "{}" \;
$(MONO) $(PROGRAM) --debug update --exceptions=all -o Test/en.actual Test/DocTest.dll
$(MAKE) Test/DocTest.dll-v1
$(MONO) $(PROGRAM) --debug update -fno-assembly-versions --delete --exceptions=all -o Test/en.actual Test/DocTest.dll
- diff --exclude=.svn -rup Test/en.expected.delete Test/en.actual
+ diff -rup Test/en.expected.delete Test/en.actual
check-monodocer-importslashdoc-update: $(PROGRAM)
find Test/en.expected.importslashdoc -name \*.xml -exec rm "{}" \;
$(MAKE) Test/DocTest.dll-v1 TEST_CSCFLAGS=-doc:Test/DocTest.xml
$(MONO) $(PROGRAM) --debug update --exceptions=all -i Test/DocTest.xml \
-o Test/en.actual Test/DocTest.dll
- diff --exclude=.svn -rup Test/en.expected.importslashdoc Test/en.actual
+ diff -rup Test/en.expected.importslashdoc Test/en.actual
check-monodocer-importecmadoc-update: $(PROGRAM)
find Test/en.expected.importecmadoc -name \*.xml -exec rm "{}" \;
'--type=System.Action`1' --type=System.AsyncCallback \
--type=System.Environment --type=System.Array \
-o Test/en.actual Test/DocTest.dll
- diff --exclude=.svn -rup Test/en.expected.importecmadoc Test/en.actual
+ diff -rup Test/en.expected.importecmadoc Test/en.actual
check-mdoc-export-html-update: $(PROGRAM)
find Test/html.expected -name \*.html -exec rm "{}" \;
rm -Rf Test/html.actual
$(MONO) $(PROGRAM) export-html -o Test/html.actual \
Test/en.expected.importslashdoc
- diff --exclude=.svn -rup Test/html.expected Test/html.actual
+ diff -rup Test/html.expected Test/html.actual
check-mdoc-export-html-with-version: $(PROGRAM)
rm -Rf Test/html.actual.v0 Test/html.actual.since-with-v0 .v0.txt .v2.txt
check-md-html-dir: $(PROGRAM)
rm -Rf Test/html.actual
$(MONO) $(PROGRAM) export-html -dest:Test/html.actual $(DIR)
- diff --exclude=.svn -rup Test/html.expected Test/html.actual
+ diff -rup Test/html.expected Test/html.actual
check-mdoc-export-msxdoc-update:
$(MONO) $(PROGRAM) export-msxdoc -o - Test/en.expected.importslashdoc \
}
- if (!quiet) {
- Console.WriteLine (os_message);
- Console.WriteLine ("Sources: {0} Auto-dependencies: {1}", sources.Count, autodeps);
- }
- if (sources.Count == 0 || output == null) {
- Help ();
- Environment.Exit (1);
- }
-
- List<string> assemblies = LoadAssemblies (sources);
- List<string> files = new List<string> ();
- foreach (string file in assemblies)
- if (!QueueAssembly (files, file))
- return 1;
-
if (fetch_target != null){
var truntime = Path.Combine (targets_dir, fetch_target, "mono");
Directory.CreateDirectory (Path.GetDirectoryName (truntime));
var wc = new WebClient ();
var uri = new Uri ($"{target_server}{fetch_target}");
try {
+ if (!quiet){
+ Console.WriteLine ($"Downloading runtime {uri} to {truntime}");
+ }
+
wc.DownloadFile (uri, truntime);
} catch {
Console.Error.WriteLine ($"Failure to download the specified runtime from {uri}");
return 0;
}
+ if (!quiet) {
+ Console.WriteLine (os_message);
+ Console.WriteLine ("Sources: {0} Auto-dependencies: {1}", sources.Count, autodeps);
+ }
+
+ if (sources.Count == 0 || output == null) {
+ Help ();
+ Environment.Exit (1);
+ }
+
+ List<string> assemblies = LoadAssemblies (sources);
+ List<string> files = new List<string> ();
+ foreach (string file in assemblies)
+ if (!QueueAssembly (files, file))
+ return 1;
+
if (custom_mode)
GenerateBundles (files);
else {
if (cross_target == "default")
runtime = null;
else {
- string truntime;
- if (runtime != null)
- truntime = runtime;
- else {
+ if (runtime == null){
if (cross_target == null){
Console.Error.WriteLine ("you should specify either a --runtime or a --cross compilation target");
Environment.Exit (1);
}
- truntime = Path.Combine (targets_dir, cross_target, "mono");
- }
- if (!File.Exists (truntime)){
- Console.Error.WriteLine ($"The runtime for the {cross_target} does not exist, use --fetch-target {cross_target} to download first");
- return 1;
+ runtime = Path.Combine (targets_dir, cross_target, "mono");
+ if (!File.Exists (runtime)){
+ Console.Error.WriteLine ($"The runtime for the {cross_target} does not exist, use --fetch-target {cross_target} to download first");
+ return 1;
+ }
+ } else {
+ if (!File.Exists (runtime)){
+ Console.Error.WriteLine ($"The Mono runtime specified with --runtime does not exist");
+ return 1;
+ }
}
- }
+
+ Console.WriteLine ("Using runtime {0}", runtime);
+ }
GeneratePackage (files);
}
{
SourceAssembly = source.GetAttribute ("name");
TargetAssembly = target.GetAttribute ("name");
- // TODO: version
+
+ var sb = source.GetAttribute ("version");
+ var tb = target.GetAttribute ("version");
+ if (sb != tb) {
+ Output.WriteLine ("<h4>Assembly Version Changed: {0} vs {1}</h4>", tb, sb);
+ }
+
// ? custom attributes ?
comparer.Compare (source, target);
}
// Example usage: -exclude:category1,category2 this command can be used
// in combination with the -include option also note that exclude takes priority
// over all includes
- public static void Main(string[] args)
+ public static int Main(string[] args)
{
- new TextUI().Execute(args);
+ var runner = new TextUI();
+ runner.Execute(args);
+
+ return (runner.Failure ? 1 : 0);
}
}
}
mono_register_jit_icall (func, name, sig, save);
}
+gpointer
+mono_string_to_bstr(MonoString* ptr)
+{
+ if (!ptr)
+ return NULL;
+
+ return mono_ptr_to_bstr(mono_string_chars(ptr), mono_string_length(ptr));
+}
+
#ifndef DISABLE_COM
#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
}
gpointer
-mono_string_to_bstr (MonoString *string_obj)
+mono_ptr_to_bstr(gpointer ptr, int slen)
{
- if (!string_obj)
+ if (!ptr)
return NULL;
#ifdef HOST_WIN32
- return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
+ return SysAllocStringLen (ptr, slen);
#else
if (com_provider == MONO_COM_DEFAULT) {
- int slen = mono_string_length (string_obj);
/* allocate len + 1 utf16 characters plus 4 byte integer for length*/
- char *ret = (char *)g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
+ char *ret = (char *)g_malloc((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
if (ret == NULL)
return NULL;
- memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
- * ((guint32 *) ret) = slen * sizeof(gunichar2);
- ret [4 + slen * sizeof(gunichar2)] = 0;
- ret [5 + slen * sizeof(gunichar2)] = 0;
+ memcpy(ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
+ *((guint32 *)ret) = slen * sizeof(gunichar2);
+ ret[4 + slen * sizeof(gunichar2)] = 0;
+ ret[5 + slen * sizeof(gunichar2)] = 0;
return ret + 4;
- } else if (com_provider == MONO_COM_MS && init_com_provider_ms ()) {
+ }
+ else if (com_provider == MONO_COM_MS && init_com_provider_ms()) {
gpointer ret = NULL;
gunichar* str = NULL;
- guint32 len;
- len = mono_string_length (string_obj);
- str = g_utf16_to_ucs4 (mono_string_chars (string_obj), len,
+ guint32 len = slen;
+ str = g_utf16_to_ucs4(ptr, len,
NULL, NULL, NULL);
- ret = sys_alloc_string_len_ms (str, len);
+ ret = sys_alloc_string_len_ms(str, len);
g_free(str);
return ret;
- } else {
- g_assert_not_reached ();
+ }
+ else {
+ g_assert_not_reached();
}
#endif
}
}
gpointer
-mono_string_to_bstr (MonoString *string_obj)
+mono_ptr_to_bstr (gpointer ptr, int slen)
{
- if (!string_obj)
+ if (!ptr)
return NULL;
#ifdef HOST_WIN32
- return SysAllocStringLen (mono_string_chars (string_obj), mono_string_length (string_obj));
+ return SysAllocStringLen (ptr, slen);
#else
{
- int slen = mono_string_length (string_obj);
/* allocate len + 1 utf16 characters plus 4 byte integer for length*/
char *ret = g_malloc ((slen + 1) * sizeof(gunichar2) + sizeof(guint32));
if (ret == NULL)
return NULL;
- memcpy (ret + sizeof(guint32), mono_string_chars (string_obj), slen * sizeof(gunichar2));
+ memcpy (ret + sizeof(guint32), ptr, slen * sizeof(gunichar2));
* ((guint32 *) ret) = slen * sizeof(gunichar2);
ret [4 + slen * sizeof(gunichar2)] = 0;
ret [5 + slen * sizeof(gunichar2)] = 0;
return mono_string_to_bstr(ptr);
}
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray* ptr, int len)
+{
+ return mono_ptr_to_bstr (ptr->vector, len);
+}
+
void
ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR (gpointer ptr)
{
#define TYPED_HANDLE_NAME(TYPE) TYPE ## Handle
/*
+ * TYPED_HANDLE_DECL(SomeType):
+ * Expands to a decl for handles to SomeType and to an internal payload struct.
+ *
+ * For example, TYPED_HANDLE_DECL(MonoObject) (see below) expands to:
+ *
* typedef struct {
* MonoObject *__obj;
* } MonoObjectHandlePayload;
* typedef MonoObjectHandlePayload* MonoObjectHandle;
*/
#define TYPED_HANDLE_DECL(TYPE) typedef struct { TYPE *__obj; } TYPED_HANDLE_PAYLOAD_NAME (TYPE) ; typedef TYPED_HANDLE_PAYLOAD_NAME (TYPE) * TYPED_HANDLE_NAME (TYPE)
-#define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_STRUCT_OFFSET(TYPED_HANDLE_PAYLOAD_NAME (TYPE), __obj)
+/* Have to double expand because MONO_STRUCT_OFFSET is doing token pasting on cross-compilers. */
+#define MONO_HANDLE_PAYLOAD_OFFSET_(PayloadType) MONO_STRUCT_OFFSET(PayloadType, __obj)
+#define MONO_HANDLE_PAYLOAD_OFFSET(TYPE) MONO_HANDLE_PAYLOAD_OFFSET_(TYPED_HANDLE_PAYLOAD_NAME (TYPE))
#define MONO_HANDLE_INIT ((void*) mono_null_value_handle)
#define NULL_HANDLE mono_null_value_handle
#endif
ICALL(MARSHAL_2, "AllocCoTaskMem", ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem)
ICALL(MARSHAL_3, "AllocHGlobal", ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal)
+ICALL(MARSHAL_50, "BufferToBSTR", ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR)
ICALL(MARSHAL_4, "DestroyStructure", ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure)
ICALL(MARSHAL_5, "FreeBSTR", ves_icall_System_Runtime_InteropServices_Marshal_FreeBSTR)
ICALL(MARSHAL_6, "FreeCoTaskMem", ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem)
ICALL(MARSHAL_33, "StringToHGlobalUni", ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni)
ICALL(MARSHAL_34, "StructureToPtr", ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr)
ICALL(MARSHAL_35, "UnsafeAddrOfPinnedArrayElement", ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement)
+
ICALL(MARSHAL_41, "copy_from_unmanaged", ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged)
ICALL(MARSHAL_42, "copy_to_unmanaged", ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged)
#else
/* it wasn't found in the static call tables */
if (!imap) {
+ if (uses_handles)
+ *uses_handles = FALSE;
mono_icall_unlock ();
return NULL;
}
MonoClass *error_class;
int thread_info_var = -1, stack_mark_var = -1, error_var = -1;
MonoMethodSignature *call_sig = csig;
- gboolean uses_handles;
+ gboolean uses_handles = FALSE;
(void) mono_lookup_internal_call_full (method, &uses_handles);
mono_string_to_ansibstr (MonoString *string_obj);
gpointer
-mono_string_to_bstr (MonoString *string_obj);
+mono_ptr_to_bstr (gpointer ptr, int slen);
+
+gpointer
+mono_string_to_bstr(MonoString* str);
void mono_delegate_free_ftnptr (MonoDelegate *delegate);
gpointer
ves_icall_System_Runtime_InteropServices_Marshal_StringToBSTR (MonoString *string);
+gpointer
+ves_icall_System_Runtime_InteropServices_Marshal_BufferToBSTR (MonoArray *ptr, int len);
+
gpointer
ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string);
#include <mono/metadata/class-internals.h>
#include <mono/metadata/object-internals.h>
#include <mono/metadata/monitor.h>
+#include <mono/metadata/handle.h>
#ifdef HAVE_SGEN_GC
#include <mono/sgen/sgen-gc.h>
#endif
LOCK_DEBUG (g_message ("%s: Finalizing sync %p", __func__, mon));
if (mon->entry_sem != NULL) {
- CloseHandle (mon->entry_sem);
+ mono_coop_sem_destroy (mon->entry_sem);
+ g_free (mon->entry_sem);
mon->entry_sem = NULL;
}
/* If this isn't empty then something is seriously broken - it
tmp_status = InterlockedCompareExchange ((gint32*)&mon->status, new_status, old_status);
if (tmp_status == old_status) {
if (have_waiters)
- ReleaseSemaphore (mon->entry_sem, 1, NULL);
+ mono_coop_sem_post (mon->entry_sem);
break;
}
old_status = tmp_status;
HANDLE sem;
gint64 then = 0, now, delta;
guint32 waitms;
- guint32 ret;
guint32 new_status, old_status, tmp_status;
+ MonoSemTimedwaitRet wait_ret;
MonoInternalThread *thread;
gboolean interrupted = FALSE;
*/
if (mon->entry_sem == NULL) {
/* Create the semaphore */
- sem = CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
- g_assert (sem != NULL);
+ sem = g_new0 (MonoCoopSem, 1);
+ mono_coop_sem_init (sem, 0);
if (InterlockedCompareExchangePointer ((gpointer*)&mon->entry_sem, sem, NULL) != NULL) {
/* Someone else just put a handle here */
- CloseHandle (sem);
+ mono_coop_sem_destroy (sem);
+ g_free (sem);
}
}
mono_thread_set_state (thread, ThreadState_WaitSleepJoin);
/*
- * We pass TRUE instead of allow_interruption since we have to check for the
+ * We pass ALERTABLE instead of allow_interruption since we have to check for the
* StopRequested case below.
*/
- MONO_ENTER_GC_SAFE;
- ret = WaitForSingleObjectEx (mon->entry_sem, waitms, TRUE);
- MONO_EXIT_GC_SAFE;
+ wait_ret = mono_coop_sem_timedwait (mon->entry_sem, waitms, MONO_SEM_FLAGS_ALERTABLE);
mono_thread_clr_state (thread, ThreadState_WaitSleepJoin);
mono_perfcounters->thread_queue_len--;
#endif
- if (ret == WAIT_IO_COMPLETION && !allow_interruption) {
+ if (wait_ret == MONO_SEM_TIMEDWAIT_RET_ALERTED && !allow_interruption) {
interrupted = TRUE;
/*
* We have to obey a stop/suspend request even if
/* retry from the top */
goto retry_contended;
}
- } else if (ret == WAIT_OBJECT_0) {
+ } else if (wait_ret == MONO_SEM_TIMEDWAIT_RET_SUCCESS) {
interrupted = FALSE;
/* retry from the top */
goto retry_contended;
- } else if (ret == WAIT_TIMEOUT) {
+ } else if (wait_ret == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) {
/* we're done */
}
mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL);
- if (ret == WAIT_IO_COMPLETION) {
+ if (wait_ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) {
LOCK_DEBUG (g_message ("%s: (%d) interrupted waiting, returning -1", __func__, id));
return -1;
- } else if (ret == WAIT_TIMEOUT) {
+ } else if (wait_ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) {
LOCK_DEBUG (g_message ("%s: (%d) timed out waiting, returning FALSE", __func__, id));
return 0;
} else {
#include <glib.h>
#include <mono/metadata/object.h>
#include <mono/io-layer/io-layer.h>
-#include "mono/utils/mono-compiler.h"
+#include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-coop-semaphore.h>
G_BEGIN_DECLS
#ifdef HAVE_MOVING_COLLECTOR
gint32 hash_code;
#endif
- HANDLE entry_sem;
GSList *wait_list;
void *data;
+ MonoCoopSem *entry_sem;
};
/*
DECL_OFFSET(MonoObject, vtable)
DECL_OFFSET(MonoObject, synchronisation)
+DECL_OFFSET(MonoObjectHandlePayload, __obj)
+
DECL_OFFSET(MonoClass, interface_bitmap)
DECL_OFFSET(MonoClass, byval_arg)
DECL_OFFSET(MonoClass, cast_class)
guint real_offset;
GSList *seq_points;
+
+ // The MonoInst of the last sequence point for the current basic block.
MonoInst *last_seq_point;
+
+ // This will hold a list of last sequence points of incoming basic blocks
+ MonoInst **pred_seq_points;
+ guint num_pred_seq_points;
GSList *spill_slot_defs;
#include "seq-points.h"
static void
-collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
+insert_pred_seq_point (MonoInst *last_seq_ins, MonoInst *ins, GSList **next)
{
- int i;
MonoBasicBlock *in_bb;
GSList *l;
+ int src_index = last_seq_ins->backend.size;
+ int dst_index = ins->backend.size;
+
+ /* bb->in_bb might contain duplicates */
+ for (l = next [src_index]; l; l = l->next)
+ if (GPOINTER_TO_UINT (l->data) == dst_index)
+ break;
+ if (!l)
+ next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
+}
+
+static void
+recursively_make_pred_seq_points (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+ const gpointer MONO_SEQ_SEEN_LOOP = GINT_TO_POINTER(-1);
+
+ GArray *predecessors = g_array_new (FALSE, TRUE, sizeof (gpointer));
+ GHashTable *seen = g_hash_table_new_full (g_direct_hash, NULL, NULL, NULL);
+
+ // Insert/remove sentinel into the memoize table to detect loops containing bb
+ bb->pred_seq_points = MONO_SEQ_SEEN_LOOP;
+
+ for (int i = 0; i < bb->in_count; ++i) {
+ MonoBasicBlock *in_bb = bb->in_bb [i];
+
+ // This bb has the last seq point, append it and continue
+ if (in_bb->last_seq_point != NULL) {
+ predecessors = g_array_append_val (predecessors, in_bb->last_seq_point);
+ continue;
+ }
+
+ // We've looped or handled this before, exit early.
+ // No last sequence points to find.
+ if (in_bb->pred_seq_points == MONO_SEQ_SEEN_LOOP)
+ continue;
+
+ // Take sequence points from incoming basic blocks
+
+ if (in_bb == cfg->bb_entry)
+ continue;
- for (i = 0; i < bb->in_count; ++i) {
- in_bb = bb->in_bb [i];
-
- if (in_bb->last_seq_point) {
- int src_index = in_bb->last_seq_point->backend.size;
- int dst_index = ins->backend.size;
-
- /* bb->in_bb might contain duplicates */
- for (l = next [src_index]; l; l = l->next)
- if (GPOINTER_TO_UINT (l->data) == dst_index)
- break;
- if (!l)
- next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
- } else {
- /* Have to look at its predecessors */
- if (depth < 5)
- collect_pred_seq_points (in_bb, ins, next, depth + 1);
+ if (in_bb->pred_seq_points == NULL)
+ recursively_make_pred_seq_points (cfg, in_bb);
+
+ // Union sequence points with incoming bb's
+ for (int i=0; i < in_bb->num_pred_seq_points; i++) {
+ if (!g_hash_table_lookup (seen, in_bb->pred_seq_points [i])) {
+ g_array_append_val (predecessors, in_bb->pred_seq_points [i]);
+ g_hash_table_insert (seen, in_bb->pred_seq_points [i], &MONO_SEQ_SEEN_LOOP);
+ }
}
+ // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
}
+
+ g_hash_table_destroy (seen);
+
+ if (predecessors->len != 0) {
+ bb->pred_seq_points = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst *) * predecessors->len);
+ bb->num_pred_seq_points = predecessors->len;
+
+ for (int newer = 0; newer < bb->num_pred_seq_points; newer++) {
+ bb->pred_seq_points [newer] = g_array_index(predecessors, gpointer, newer);
+ }
+ }
+
+ g_free (predecessors);
+}
+
+static void
+collect_pred_seq_points (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, GSList **next)
+{
+ // Doesn't have a last sequence point, must find from incoming basic blocks
+ if (bb->pred_seq_points == NULL && bb != cfg->bb_entry)
+ recursively_make_pred_seq_points (cfg, bb);
+
+ for (int i = 0; i < bb->num_pred_seq_points; i++)
+ insert_pred_seq_point (bb->pred_seq_points [i], ins, next);
+
+ return;
}
void
next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
} else {
/* Link with the last bb in the previous bblocks */
- collect_pred_seq_points (bb, ins, next, 0);
+ collect_pred_seq_points (cfg, bb, ins, next);
}
last = ins;
trap "rm -rf ${TMP_FILE_PREFIX}*" EXIT
tmp_file () {
- mktemp ./${TMP_FILE_PREFIX}XXXX
+ mktemp ./${TMP_FILE_PREFIX}XXXXXX
}
clean_aot () {
# Remove empty .stdout and .stderr files for wrench
rm-empty-logs:
@echo "Removing empty logs..."
- @find . '(' -name "*.stdout" -o -name "*.stderr" ')' -empty -exec rm {} \;
+ find . '(' -name "*.stdout" -o -name "*.stderr" ')' -size 0 -exec rm {} \;
assemblyresolve/test/asm.dll:
$(MAKE) -C assemblyresolve prereq
public class Tests
{
+ private static int mainThreadId;
+
public static int Main ()
{
+ mainThreadId = Thread.CurrentThread.ManagedThreadId;
return TestDriver.RunTests (typeof (Tests));
}
Thread.CurrentThread.Priority.ToString());
}
+ public static int test_0_main_thread_priority ()
+ {
+ Console.WriteLine("Testing main thread's priority");
+ if (Thread.CurrentThread.ManagedThreadId != mainThreadId)
+ {
+ Console.WriteLine("test_0_main_thread_priority() must be run on the main thread");
+ return 1;
+ }
+
+ var before = Thread.CurrentThread.Priority;
+ Console.WriteLine("Priority: {0}", before);
+ if (before != ThreadPriority.Normal)
+ return 2;
+
+ Console.WriteLine("Setting main thread's priority to AboveNormal");
+ Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
+ var after = Thread.CurrentThread.Priority;
+ Console.WriteLine("Priority: {0} {1}", before, after);
+ if (after != ThreadPriority.AboveNormal)
+ return 3;
+
+ before = after;
+ Console.WriteLine("Setting main thread's priority to BelowNormal");
+ Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
+ after = Thread.CurrentThread.Priority;
+ Console.WriteLine("Priority: {0} {1}", before, after);
+ if (after != ThreadPriority.BelowNormal)
+ return 4;
+
+ before = after;
+ Console.WriteLine("Setting main thread's priority to Normal");
+ Thread.CurrentThread.Priority = ThreadPriority.Normal;
+ after = Thread.CurrentThread.Priority;
+ Console.WriteLine("Priority: {0} {1}", before, after);
+ if (after != ThreadPriority.Normal)
+ return 5;
+
+ return 0;
+ }
+
public static int test_0_thread_priority ()
{
int res = 0;
void
mono_threads_suspend_register (MonoThreadInfo *info)
{
+ g_assert (!info->handle);
+ info->handle = mono_threads_platform_open_handle();
}
void
typedef struct {
LPTHREAD_START_ROUTINE start_routine;
void *arg;
+ gint32 priority;
MonoCoopSem registered;
gboolean suspend;
HANDLE suspend_event;
info->runtime_thread = TRUE;
info->create_suspended = suspend;
+ mono_threads_platform_set_priority(info, start_info->priority);
+
mono_coop_sem_post (&(start_info->registered));
if (suspend) {
return NULL;
mono_coop_sem_init (&(start_info->registered), 0);
start_info->arg = arg;
+ start_info->priority = tp->priority;
start_info->start_routine = start_routine;
start_info->suspend = creation_flags & CREATE_SUSPENDED;
creation_flags &= ~CREATE_SUSPENDED;
MonoThreadPriority
mono_threads_platform_get_priority (MonoThreadInfo *info)
{
+ g_assert (info->handle);
return GetThreadPriority (info->handle) + 2;
}
gboolean
mono_threads_platform_set_priority (MonoThreadInfo *info, MonoThreadPriority priority)
{
+ g_assert (info->handle);
return SetThreadPriority (info->handle, priority - 2);
}
var types = new List<string>
{
"MonoObject",
+ "MonoObjectHandlePayload",
"MonoClass",
"MonoVTable",
"MonoDelegate",