You've already forked linux-packaging-mono
Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
@ -0,0 +1,127 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Description;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
//This is the behavior is intended to auto apply IIS/AspNet configuration to WCF post design time
|
||||
class ApplyHostConfigurationBehavior : IServiceBehavior
|
||||
{
|
||||
internal ApplyHostConfigurationBehavior()
|
||||
{
|
||||
}
|
||||
|
||||
void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase service)
|
||||
{
|
||||
if (service.Description.Endpoints != null && ServiceHostingEnvironment.MultipleSiteBindingsEnabled)
|
||||
{
|
||||
FailActivationIfEndpointsHaveAbsoluteAddress(service);
|
||||
}
|
||||
}
|
||||
|
||||
void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase service, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
|
||||
{
|
||||
}
|
||||
|
||||
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase service)
|
||||
{
|
||||
if (ServiceHostingEnvironment.MultipleSiteBindingsEnabled)
|
||||
{
|
||||
SetEndpointAddressFilterToIgnorePort(service);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEndpointAddressFilterToIgnorePort(ServiceHostBase service)
|
||||
{
|
||||
for (int i = 0; i < service.ChannelDispatchers.Count; i++)
|
||||
{
|
||||
ChannelDispatcher channelDispatcher = service.ChannelDispatchers[i] as ChannelDispatcher;
|
||||
if (channelDispatcher != null)
|
||||
{
|
||||
if (IsSchemeHttpOrHttps(channelDispatcher.Listener.Uri.Scheme))
|
||||
{
|
||||
for (int j = 0; j < channelDispatcher.Endpoints.Count; j++)
|
||||
{
|
||||
EndpointDispatcher endpointDispatcher = channelDispatcher.Endpoints[j];
|
||||
EndpointAddressMessageFilter endpointAddressMessageFilter = endpointDispatcher.AddressFilter as EndpointAddressMessageFilter;
|
||||
if (endpointAddressMessageFilter != null)
|
||||
{
|
||||
endpointAddressMessageFilter.ComparePort = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FailActivationIfEndpointsHaveAbsoluteAddress(ServiceHostBase service)
|
||||
{
|
||||
foreach (ServiceEndpoint endpoint in service.Description.Endpoints)
|
||||
{
|
||||
if (IsSchemeHttpOrHttps(endpoint.Binding.Scheme))
|
||||
{
|
||||
if (endpoint.UnresolvedListenUri != null)
|
||||
{
|
||||
ThrowIfAbsolute(endpoint.UnresolvedListenUri);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the listen URI is not null, we shouldn't care about address. Because there are
|
||||
//customers who have following config (for load balancer scenarios) - Note ExtraFolder and https
|
||||
//listen URI - http://localhost/App1/x.svc
|
||||
//Address - https://externalhost/ExtranFolder/App1/x.svc
|
||||
ThrowIfAbsolute(endpoint.UnresolvedAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServiceDebugBehavior debugBehavior = service.Description.Behaviors.Find<ServiceDebugBehavior>();
|
||||
if (debugBehavior != null)
|
||||
{
|
||||
if (debugBehavior.HttpHelpPageEnabled)
|
||||
{
|
||||
ThrowIfAbsolute(debugBehavior.HttpHelpPageUrl);
|
||||
}
|
||||
if (debugBehavior.HttpsHelpPageEnabled)
|
||||
{
|
||||
ThrowIfAbsolute(debugBehavior.HttpsHelpPageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
ServiceMetadataBehavior metadataBehavior = service.Description.Behaviors.Find<ServiceMetadataBehavior>();
|
||||
if (metadataBehavior != null)
|
||||
{
|
||||
if (metadataBehavior.HttpGetEnabled)
|
||||
{
|
||||
ThrowIfAbsolute(metadataBehavior.HttpGetUrl);
|
||||
}
|
||||
if (metadataBehavior.HttpsGetEnabled)
|
||||
{
|
||||
ThrowIfAbsolute(metadataBehavior.HttpsGetUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ThrowIfAbsolute(Uri uri)
|
||||
{
|
||||
if (uri != null && uri.IsAbsoluteUri)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_SharedEndpointRequiresRelativeEndpoint(uri.ToString())));
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsSchemeHttpOrHttps(string scheme)
|
||||
{
|
||||
return string.Compare(scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) == 0 ||
|
||||
string.Compare(scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,116 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace System.ServiceModel
|
||||
{
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
|
||||
static class AspNetPartialTrustHelpers
|
||||
{
|
||||
[Fx.Tag.SecurityNote(Critical = "Caches the PermissionSet associated with the asp.net trust level."
|
||||
+ "This will not change over the life of the AppDomain.")]
|
||||
[SecurityCritical]
|
||||
static SecurityContext aspNetSecurityContext;
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "If erroneously set to true, could bypass the PermitOnly.")]
|
||||
[SecurityCritical]
|
||||
static bool isInitialized;
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Critical field used to prevent usage of System.Web types in partial trust outside the ASP.NET context.")]
|
||||
[SecurityCritical]
|
||||
private static bool isInPartialTrustOutsideAspNet; // indicates if we are running in partial trust outside the ASP.NET context
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Critical field used to prevent usage of System.Web types in partial trust outside the ASP.NET context.")]
|
||||
[SecurityCritical]
|
||||
private static bool isInPartialTrustOutsideAspNetInitialized = false;
|
||||
|
||||
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - determines if the given PermissionSet is full trust."
|
||||
+ "We will base subsequent security decisions on this.")]
|
||||
static bool IsFullTrust(PermissionSet perms)
|
||||
{
|
||||
return perms == null || perms.IsUnrestricted();
|
||||
}
|
||||
|
||||
internal static bool NeedPartialTrustInvoke
|
||||
{
|
||||
[SuppressMessage(FxCop.Category.Security, "CA2107:ReviewDenyAndPermitOnlyUsage")]
|
||||
[Fx.Tag.SecurityNote(Critical = "Makes a security sensitive decision, updates aspNetSecurityContext and isInitialized.",
|
||||
Safe = "Ok to know whether the ASP app is partial trust.")]
|
||||
[SecuritySafeCritical]
|
||||
get
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
FailIfInPartialTrustOutsideAspNet();
|
||||
NamedPermissionSet aspNetPermissionSet = GetHttpRuntimeNamedPermissionSet();
|
||||
if (!IsFullTrust(aspNetPermissionSet))
|
||||
{
|
||||
try
|
||||
{
|
||||
aspNetPermissionSet.PermitOnly();
|
||||
aspNetSecurityContext = System.Runtime.PartialTrustHelpers.CaptureSecurityContextNoIdentityFlow();
|
||||
}
|
||||
finally
|
||||
{
|
||||
CodeAccessPermission.RevertPermitOnly();
|
||||
}
|
||||
}
|
||||
isInitialized = true;
|
||||
}
|
||||
return aspNetSecurityContext != null;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.SecureAsserts, Justification = "Users cannot pass arbitrary data to this code.")]
|
||||
[Fx.Tag.SecurityNote(Critical = "Asserts AspNetHostingPermission.")]
|
||||
[SecurityCritical]
|
||||
[AspNetHostingPermission(SecurityAction.Assert, Level = AspNetHostingPermissionLevel.Unrestricted)]
|
||||
static NamedPermissionSet GetHttpRuntimeNamedPermissionSet()
|
||||
{
|
||||
return HttpRuntime.GetNamedPermissionSet();
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Touches aspNetSecurityContext.",
|
||||
Safe = "Ok to invoke the user's delegate under the PT context.")]
|
||||
[SecuritySafeCritical]
|
||||
internal static void PartialTrustInvoke(ContextCallback callback, object state)
|
||||
{
|
||||
if (NeedPartialTrustInvoke)
|
||||
{
|
||||
SecurityContext.Run(aspNetSecurityContext.CreateCopy(), callback, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to guard usage of System.Web types in partial trust outside the ASP.NET context (because they are not secure),
|
||||
/// in which case we shutdown the process.
|
||||
/// </summary>
|
||||
[Fx.Tag.SecurityNote(Critical = "Critical because it uses security critical fields.",
|
||||
Safe = "Safe because it doesn't take user input and it doesn't leak security sensitive information.")]
|
||||
[SecuritySafeCritical]
|
||||
internal static void FailIfInPartialTrustOutsideAspNet()
|
||||
{
|
||||
if (!isInPartialTrustOutsideAspNetInitialized)
|
||||
{
|
||||
// The HostingEnvironment.IsHosted property is safe to be called in partial trust outside the ASP.NET context.
|
||||
isInPartialTrustOutsideAspNet = !(PartialTrustHelpers.AppDomainFullyTrusted || HostingEnvironment.IsHosted);
|
||||
isInPartialTrustOutsideAspNetInitialized = true;
|
||||
}
|
||||
|
||||
if (isInPartialTrustOutsideAspNet)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new SecurityException(Activation.SR.CannotRunInPartialTrustOutsideAspNet));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Runtime;
|
||||
using System.Security;
|
||||
using System.ServiceModel;
|
||||
using System.Web;
|
||||
using System.Web.SessionState;
|
||||
|
||||
class AspNetRouteServiceHttpHandler : IHttpAsyncHandler, IRequiresSessionState
|
||||
{
|
||||
string serviceVirtualPath;
|
||||
|
||||
public AspNetRouteServiceHttpHandler(string virtualPath)
|
||||
{
|
||||
this.serviceVirtualPath = virtualPath;
|
||||
}
|
||||
|
||||
public bool IsReusable
|
||||
{
|
||||
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called outside PermitOnly context.")]
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Entry-point from asp.net, called outside PermitOnly context. ASP.NET calls are critical." +
|
||||
"ExecuteSynchronous is critical because it captures HostedImpersonationContext (and makes it available later) " +
|
||||
"so caller must ensure that this is called in the right place.")]
|
||||
[SecurityCritical]
|
||||
public void ProcessRequest(HttpContext context)
|
||||
{
|
||||
ServiceHostingEnvironment.SafeEnsureInitialized();
|
||||
|
||||
HostedHttpRequestAsyncResult.ExecuteSynchronous(context.ApplicationInstance, this.serviceVirtualPath, true, false);
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Entry-point from asp.net, called outside PermitOnly context. ASP.NET calls are critical." +
|
||||
"ExecuteSynchronous is critical because it captures HostedImpersonationContext (and makes it available later) " +
|
||||
"so caller must ensure that this is called in the right place.")]
|
||||
[SecurityCritical]
|
||||
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback callback, object extraData)
|
||||
{
|
||||
ServiceHostingEnvironment.SafeEnsureInitialized();
|
||||
|
||||
return new HostedHttpRequestAsyncResult(context.ApplicationInstance, this.serviceVirtualPath, true, false, callback, extraData);
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - called outside PermitOnly context.")]
|
||||
public void EndProcessRequest(IAsyncResult result)
|
||||
{
|
||||
HostedHttpRequestAsyncResult.End(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,383 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
// This class implements an LRU cache that support recycling of oldest items.
|
||||
//
|
||||
// The read path is very light-weighted. It takes the reader lock, do a cache lookup, and increment the counter to
|
||||
// make sure the item is up-to-date.
|
||||
//
|
||||
// It exposes the writer lock through an IDisposable object through CreateWriterLockScope(). Whenever a modification
|
||||
// is required to the cache, we create a scope to perform the work.
|
||||
//
|
||||
// It exposes a list of "unsafe" methods for cache modifications. These operations should be invoked only inside a
|
||||
// WriterLockScope.
|
||||
//
|
||||
// Recycling happens in batches. The method UnsafeBeginBatchCollect() finds a batch of items, remove them from the
|
||||
// cache, and have them closed. The counter is updated whenever Collect happens.
|
||||
//
|
||||
// It supports the recycling for the whole cache. In order to avoid blocking the closing, the asynchronous method
|
||||
// UnsafeBeginCollectAll() is used to initiate the close operations for all of the nodes.
|
||||
//
|
||||
// Since the cache favors reads than writes, the items in the cache are not sorted until a Collect operation happens.
|
||||
// When the Collect operation happens, items are sorted by the LastCounter field of CollectibleNode. Oldest items which
|
||||
// are collectible (CanClose returns true) are moved into the batch for collection.
|
||||
//
|
||||
// Here are some fields of the class that control the recycling logic to achieve best results:
|
||||
// - collectPercentageInOneBatch: This defines how many items the batch can have for a single Collect operation.
|
||||
// We need to best leverage the machine capacity but at the same time have an efficient recycling result. This
|
||||
// number defines the percentage of items in the cache to be collected. The value is hard-coded to be 25%.
|
||||
// - minSkipCountForWrites: This defines the consecutive writes (service activation, for example) before the next
|
||||
// Collect operation.
|
||||
class CollectibleLRUCache<TKey, TValue>
|
||||
{
|
||||
// Collect x% of items when a collection happens
|
||||
readonly double collectPercentageInOneBatch = 0.25;
|
||||
|
||||
// After an immediate collection, we skip this number of new writes before performing another collection
|
||||
readonly int minSkipCountForWrites = 4;
|
||||
|
||||
// The look up counter that simulates the timestamp
|
||||
int counter;
|
||||
|
||||
ReaderWriterLockSlim rwLock;
|
||||
|
||||
// Records the current counter for write
|
||||
int writeCounter;
|
||||
|
||||
Dictionary<TKey, CollectibleNode> directory;
|
||||
CollectibleBatch currentCollectibleBatch;
|
||||
|
||||
public CollectibleLRUCache(int capacity, IEqualityComparer<TKey> comparer)
|
||||
{
|
||||
rwLock = new ReaderWriterLockSlim();
|
||||
directory = new Dictionary<TKey, CollectibleNode>(capacity, comparer);
|
||||
currentCollectibleBatch = new CollectibleBatch();
|
||||
}
|
||||
|
||||
public CollectibleNode this[TKey key]
|
||||
{
|
||||
get
|
||||
{
|
||||
rwLock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
CollectibleNode node = UnsafeGet(key);
|
||||
if (node != null)
|
||||
{
|
||||
// Record the last counter in the node. We don't take a writer lock here because the counter does
|
||||
// not have to be very accurate.
|
||||
node.LastCounter = Interlocked.Increment(ref counter);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
finally
|
||||
{
|
||||
rwLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method must be called inside a lock. The counter is not updated
|
||||
public CollectibleNode UnsafeGet(TKey key)
|
||||
{
|
||||
CollectibleNode node;
|
||||
if (directory.TryGetValue(key, out node))
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
public void Touch(TKey key)
|
||||
{
|
||||
rwLock.EnterReadLock();
|
||||
try
|
||||
{
|
||||
CollectibleNode node = UnsafeGet(key);
|
||||
|
||||
if (node != null)
|
||||
{
|
||||
// Record the last counter in the node. We don't take a writer lock here because the counter does
|
||||
// not have to be very accurate.
|
||||
node.LastCounter = Interlocked.Increment(ref counter);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
rwLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public void UnsafeRemove(CollectibleNode node)
|
||||
{
|
||||
if (directory.ContainsKey(node.GetKey()))
|
||||
{
|
||||
directory.Remove(node.GetKey());
|
||||
}
|
||||
}
|
||||
|
||||
// This method must be called inside a writable lock
|
||||
public void UnsafeAdd(CollectibleNode node)
|
||||
{
|
||||
Fx.Assert(rwLock.IsWriteLockHeld, "This method can be called only when the WriterLock is acquired");
|
||||
|
||||
writeCounter++;
|
||||
directory.Add(node.GetKey(), node);
|
||||
node.LastCounter = Interlocked.Increment(ref counter);
|
||||
}
|
||||
|
||||
// This method must be called inside a writable lock
|
||||
public bool UnsafeBeginBatchCollect()
|
||||
{
|
||||
return UnsafeBeginBatchCollect(false);
|
||||
}
|
||||
|
||||
public bool UnsafeBeginBatchCollect(bool collectingAll)
|
||||
{
|
||||
Fx.Assert(rwLock.IsWriteLockHeld, "This method can be called only when the WriterLock is acquired");
|
||||
|
||||
if (collectingAll)
|
||||
{
|
||||
AbortExistingBatch();
|
||||
|
||||
if (this.directory.Count > 0)
|
||||
{
|
||||
this.currentCollectibleBatch.AddRange(this.directory.Values);
|
||||
this.directory.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to avoid collecting items in a consecutive order.
|
||||
if (minSkipCountForWrites >= writeCounter)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CollectibleNode[] array = ResetCountersAndToArray();
|
||||
Array.Sort<CollectibleNode>(array, CollectibleNode.CounterComparison);
|
||||
|
||||
// Collect the items here.
|
||||
int collectTargetCount = (int)(array.Length * collectPercentageInOneBatch);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
if (array[i].CanClose())
|
||||
{
|
||||
currentCollectibleBatch.Add(array[i]);
|
||||
}
|
||||
|
||||
if (currentCollectibleBatch.Count >= collectTargetCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCollectibleBatch.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < currentCollectibleBatch.Count; i++)
|
||||
{
|
||||
directory.Remove(currentCollectibleBatch[i].GetKey());
|
||||
}
|
||||
}
|
||||
|
||||
currentCollectibleBatch.BeginCollect();
|
||||
|
||||
// Wrapping WriterCounter to 0 to avoid integer overflow.
|
||||
writeCounter = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Reliability, FxCop.Rule.AvoidCallingProblematicMethods,
|
||||
Justification = "Calling GC.Collect to control memory usage more explicitly.")]
|
||||
public void EndBatchCollect()
|
||||
{
|
||||
currentCollectibleBatch.WaitForRecyclingCompletion();
|
||||
|
||||
// Force garbage collection
|
||||
GC.Collect(2, GCCollectionMode.Optimized);
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
using (this.CreateWriterLockScope())
|
||||
{
|
||||
AbortExistingBatch();
|
||||
|
||||
if (this.directory.Count > 0)
|
||||
{
|
||||
this.currentCollectibleBatch.AddRange(this.directory.Values);
|
||||
this.currentCollectibleBatch.Abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AbortExistingBatch()
|
||||
{
|
||||
if (this.currentCollectibleBatch.Count > 0)
|
||||
{
|
||||
this.currentCollectibleBatch.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.directory.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public IDisposable CreateWriterLockScope()
|
||||
{
|
||||
return new WriterLockScope(this.rwLock);
|
||||
}
|
||||
|
||||
CollectibleNode[] ResetCountersAndToArray()
|
||||
{
|
||||
CollectibleNode[] array = directory.Values.ToArray();
|
||||
|
||||
// Reset the counters so that the integer counters are not wrapped (overflow from positive to negative)
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i].LastCounter -= this.counter;
|
||||
}
|
||||
|
||||
this.counter = 0;
|
||||
return array;
|
||||
}
|
||||
|
||||
internal abstract class CollectibleNode
|
||||
{
|
||||
public static Comparison<CollectibleNode> CounterComparison = new Comparison<CollectibleNode>(CounterLessThan);
|
||||
public int LastCounter;
|
||||
public abstract TKey GetKey();
|
||||
public abstract IAsyncResult BeginClose(AsyncCallback callback, object state);
|
||||
public abstract void EndClose(IAsyncResult result);
|
||||
public abstract void Abort();
|
||||
public abstract bool CanClose();
|
||||
public TValue Value { get; set; }
|
||||
|
||||
public static int CounterLessThan(CollectibleNode x, CollectibleNode y)
|
||||
{
|
||||
return x.LastCounter - y.LastCounter;
|
||||
}
|
||||
}
|
||||
|
||||
class WriterLockScope : IDisposable
|
||||
{
|
||||
ReaderWriterLockSlim rwLock;
|
||||
public WriterLockScope(ReaderWriterLockSlim rwLock)
|
||||
{
|
||||
this.rwLock = rwLock;
|
||||
rwLock.EnterWriteLock();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
rwLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
class CollectibleBatch : List<CollectibleNode>
|
||||
{
|
||||
ManualResetEvent recyclingCompletedWaitHandle;
|
||||
AsyncCallback collectibleNodeClosedCallback;
|
||||
int totalCollectCount;
|
||||
|
||||
public CollectibleBatch()
|
||||
{
|
||||
// The event is initially set when the batch is empty.
|
||||
recyclingCompletedWaitHandle = new ManualResetEvent(true);
|
||||
collectibleNodeClosedCallback = Fx.ThunkCallback(new AsyncCallback(OnCollectibleNodeClosed));
|
||||
}
|
||||
|
||||
public void BeginCollect()
|
||||
{
|
||||
this.totalCollectCount = this.Count;
|
||||
if (this.totalCollectCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recyclingCompletedWaitHandle.Reset();
|
||||
for (int i = 0; i < this.Count; i++)
|
||||
{
|
||||
IAsyncResult result = this[i].BeginClose(collectibleNodeClosedCallback, this[i]);
|
||||
if (result == null)
|
||||
{
|
||||
DecrementCollectCount();
|
||||
}
|
||||
else if (result.CompletedSynchronously)
|
||||
{
|
||||
HandleCollectibleNodeClosed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void WaitForRecyclingCompletion()
|
||||
{
|
||||
recyclingCompletedWaitHandle.WaitOne();
|
||||
this.Clear();
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
for (int i = 0; i < this.Count; i++)
|
||||
{
|
||||
this[i].Abort();
|
||||
}
|
||||
|
||||
this.Clear();
|
||||
recyclingCompletedWaitHandle.Set();
|
||||
}
|
||||
|
||||
void DecrementCollectCount()
|
||||
{
|
||||
int currentCount = Interlocked.Decrement(ref this.totalCollectCount);
|
||||
if (currentCount == 0)
|
||||
{
|
||||
this.recyclingCompletedWaitHandle.Set();
|
||||
}
|
||||
}
|
||||
|
||||
void OnCollectibleNodeClosed(IAsyncResult result)
|
||||
{
|
||||
if (result == null || result.CompletedSynchronously)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HandleCollectibleNodeClosed(result);
|
||||
}
|
||||
|
||||
void HandleCollectibleNodeClosed(IAsyncResult result)
|
||||
{
|
||||
CollectibleNode node = result.AsyncState as CollectibleNode;
|
||||
if (node != null)
|
||||
{
|
||||
node.EndClose(result);
|
||||
}
|
||||
|
||||
DecrementCollectCount();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
// <copyright>
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace System.ServiceModel.Activation.Configuration
|
||||
{
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
|
||||
internal static class AppSettings
|
||||
{
|
||||
private const string UseClassicReadEntityBodyModeString = "wcf:serviceHostingEnvironment:useClassicReadEntityBodyMode";
|
||||
private static bool useClassicReadEntityBodyMode = false;
|
||||
|
||||
private static volatile bool settingsInitalized = false;
|
||||
private static object appSettingsLock = new object();
|
||||
|
||||
internal static bool UseClassicReadEntityMode
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureSettingsLoaded();
|
||||
return useClassicReadEntityBodyMode;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.ReliabilityBasic, "Reliability104:CaughtAndHandledExceptionsRule",
|
||||
Justification = "Handle the configuration exceptions here to avoid regressions on customer's existing scenarios")]
|
||||
private static void EnsureSettingsLoaded()
|
||||
{
|
||||
if (!settingsInitalized)
|
||||
{
|
||||
lock (appSettingsLock)
|
||||
{
|
||||
if (!settingsInitalized)
|
||||
{
|
||||
NameValueCollection appSettingsSection = null;
|
||||
try
|
||||
{
|
||||
appSettingsSection = ConfigurationManager.AppSettings;
|
||||
}
|
||||
catch (ConfigurationErrorsException)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ((appSettingsSection == null) || !bool.TryParse(appSettingsSection[UseClassicReadEntityBodyModeString], out useClassicReadEntityBodyMode))
|
||||
{
|
||||
useClassicReadEntityBodyMode = false;
|
||||
}
|
||||
|
||||
settingsInitalized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activation.Diagnostics
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
static class TraceCode
|
||||
{
|
||||
// WebHost trace codes
|
||||
public const int Activation = 0X90000;
|
||||
public const int WebHostFailedToCompile = TraceCode.Activation | 0X0001;
|
||||
public const int WebHostServiceActivated = TraceCode.Activation | 0X0002;
|
||||
public const int WebHostFailedToActivateService = TraceCode.Activation | 0X0003;
|
||||
public const int WebHostCompilation = TraceCode.Activation | 0X0004;
|
||||
public const int WebHostDebugRequest = TraceCode.Activation | 0X0005;
|
||||
public const int WebHostProtocolMisconfigured = TraceCode.Activation | 0X0006;
|
||||
public const int WebHostServiceCloseFailed = TraceCode.Activation | 0X0007;
|
||||
public const int WebHostNoCBTSupport = TraceCode.Activation | 0X0008;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activation.Diagnostics
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime;
|
||||
using System.Runtime.Diagnostics;
|
||||
|
||||
static class TraceUtility
|
||||
{
|
||||
static Dictionary<int, string> traceCodes = new Dictionary<int, string>(7)
|
||||
{
|
||||
{ TraceCode.WebHostFailedToCompile, "WebHostFailedToCompile" },
|
||||
{ TraceCode.WebHostServiceActivated, "WebHostServiceActivated" },
|
||||
{ TraceCode.WebHostFailedToActivateService, "WebHostFailedToActivateService" },
|
||||
{ TraceCode.WebHostCompilation, "WebHostCompilation" },
|
||||
{ TraceCode.WebHostDebugRequest, "WebHostDebugRequest" },
|
||||
{ TraceCode.WebHostProtocolMisconfigured, "WebHostProtocolMisconfigured" },
|
||||
{ TraceCode.WebHostServiceCloseFailed, "WebHostServiceCloseFailed" },
|
||||
{ TraceCode.WebHostNoCBTSupport, "WebHostNoCBTSupport" },
|
||||
};
|
||||
|
||||
internal static void TraceEvent(TraceEventType severity, int traceCode, string traceDescription, object source)
|
||||
{
|
||||
TraceEvent(severity, traceCode, traceDescription, null, source, null);
|
||||
}
|
||||
|
||||
internal static void TraceEvent(TraceEventType severity, int traceCode, string traceDescription, object source, Exception exception)
|
||||
{
|
||||
TraceEvent(severity, traceCode, traceDescription, null, source, exception);
|
||||
}
|
||||
|
||||
internal static void TraceEvent(TraceEventType severity, int traceCode, string traceDescription, TraceRecord record, object source, Exception exception)
|
||||
{
|
||||
Fx.Assert(traceCodes.ContainsKey(traceCode),
|
||||
string.Format(CultureInfo.InvariantCulture, "Unsupported trace code: Please add trace code 0x{0} to the dictionary TraceUtility.traceCodes in {1}",
|
||||
traceCode.ToString("X", CultureInfo.InvariantCulture), typeof(TraceUtility)));
|
||||
string msdnTraceCode = System.ServiceModel.Diagnostics.LegacyDiagnosticTrace.GenerateMsdnTraceCode("System.ServiceModel.Activation", traceCodes[traceCode]);
|
||||
DiagnosticUtility.DiagnosticTrace.TraceEvent(severity, traceCode, msdnTraceCode, traceDescription, record, exception, source);
|
||||
}
|
||||
|
||||
internal static string CreateSourceString(object source)
|
||||
{
|
||||
return source.GetType().ToString() + "/" + source.GetHashCode().ToString(CultureInfo.CurrentCulture);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Description;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ServiceModel.Channels;
|
||||
|
||||
class HostedBindingBehavior : IServiceBehavior
|
||||
{
|
||||
VirtualPathExtension virtualPathExtension;
|
||||
|
||||
internal HostedBindingBehavior(VirtualPathExtension virtualPathExtension)
|
||||
{
|
||||
this.virtualPathExtension = virtualPathExtension;
|
||||
}
|
||||
|
||||
public VirtualPathExtension VirtualPathExtension
|
||||
{
|
||||
get { return this.virtualPathExtension; }
|
||||
}
|
||||
|
||||
void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
|
||||
{
|
||||
}
|
||||
|
||||
void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
{
|
||||
throw FxTrace.Exception.ArgumentNull("parameters");
|
||||
}
|
||||
|
||||
parameters.Add(this.virtualPathExtension);
|
||||
}
|
||||
|
||||
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,282 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Runtime;
|
||||
using System.Runtime.Diagnostics;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Diagnostics;
|
||||
using System.ServiceModel.Dispatcher;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
|
||||
class HostedHttpTransportManager : HttpTransportManager
|
||||
{
|
||||
string scheme;
|
||||
int port;
|
||||
string host;
|
||||
static AsyncCallback onHttpContextReceived = Fx.ThunkCallback(OnHttpContextReceived);
|
||||
|
||||
internal HostedHttpTransportManager(BaseUriWithWildcard baseAddress) :
|
||||
base(baseAddress.BaseAddress, baseAddress.HostNameComparisonMode)
|
||||
{
|
||||
base.IsHosted = true;
|
||||
}
|
||||
|
||||
internal override bool IsCompatible(HttpChannelListener factory)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
internal override void OnClose(TimeSpan timeout)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
internal override void OnOpen()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
internal override void OnAbort()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
internal override string Scheme
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.scheme ?? (this.scheme = this.ListenUri.Scheme);
|
||||
}
|
||||
}
|
||||
|
||||
internal string Host
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.host ?? (this.host = this.ListenUri.Host);
|
||||
}
|
||||
}
|
||||
|
||||
internal int Port
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.port == 0 ? (this.port = this.ListenUri.Port) : this.port;
|
||||
}
|
||||
}
|
||||
|
||||
static bool canTraceConnectionInformation = true;
|
||||
public void TraceConnectionInformation(HostedHttpRequestAsyncResult result)
|
||||
{
|
||||
if (result != null && DiagnosticUtility.ShouldTraceInformation && canTraceConnectionInformation)
|
||||
{
|
||||
try
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
IServiceProvider provider = (IServiceProvider)result.Application.Context;
|
||||
HttpWorkerRequest workerRequest = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
|
||||
string localAddress = string.Format(CultureInfo.InvariantCulture,
|
||||
"{0}:{1}", workerRequest.GetLocalAddress(), workerRequest.GetLocalPort());
|
||||
string remoteAddress = string.Format(CultureInfo.InvariantCulture,
|
||||
"{0}:{1}", workerRequest.GetRemoteAddress(), workerRequest.GetRemotePort());
|
||||
TraceUtility.TraceHttpConnectionInformation(localAddress, remoteAddress, this);
|
||||
}
|
||||
catch (SecurityException e)
|
||||
{
|
||||
canTraceConnectionInformation = false;
|
||||
|
||||
// not re-throwing on purpose
|
||||
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.", Safe = "Only returns the activity, doesn't leak the ASP .NET objects.")]
|
||||
[SecuritySafeCritical]
|
||||
public ServiceModelActivity CreateReceiveBytesActivity(HostedHttpRequestAsyncResult result)
|
||||
{
|
||||
ServiceModelActivity retval = null;
|
||||
if (result != null)
|
||||
{
|
||||
TraceMessageReceived(result.EventTraceActivity, result.RequestUri);
|
||||
if (DiagnosticUtility.ShouldUseActivity)
|
||||
{
|
||||
IServiceProvider provider = (IServiceProvider)result.Application.Context;
|
||||
retval = ServiceModelActivity.CreateBoundedActivity(GetRequestTraceIdentifier(provider));
|
||||
StartReceiveBytesActivity(retval, result.RequestUri);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Uses the HttpWorkerRequest to get the trace identifier, which Demands UnamangedCode.", Safe = "Only returns the trace id, doesn't leak the HttpWorkerRequest.")]
|
||||
[SecuritySafeCritical]
|
||||
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
|
||||
static Guid GetRequestTraceIdentifier(IServiceProvider provider)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return ((HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest))).RequestTraceIdentifier;
|
||||
}
|
||||
|
||||
internal void HttpContextReceived(HostedHttpRequestAsyncResult result)
|
||||
{
|
||||
using (DiagnosticUtility.ShouldUseActivity ? ServiceModelActivity.BoundOperation(this.Activity) : null)
|
||||
{
|
||||
using (ServiceModelActivity activity = this.CreateReceiveBytesActivity(result))
|
||||
{
|
||||
this.TraceConnectionInformation(result);
|
||||
HttpChannelListener listener;
|
||||
|
||||
if (base.TryLookupUri(result.RequestUri, result.GetHttpMethod(),
|
||||
this.HostNameComparisonMode, result.IsWebSocketRequest, out listener))
|
||||
{
|
||||
HostedHttpContext hostedContext = new HostedHttpContext(listener, result);
|
||||
object state = DiagnosticUtility.ShouldUseActivity ? (object)new ActivityHolder(activity, hostedContext) : (object)hostedContext;
|
||||
IAsyncResult httpContextReceivedResult = listener.BeginHttpContextReceived(hostedContext,
|
||||
null,
|
||||
onHttpContextReceived,
|
||||
state);
|
||||
if (httpContextReceivedResult.CompletedSynchronously)
|
||||
{
|
||||
EndHttpContextReceived(httpContextReceivedResult);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (DiagnosticUtility.ShouldTraceError)
|
||||
{
|
||||
TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.HttpChannelMessageReceiveFailed, SR.TraceCodeHttpChannelMessageReceiveFailed,
|
||||
new StringTraceRecord("IsRecycling", ServiceHostingEnvironment.IsRecycling.ToString(CultureInfo.CurrentCulture)),
|
||||
this, null);
|
||||
}
|
||||
|
||||
if (ServiceHostingEnvironment.IsRecycling)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(
|
||||
new EndpointNotFoundException(SR.Hosting_ListenerNotFoundForActivationInRecycling(result.RequestUri.ToString())));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw FxTrace.Exception.AsError(
|
||||
new EndpointNotFoundException(SR.Hosting_ListenerNotFoundForActivation(result.RequestUri.ToString())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void EndHttpContextReceived(IAsyncResult httpContextReceivedResult)
|
||||
{
|
||||
using (DiagnosticUtility.ShouldUseActivity ? (ActivityHolder)httpContextReceivedResult.AsyncState : null)
|
||||
{
|
||||
HttpChannelListener channelListener =
|
||||
(DiagnosticUtility.ShouldUseActivity ?
|
||||
((ActivityHolder)httpContextReceivedResult.AsyncState).context :
|
||||
(HttpRequestContext)httpContextReceivedResult.AsyncState).Listener;
|
||||
|
||||
channelListener.EndHttpContextReceived(httpContextReceivedResult);
|
||||
}
|
||||
}
|
||||
|
||||
static void OnHttpContextReceived(IAsyncResult httpContextReceivedResult)
|
||||
{
|
||||
if (httpContextReceivedResult.CompletedSynchronously)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Exception completionException = null;
|
||||
try
|
||||
{
|
||||
EndHttpContextReceived(httpContextReceivedResult);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (Fx.IsFatal(exception))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
completionException = exception;
|
||||
}
|
||||
|
||||
if (completionException != null)
|
||||
{
|
||||
HostedHttpContext context =
|
||||
(HostedHttpContext)(DiagnosticUtility.ShouldUseActivity ?
|
||||
((ActivityHolder)httpContextReceivedResult.AsyncState).context :
|
||||
httpContextReceivedResult.AsyncState);
|
||||
|
||||
context.CompleteWithException(completionException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Captures HttpContext.Current on construction, then can apply that state at a later time and reset on Dispose."
|
||||
+ "Whole object is critical because where it was initially constructed can be used to control HttpContext.set_Current later and HttpContext.set_Current requires an elevation")]
|
||||
#pragma warning disable 618 // have not moved to the v4 security model yet
|
||||
[SecurityCritical(SecurityCriticalScope.Everything)]
|
||||
#pragma warning restore 618
|
||||
class HostedThreadData
|
||||
{
|
||||
CultureInfo cultureInfo;
|
||||
CultureInfo uiCultureInfo;
|
||||
HttpContext httpContext;
|
||||
|
||||
public HostedThreadData()
|
||||
{
|
||||
this.cultureInfo = CultureInfo.CurrentCulture;
|
||||
this.uiCultureInfo = CultureInfo.CurrentUICulture;
|
||||
this.httpContext = HttpContext.Current;
|
||||
}
|
||||
|
||||
public IDisposable CreateContext()
|
||||
{
|
||||
return new HostedAspNetContext(this);
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
|
||||
static void UnsafeApplyData(HostedThreadData data)
|
||||
{
|
||||
// We set the CallContext.HostContext directly instead of setting HttpContext.Current because
|
||||
// the latter uses a demand instead of a link demand, which is very expensive in partial trust.
|
||||
System.Runtime.Remoting.Messaging.CallContext.HostContext = data.httpContext;
|
||||
|
||||
Thread currentThread = Thread.CurrentThread;
|
||||
if (currentThread.CurrentCulture != data.cultureInfo)
|
||||
{
|
||||
currentThread.CurrentCulture = data.cultureInfo;
|
||||
}
|
||||
|
||||
if (currentThread.CurrentUICulture != data.uiCultureInfo)
|
||||
{
|
||||
currentThread.CurrentUICulture = data.uiCultureInfo;
|
||||
}
|
||||
}
|
||||
|
||||
class HostedAspNetContext : IDisposable
|
||||
{
|
||||
HostedThreadData oldData;
|
||||
|
||||
public HostedAspNetContext(HostedThreadData newData)
|
||||
{
|
||||
oldData = new HostedThreadData();
|
||||
HostedThreadData.UnsafeApplyData(newData);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
HostedThreadData.UnsafeApplyData(oldData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.ComponentModel;
|
||||
using System.Runtime;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Principal;
|
||||
using System.ServiceModel.Activation.Interop;
|
||||
using System.Threading;
|
||||
|
||||
[Fx.Tag.SecurityNote(Miscellaneous = "RequiresReview - All member methods are security critical. The class might be used outside of the restricted SecurityContext." +
|
||||
"Ensure they do not accidentally satisfy any demands.")]
|
||||
class HostedImpersonationContext
|
||||
{
|
||||
[Fx.Tag.SecurityNote(Critical = "Stores the impersonation token handle. Since we're allowing 'safe' Impersonation of the token we got from asp.net we need to protect this value.")]
|
||||
[SecurityCritical]
|
||||
SafeCloseHandleCritical tokenHandle;
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Controls lifetime of token handle, caller must use care.")]
|
||||
[SecurityCritical]
|
||||
int refCount = 0;
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Security critical field, caller must use care.")]
|
||||
[SecurityCritical]
|
||||
bool isImpersonated;
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls two safe native methods under OpenCurrentThreadTokenCritical: GetCurrentThread and OpenThreadToken." +
|
||||
"Marshal.GetLastWin32Error captures current thread token in a SecurityCritical field.")]
|
||||
[SecurityCritical]
|
||||
public HostedImpersonationContext()
|
||||
{
|
||||
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled)
|
||||
{
|
||||
int error;
|
||||
bool isSuccess = SafeNativeMethods.OpenCurrentThreadTokenCritical(TokenAccessLevels.Query | TokenAccessLevels.Impersonate,
|
||||
true, out tokenHandle, out error);
|
||||
|
||||
if (isSuccess)
|
||||
{
|
||||
isImpersonated = true;
|
||||
Interlocked.Increment(ref refCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseInvalidOutSafeHandleCritical(tokenHandle);
|
||||
tokenHandle = null;
|
||||
if (error != SafeNativeMethods.ERROR_NO_TOKEN)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new Win32Exception(error, SR.Hosting_ImpersonationFailed));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls SetHandleAsInvalid which has a LinkDemand for UnmanagedCode.")]
|
||||
[SecurityCritical]
|
||||
static void CloseInvalidOutSafeHandleCritical(SafeHandle handle)
|
||||
{
|
||||
// Workaround for 64-bit CLR bug VSWhidbey 546830 - sometimes invalid SafeHandles come back null.
|
||||
if (handle != null)
|
||||
{
|
||||
Fx.Assert(handle.IsInvalid, "CloseInvalidOutSafeHandle called with a valid handle!");
|
||||
|
||||
// Calls SuppressFinalize.
|
||||
handle.SetHandleAsInvalid();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsImpersonated
|
||||
{
|
||||
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical isImpersonated field.", Safe = "Does not leak control or mutable/harmful data, no potential for harm.")]
|
||||
[SecuritySafeCritical]
|
||||
get
|
||||
{
|
||||
return isImpersonated;
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical tokenHandle field and uses LinkDemanded DangerousGetHandle method as well as UnsafeCreate." +
|
||||
"Caller should use with care, must take responsibility for reverting impersonation.")]
|
||||
[SecurityCritical]
|
||||
public IDisposable Impersonate()
|
||||
{
|
||||
if (!isImpersonated)
|
||||
return null;
|
||||
|
||||
Fx.Assert(tokenHandle != null, "The token handle was incorrectly released earlier.");
|
||||
HostedInnerImpersonationContext context = null;
|
||||
lock (tokenHandle)
|
||||
{
|
||||
context = HostedInnerImpersonationContext.UnsafeCreate(tokenHandle.DangerousGetHandle());
|
||||
GC.KeepAlive(tokenHandle);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Controls lifetime of token handle, caller must use care.")]
|
||||
[SecurityCritical]
|
||||
public void AddRef()
|
||||
{
|
||||
if (IsImpersonated)
|
||||
{
|
||||
Interlocked.Increment(ref refCount);
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Controls lifetime of token handle, caller must use care.")]
|
||||
[SecurityCritical]
|
||||
public void Release()
|
||||
{
|
||||
if (IsImpersonated)
|
||||
{
|
||||
Fx.Assert(tokenHandle != null, "The token handle is incorrectly released earlier.");
|
||||
int currentCount = Interlocked.Decrement(ref refCount);
|
||||
if (currentCount == 0)
|
||||
{
|
||||
lock (tokenHandle)
|
||||
{
|
||||
tokenHandle.Close();
|
||||
tokenHandle = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Keeps track of impersonated user, caller must use with care and call Dispose at the appropriate time.")]
|
||||
#pragma warning disable 618 // have not moved to the v4 security model yet
|
||||
[SecurityCritical(SecurityCriticalScope.Everything)]
|
||||
#pragma warning restore 618
|
||||
class HostedInnerImpersonationContext : IDisposable
|
||||
{
|
||||
IDisposable impersonatedContext;
|
||||
|
||||
HostedInnerImpersonationContext(IDisposable impersonatedContext)
|
||||
{
|
||||
if (impersonatedContext == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_ImpersonationFailed));
|
||||
}
|
||||
this.impersonatedContext = impersonatedContext;
|
||||
}
|
||||
|
||||
public static HostedInnerImpersonationContext UnsafeCreate(IntPtr token)
|
||||
{
|
||||
return new HostedInnerImpersonationContext(HostingEnvironmentWrapper.UnsafeImpersonate(token));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (impersonatedContext != null)
|
||||
{
|
||||
impersonatedContext.Dispose();
|
||||
impersonatedContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Diagnostics;
|
||||
|
||||
class HostedNamedPipeTransportManager : NamedPipeTransportManager
|
||||
{
|
||||
// Double-checked locking pattern requires volatile for read/write synchronization
|
||||
volatile bool settingsApplied;
|
||||
Action<Uri> onViaCallback;
|
||||
SharedConnectionListener listener;
|
||||
ConnectionDemuxer connectionDemuxer;
|
||||
int queueId;
|
||||
Guid token;
|
||||
Func<Uri, int> onDuplicatedViaCallback;
|
||||
|
||||
// Double-checked locking pattern requires volatile for read/write synchronization
|
||||
volatile bool demuxerCreated;
|
||||
|
||||
public HostedNamedPipeTransportManager(BaseUriWithWildcard baseAddress)
|
||||
: base(baseAddress.BaseAddress)
|
||||
{
|
||||
this.HostNameComparisonMode = baseAddress.HostNameComparisonMode;
|
||||
this.onViaCallback = new Action<Uri>(OnVia);
|
||||
this.onDuplicatedViaCallback = new Func<Uri, int>(OnDuplicatedVia);
|
||||
}
|
||||
|
||||
protected override bool IsCompatible(NamedPipeChannelListener channelListener)
|
||||
{
|
||||
if (channelListener.HostedVirtualPath == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.IsCompatible(channelListener);
|
||||
}
|
||||
|
||||
internal void Start(int queueId, Guid token, Action messageReceivedCallback)
|
||||
{
|
||||
SetMessageReceivedCallback(messageReceivedCallback);
|
||||
OnOpenInternal(queueId, token);
|
||||
}
|
||||
|
||||
internal override void OnOpen()
|
||||
{
|
||||
// This is intentionally empty.
|
||||
}
|
||||
|
||||
internal override void OnAbort()
|
||||
{
|
||||
}
|
||||
|
||||
internal void Stop(TimeSpan timeout)
|
||||
{
|
||||
Cleanup(false, timeout);
|
||||
}
|
||||
|
||||
void Cleanup(bool aborting, TimeSpan timeout)
|
||||
{
|
||||
lock (ThisLock)
|
||||
{
|
||||
if (listener != null)
|
||||
{
|
||||
if (!aborting)
|
||||
{
|
||||
listener.Stop(timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
listener.Abort();
|
||||
}
|
||||
|
||||
// The listener will be closed by the demuxer.
|
||||
listener = null;
|
||||
}
|
||||
|
||||
if (connectionDemuxer != null)
|
||||
{
|
||||
connectionDemuxer.Dispose();
|
||||
}
|
||||
|
||||
demuxerCreated = false;
|
||||
settingsApplied = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateConnectionDemuxer()
|
||||
{
|
||||
IConnectionListener connectionListener = new BufferedConnectionListener(listener, MaxOutputDelay, ConnectionBufferSize);
|
||||
if (DiagnosticUtility.ShouldUseActivity)
|
||||
{
|
||||
connectionListener = new TracingConnectionListener(connectionListener, this.ListenUri);
|
||||
}
|
||||
|
||||
connectionDemuxer = new ConnectionDemuxer(connectionListener,
|
||||
MaxPendingAccepts, MaxPendingConnections, ChannelInitializationTimeout,
|
||||
IdleTimeout, MaxPooledConnections,
|
||||
OnGetTransportFactorySettings,
|
||||
OnGetSingletonMessageHandler,
|
||||
OnHandleServerSessionPreamble,
|
||||
OnDemuxerError);
|
||||
|
||||
connectionDemuxer.StartDemuxing(onViaCallback);
|
||||
}
|
||||
|
||||
void OnOpenInternal(int queueId, Guid token)
|
||||
{
|
||||
lock (ThisLock)
|
||||
{
|
||||
this.queueId = queueId;
|
||||
this.token = token;
|
||||
|
||||
BaseUriWithWildcard path = new BaseUriWithWildcard(this.ListenUri, this.HostNameComparisonMode);
|
||||
|
||||
listener = new SharedConnectionListener(path, queueId, token, this.onDuplicatedViaCallback);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnClose(TimeSpan timeout)
|
||||
{
|
||||
}
|
||||
|
||||
void OnVia(Uri address)
|
||||
{
|
||||
Debug.Print("HostedNamedPipeTransportManager.OnVia() address: " + address + " calling EnsureServiceAvailable()");
|
||||
ServiceHostingEnvironment.EnsureServiceAvailable(address.LocalPath);
|
||||
}
|
||||
|
||||
protected override void OnSelecting(NamedPipeChannelListener channelListener)
|
||||
{
|
||||
if (settingsApplied)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (ThisLock)
|
||||
{
|
||||
if (settingsApplied)
|
||||
{
|
||||
// Use the setting for the first one.
|
||||
return;
|
||||
}
|
||||
|
||||
this.ApplyListenerSettings(channelListener);
|
||||
settingsApplied = true;
|
||||
}
|
||||
}
|
||||
|
||||
// This method is called only for the first via of the current proxy.
|
||||
int OnDuplicatedVia(Uri via)
|
||||
{
|
||||
OnVia(via);
|
||||
|
||||
if (!demuxerCreated)
|
||||
{
|
||||
lock (ThisLock)
|
||||
{
|
||||
if (listener == null)
|
||||
{
|
||||
// The listener has been stopped.
|
||||
throw FxTrace.Exception.AsError(new CommunicationObjectAbortedException(SR.PipeListenerProxyStopped));
|
||||
}
|
||||
|
||||
if (!demuxerCreated)
|
||||
{
|
||||
CreateConnectionDemuxer();
|
||||
demuxerCreated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.ConnectionBufferSize;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
class HostedTcpTransportManager : SharedTcpTransportManager
|
||||
{
|
||||
// Double-checked locking pattern requires volatile for read/write synchronization
|
||||
volatile bool settingsApplied;
|
||||
Action<Uri> onViaCallback;
|
||||
|
||||
public HostedTcpTransportManager(BaseUriWithWildcard baseAddress)
|
||||
: base(baseAddress.BaseAddress)
|
||||
{
|
||||
this.HostNameComparisonMode = baseAddress.HostNameComparisonMode;
|
||||
this.onViaCallback = new Action<Uri>(OnVia);
|
||||
}
|
||||
|
||||
internal void Start(int queueId, Guid token, Action messageReceivedCallback)
|
||||
{
|
||||
SetMessageReceivedCallback(messageReceivedCallback);
|
||||
OnOpenInternal(queueId, token);
|
||||
}
|
||||
|
||||
internal override void OnOpen()
|
||||
{
|
||||
// This is intentionally empty.
|
||||
}
|
||||
|
||||
internal override void OnClose(TimeSpan timeout)
|
||||
{
|
||||
// This is intentionally empty.
|
||||
}
|
||||
|
||||
internal override void OnAbort()
|
||||
{
|
||||
// This is intentionally empty.
|
||||
}
|
||||
|
||||
internal void Stop(TimeSpan timeout)
|
||||
{
|
||||
CleanUp(false, timeout);
|
||||
settingsApplied = false;
|
||||
}
|
||||
|
||||
protected override Action<Uri> GetOnViaCallback()
|
||||
{
|
||||
return this.onViaCallback;
|
||||
}
|
||||
|
||||
void OnVia(Uri address)
|
||||
{
|
||||
Debug.Print("HostedTcpTransportManager.OnVia() address: " + address + " calling EnsureServiceAvailable()");
|
||||
ServiceHostingEnvironment.EnsureServiceAvailable(address.LocalPath);
|
||||
}
|
||||
|
||||
protected override void OnSelecting(TcpChannelListener channelListener)
|
||||
{
|
||||
if (settingsApplied)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (ThisLock)
|
||||
{
|
||||
if (settingsApplied)
|
||||
{
|
||||
// Use the first one.
|
||||
return;
|
||||
}
|
||||
|
||||
this.ApplyListenerSettings(channelListener);
|
||||
settingsApplied = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[TypeForwardedFrom("System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
|
||||
public abstract class HostedTransportConfiguration
|
||||
{
|
||||
public abstract Uri[] GetBaseAddresses(string virtualPath);
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.Globalization;
|
||||
using System.Web.Hosting;
|
||||
using System.Web;
|
||||
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
abstract class HostedTransportConfigurationBase : HostedTransportConfiguration
|
||||
{
|
||||
List<BaseUriWithWildcard> listenAddresses;
|
||||
string scheme;
|
||||
|
||||
internal protected HostedTransportConfigurationBase(string scheme)
|
||||
{
|
||||
this.scheme = scheme;
|
||||
this.listenAddresses = new List<BaseUriWithWildcard>();
|
||||
}
|
||||
|
||||
internal string Scheme
|
||||
{
|
||||
get
|
||||
{
|
||||
return scheme;
|
||||
}
|
||||
}
|
||||
|
||||
internal protected IList<BaseUriWithWildcard> ListenAddresses
|
||||
{
|
||||
get
|
||||
{
|
||||
return listenAddresses;
|
||||
}
|
||||
}
|
||||
|
||||
public override Uri[] GetBaseAddresses(string virtualPath)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
Uri[] addresses = new Uri[listenAddresses.Count];
|
||||
for (int i = 0; i < listenAddresses.Count; i++)
|
||||
{
|
||||
string absoluteVirtualPath = VirtualPathUtility.ToAbsolute(virtualPath, HostingEnvironmentWrapper.ApplicationVirtualPath);
|
||||
addresses[i] = new Uri(listenAddresses[i].BaseAddress, absoluteVirtualPath);
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
internal BaseUriWithWildcard FindBaseAddress(Uri uri)
|
||||
{
|
||||
BaseUriWithWildcard foundBaseAddress = null;
|
||||
BaseUriWithWildcard weakBaseAddress = null;
|
||||
|
||||
for (int i = 0; i < listenAddresses.Count; i++)
|
||||
{
|
||||
if ((string.Compare(listenAddresses[i].BaseAddress.Scheme, uri.Scheme, StringComparison.OrdinalIgnoreCase) == 0)
|
||||
&& (listenAddresses[i].BaseAddress.Port == uri.Port))
|
||||
{
|
||||
if (listenAddresses[i].HostNameComparisonMode == HostNameComparisonMode.StrongWildcard)
|
||||
{
|
||||
return listenAddresses[i];
|
||||
}
|
||||
|
||||
if (listenAddresses[i].HostNameComparisonMode == HostNameComparisonMode.WeakWildcard)
|
||||
{
|
||||
weakBaseAddress = listenAddresses[i];
|
||||
}
|
||||
|
||||
if ((listenAddresses[i].HostNameComparisonMode == HostNameComparisonMode.Exact)
|
||||
&& (string.Compare(listenAddresses[i].BaseAddress.Host, uri.Host, StringComparison.OrdinalIgnoreCase) == 0))
|
||||
{
|
||||
foundBaseAddress = listenAddresses[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundBaseAddress == null)
|
||||
foundBaseAddress = weakBaseAddress;
|
||||
|
||||
return foundBaseAddress;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,275 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime;
|
||||
using System.Runtime.Diagnostics;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Configuration;
|
||||
using System.ServiceModel.Activation.Diagnostics;
|
||||
using System.ServiceModel.Diagnostics.Application;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
class HostedTransportConfigurationManager
|
||||
{
|
||||
IDictionary<string, HostedTransportConfiguration> configurations = new Dictionary<string, HostedTransportConfiguration>(StringComparer.Ordinal);
|
||||
|
||||
// Double-checked locking pattern requires volatile for read/write synchronization
|
||||
volatile bool initialized = false;
|
||||
MetabaseSettings metabaseSettings;
|
||||
|
||||
// Double-checked locking pattern requires volatile for read/write synchronization
|
||||
static volatile HostedTransportConfigurationManager singleton;
|
||||
static object syncRoot = new object();
|
||||
#pragma warning disable 436
|
||||
const string WasHostingAssemblyName = "System.ServiceModel.WasHosting, Version=" + ThisAssembly.Version + ", Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKey;
|
||||
const string MetabaseSettingsIis7FactoryTypeName = "System.ServiceModel.WasHosting.MetabaseSettingsIis7Factory, " + WasHostingAssemblyName;
|
||||
#pragma warning restore 436
|
||||
const string CreateMetabaseSettingsIis7MethodName = "CreateMetabaseSettings";
|
||||
|
||||
HostedTransportConfigurationManager()
|
||||
{
|
||||
if (!Iis7Helper.IsIis7)
|
||||
{
|
||||
metabaseSettings = new MetabaseSettingsIis6();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
metabaseSettings = CreateWasHostingMetabaseSettings();
|
||||
}
|
||||
}
|
||||
|
||||
HostedTransportConfigurationManager(MetabaseSettings metabaseSettings)
|
||||
{
|
||||
this.metabaseSettings = metabaseSettings;
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls Critical methods CreateMetabaseSettings.",
|
||||
Safe = "Ensures that only the correct, well-known method is called to construct the metabase settings. No other " +
|
||||
"details are leaked, and no control flow or data is allowed in.")]
|
||||
[SecuritySafeCritical]
|
||||
static MetabaseSettingsIis CreateWasHostingMetabaseSettings()
|
||||
{
|
||||
Type type = Type.GetType(MetabaseSettingsIis7FactoryTypeName, false);
|
||||
if (type == null)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_MetabaseSettingsIis7TypeNotFound(MetabaseSettingsIis7FactoryTypeName, WasHostingAssemblyName)));
|
||||
}
|
||||
return CreateMetabaseSettings(type);
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.SecureAsserts, Justification = "This is a private SecurityCritical method and its only caller passes in non-user data. Users cannot pass arbitrary data to this code.")]
|
||||
[Fx.Tag.SecurityNote(Critical = "Asserts full trust in order to call a well-known internal static in WasHosting.dll." +
|
||||
"Caller must ensure that 'type' argument refers to the trusted, well-known Type.")]
|
||||
[SecurityCritical]
|
||||
static MetabaseSettingsIis CreateMetabaseSettings(Type type)
|
||||
{
|
||||
object instance = null;
|
||||
MethodInfo method = type.GetMethod(CreateMetabaseSettingsIis7MethodName, BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
try
|
||||
{
|
||||
new PermissionSet(PermissionState.Unrestricted).Assert();
|
||||
|
||||
instance = method.Invoke(null, null);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PermissionSet.RevertAssert();
|
||||
}
|
||||
|
||||
if (!(instance is MetabaseSettingsIis))
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_BadMetabaseSettingsIis7Type(type.AssemblyQualifiedName)));
|
||||
}
|
||||
|
||||
return (MetabaseSettingsIis)instance;
|
||||
}
|
||||
|
||||
internal static void EnsureInitializedForSimpleApplicationHost(HostedHttpRequestAsyncResult result)
|
||||
{
|
||||
if (singleton != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (singleton != null)
|
||||
return;
|
||||
|
||||
singleton = new HostedTransportConfigurationManager(new MetabaseSettingsCassini(result));
|
||||
}
|
||||
}
|
||||
|
||||
internal static MetabaseSettings MetabaseSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
return HostedTransportConfigurationManager.Value.metabaseSettings;
|
||||
}
|
||||
}
|
||||
|
||||
object ThisLock
|
||||
{
|
||||
get
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
static HostedTransportConfigurationManager Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (singleton == null)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (singleton == null)
|
||||
{
|
||||
//Ensure ETW tracing is initialized
|
||||
System.ServiceModel.Diagnostics.TraceUtility.SetEtwProviderId();
|
||||
|
||||
if (TD.HostedTransportConfigurationManagerConfigInitStartIsEnabled())
|
||||
{
|
||||
TD.HostedTransportConfigurationManagerConfigInitStart();
|
||||
}
|
||||
ServiceHostingEnvironment.EnsureInitialized();
|
||||
singleton = new HostedTransportConfigurationManager();
|
||||
if (TD.HostedTransportConfigurationManagerConfigInitStopIsEnabled())
|
||||
{
|
||||
TD.HostedTransportConfigurationManagerConfigInitStop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return singleton;
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureInitialized()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
lock (ThisLock)
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
// Register protocols.
|
||||
foreach (string protocol in metabaseSettings.GetProtocols())
|
||||
{
|
||||
// special case HTTP, it's a legacy protocol
|
||||
if (string.CompareOrdinal(protocol, Uri.UriSchemeHttp) == 0 ||
|
||||
string.CompareOrdinal(protocol, Uri.UriSchemeHttps) == 0)
|
||||
{
|
||||
HttpHostedTransportConfiguration httpConfiguration = null;
|
||||
if (string.CompareOrdinal(protocol, Uri.UriSchemeHttp) == 0)
|
||||
{
|
||||
httpConfiguration = new HttpHostedTransportConfiguration();
|
||||
}
|
||||
else
|
||||
{
|
||||
httpConfiguration = new HttpsHostedTransportConfiguration();
|
||||
}
|
||||
|
||||
configurations.Add(protocol, httpConfiguration);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Iis7Helper.IsIis7)
|
||||
{
|
||||
throw Fx.AssertAndThrowFatal("HostedTransportConfigurationManager.EnsureInitialized() protocols other than http and https can only be configured in IIS7");
|
||||
}
|
||||
if (AspNetPartialTrustHelpers.NeedPartialTrustInvoke)
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.PartialTrustNonHttpActivation(protocol, HostingEnvironmentWrapper.ApplicationVirtualPath)));
|
||||
}
|
||||
AddHostedTransportConfigurationIis7(protocol);
|
||||
}
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddHostedTransportConfigurationIis7(string protocol)
|
||||
{
|
||||
HostedTransportConfiguration configuration = null;
|
||||
try
|
||||
{
|
||||
ServiceHostingEnvironmentSection section = ServiceHostingEnvironmentSection.GetSection();
|
||||
if (section.TransportConfigurationTypes.ContainsKey(protocol))
|
||||
{
|
||||
TransportConfigurationTypeElement element = section.TransportConfigurationTypes[protocol];
|
||||
Debug.Print("HostedTransportConfigurationManager.AddHostedTransportConfigurationIis7() found TransportConfigurationTypes for protocol: " + protocol + " name: " + element.TransportConfigurationType);
|
||||
|
||||
Type type = Type.GetType(element.TransportConfigurationType);
|
||||
configuration = Activator.CreateInstance(type) as HostedTransportConfiguration;
|
||||
configurations.Add(protocol, configuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_ProtocolNoConfiguration(protocol)));
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (!Fx.IsFatal(exception))
|
||||
{
|
||||
Debug.Print("HostedTransportConfigurationManager.AddHostedTransportConfigurationIis7() caught exception: " + exception);
|
||||
if (DiagnosticUtility.ShouldTraceError)
|
||||
{
|
||||
TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.WebHostProtocolMisconfigured, SR.TraceCodeWebHostProtocolMisconfigured,
|
||||
new StringTraceRecord("Protocol", protocol),
|
||||
this, exception);
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
internal static Uri[] GetBaseAddresses(string virtualPath)
|
||||
{
|
||||
return HostedTransportConfigurationManager.Value.InternalGetBaseAddresses(virtualPath);
|
||||
}
|
||||
|
||||
internal static HostedTransportConfiguration GetConfiguration(string scheme)
|
||||
{
|
||||
return HostedTransportConfigurationManager.Value.InternalGetConfiguration(scheme);
|
||||
}
|
||||
|
||||
Uri[] InternalGetBaseAddresses(string virtualPath)
|
||||
{
|
||||
EnsureInitialized();
|
||||
List<Uri> baseAddresses = new List<Uri>();
|
||||
foreach (HostedTransportConfiguration configuration in configurations.Values)
|
||||
{
|
||||
baseAddresses.AddRange(configuration.GetBaseAddresses(virtualPath));
|
||||
}
|
||||
|
||||
return baseAddresses.ToArray();
|
||||
}
|
||||
|
||||
HostedTransportConfiguration InternalGetConfiguration(string scheme)
|
||||
{
|
||||
EnsureInitialized();
|
||||
if (!configurations.ContainsKey(scheme))
|
||||
{
|
||||
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_NotSupportedProtocol(scheme)));
|
||||
}
|
||||
|
||||
return configurations[scheme];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
|
||||
// wrapper class that helps with partial trust analysis
|
||||
// -- HostingEnvironment does a number of Demands and LinkDemands
|
||||
// -- this wrapper encapsulates access into "Safe" and "Unsafe" methods that do the appropriate asserts
|
||||
// -- it is recommended that ALL HostingEnvironment access go through this class
|
||||
// -- "Safe" methods are [SecurityCritical, SecurityTreatAsSafe] or not [SecurityCritical]
|
||||
// -- "Unsafe" methods are [SecurityCritical]
|
||||
// -- because each method does precisely one access, we use declarative asserts for clarity
|
||||
static class HostingEnvironmentWrapper
|
||||
{
|
||||
public static string ApplicationVirtualPath
|
||||
{
|
||||
get
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.ApplicationVirtualPath;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsHosted
|
||||
{
|
||||
get { return HostingEnvironment.IsHosted; }
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.",
|
||||
Safe = "Does not leak control or mutable/harmful data, no potential for harm.")]
|
||||
public static VirtualPathProvider VirtualPathProvider
|
||||
{
|
||||
[SecuritySafeCritical]
|
||||
get
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.VirtualPathProvider;
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.",
|
||||
Safe = "Does not leak control or mutable/harmful data, no potential for harm.")]
|
||||
[SecuritySafeCritical]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void DecrementBusyCount()
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
HostingEnvironment.DecrementBusyCount();
|
||||
}
|
||||
|
||||
// demands SecurityPermission(ControlPrincipal) -- use Unsafe version to assert
|
||||
public static IDisposable Impersonate()
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.Impersonate();
|
||||
}
|
||||
|
||||
// demands SecurityPermission(Unrestricted) -- use Unsafe version to assert
|
||||
public static IDisposable Impersonate(IntPtr token)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.Impersonate(token);
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Calls getters with LinkDemands in ASP .NET objects.",
|
||||
Safe = "Does not leak control or mutable/harmful data, no potential for harm.")]
|
||||
[SecuritySafeCritical]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void IncrementBusyCount()
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
HostingEnvironment.IncrementBusyCount();
|
||||
}
|
||||
|
||||
public static string MapPath(string virtualPath)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.MapPath(virtualPath);
|
||||
}
|
||||
|
||||
public static string UnsafeApplicationID
|
||||
{
|
||||
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.SecureAsserts, Justification = "Users cannot pass arbitrary data to this code.")]
|
||||
[Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission in order to call HostingEnvironment.get_ApplicationID.")]
|
||||
[SecurityCritical]
|
||||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.Assert, Level = AspNetHostingPermissionLevel.High)]
|
||||
get
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.ApplicationID;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.SecureAsserts, Justification = "Users cannot pass arbitrary data to this code.")]
|
||||
[Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission in order to call HostingEnvironment.UnsafeImpersonate.")]
|
||||
[SecurityCritical]
|
||||
[SecurityPermission(SecurityAction.Assert, ControlPrincipal = true)]
|
||||
public static IDisposable UnsafeImpersonate()
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.Impersonate();
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission in order to call HostingEnvironment.UnsafeImpersonate.")]
|
||||
[SecurityCritical]
|
||||
[SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
|
||||
public static IDisposable UnsafeImpersonate(IntPtr token)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
return HostingEnvironment.Impersonate(token);
|
||||
}
|
||||
|
||||
[SuppressMessage(FxCop.Category.Security, FxCop.Rule.SecureAsserts, Justification = "This is an internal SecurityCritical method and its only caller passes in non-user data. Users cannot pass arbitrary data to this code.")]
|
||||
[Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission in order to call HostingEnvironment.RegisterObject.")]
|
||||
[SecurityCritical]
|
||||
[SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
|
||||
public static void UnsafeRegisterObject(IRegisteredObject target)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
HostingEnvironment.RegisterObject(target);
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Asserts SecurityPermission in order to call HostingEnvironment.UnregisterObject.")]
|
||||
[SecurityCritical]
|
||||
[SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
|
||||
public static void UnsafeUnregisterObject(IRegisteredObject target)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
HostingEnvironment.UnregisterObject(target);
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Uses SecurityCritical method UnsafeImpersonate in order to check whether the service file exists.",
|
||||
Safe = "Does not leak anything, does not let caller influence impersonation.")]
|
||||
[SecuritySafeCritical]
|
||||
public static bool ServiceFileExists(string normalizedVirtualPath)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
|
||||
IDisposable unsafeImpersonate = null;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate();
|
||||
}
|
||||
return HostingEnvironment.VirtualPathProvider.FileExists(normalizedVirtualPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (null != unsafeImpersonate)
|
||||
{
|
||||
unsafeImpersonate.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Uses SecurityCritical method UnsafeImpersonate in order to get service file.",
|
||||
Safe = "Does not leak anything, does not let caller influence impersonation.")]
|
||||
[SecuritySafeCritical]
|
||||
public static VirtualFile GetServiceFile(string normalizedVirtualPath)
|
||||
{
|
||||
AspNetPartialTrustHelpers.FailIfInPartialTrustOutsideAspNet();
|
||||
|
||||
IDisposable unsafeImpersonate = null;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
unsafeImpersonate = HostingEnvironmentWrapper.UnsafeImpersonate();
|
||||
}
|
||||
return HostingEnvironment.VirtualPathProvider.GetFile(normalizedVirtualPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (null != unsafeImpersonate)
|
||||
{
|
||||
unsafeImpersonate.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//----------------------------------------------------------------------------
|
||||
namespace System.ServiceModel.Activation
|
||||
{
|
||||
using System.Runtime;
|
||||
using System.Security;
|
||||
using System.ServiceModel;
|
||||
|
||||
sealed class HostingMessageProperty : IAspNetMessageProperty
|
||||
{
|
||||
const string name = "webhost";
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Keeps track of impersonated user, caller must use with care and call Dispose at the appropriate time.")]
|
||||
[SecurityCritical]
|
||||
HostedImpersonationContext impersonationContext;
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Stores a SecurityCritical helper class that controls HttpContext.Current with an elevation." +
|
||||
"Need to ensure that HostedThreadData is constructed and used properly.")]
|
||||
[SecurityCritical]
|
||||
HostedThreadData currentThreadData;
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Sets impersonation context from an arbitrary source, caller must guard.")]
|
||||
[SecurityCritical]
|
||||
internal HostingMessageProperty(HostedHttpRequestAsyncResult result)
|
||||
{
|
||||
Fx.Assert(ServiceHostingEnvironment.IsHosted, "should only be called in the hosted path");
|
||||
|
||||
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled)
|
||||
{
|
||||
if (result.ImpersonationContext != null && result.ImpersonationContext.IsImpersonated)
|
||||
{
|
||||
this.impersonationContext = result.ImpersonationContext;
|
||||
this.impersonationContext.AddRef();
|
||||
}
|
||||
|
||||
currentThreadData = result.HostedThreadData;
|
||||
}
|
||||
|
||||
this.OriginalRequestUri = result.OriginalRequestUri;
|
||||
}
|
||||
|
||||
public Uri OriginalRequestUri
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
static internal string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
HostedImpersonationContext ImpersonationContext
|
||||
{
|
||||
[Fx.Tag.SecurityNote(Critical = "Keeps track of impersonated user, caller must use with care.",
|
||||
Safe = "Safe for Get, individual members of HostedImpersonationContext are protected.")]
|
||||
[SecuritySafeCritical]
|
||||
get
|
||||
{
|
||||
return impersonationContext;
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Delegates to a SecurityCritical method in HostedThreadData." +
|
||||
"Caller must ensure that function is called appropriately and result is guarded and Dispose()'d correctly.")]
|
||||
[SecurityCritical]
|
||||
public IDisposable ApplyIntegrationContext()
|
||||
{
|
||||
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled)
|
||||
{
|
||||
return currentThreadData.CreateContext();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical method HostedImpersonationContext.Impersonate." +
|
||||
"Caller should use with care, must take responsibility for reverting impersonation.")]
|
||||
[SecurityCritical]
|
||||
public IDisposable Impersonate()
|
||||
{
|
||||
if (this.ImpersonationContext != null)
|
||||
{
|
||||
return this.ImpersonationContext.Impersonate();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[Fx.Tag.SecurityNote(Critical = "Cleans up impersonationContext, which is critical.", Safe = "Doesn't leak anything.")]
|
||||
[SecuritySafeCritical]
|
||||
public void Close()
|
||||
{
|
||||
if (impersonationContext != null)
|
||||
{
|
||||
impersonationContext.Release();
|
||||
impersonationContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user