internal static void RemoveThisAppDomainFromUnmanagedTable() { if (Interlocked.Exchange(ref s_isThisAppDomainRemovedFromUnmanagedTable, 1) != 0) { return; } // // only notify mgdeng of this shutdown if we went through // Initialize from the there // We can also have PipelineRuntime in app domains with only // other protocols // try { if (s_thisAppDomainsIsapiAppId != null && s_ApplicationContext != IntPtr.Zero) { Debug.Trace("PipelineDomain", "Calling MgdAppDomainShutdown appId=" + s_thisAppDomainsIsapiAppId + " (AppDomainAppId=" + HttpRuntime.AppDomainAppId + ")"); UnsafeIISMethods.MgdAppDomainShutdown(s_ApplicationContext); } HttpRuntime.AddAppDomainTraceMessage(SR.GetString(SR.App_Domain_Restart)); } catch (Exception e) { if (ShouldRethrowException(e)) { throw; } } }
internal static void DisposeHandler(HttpContext context, IntPtr nativeRequestContext, RequestNotificationStatus status) { if (UnsafeIISMethods.MgdCanDisposeManagedContext(nativeRequestContext, status)) { DisposeHandlerPrivate(context); } }
// called from managed code as a perf optimization to avoid calling back later internal static void DisposeHandler(HttpContext context, IntPtr nativeRequestContext, RequestNotificationStatus status) { if (IIS.MgdCanDisposeManagedContext(nativeRequestContext, status)) { context.RootedObjects.Destroy(); } }
internal static void PreloadApplicationIfNotShuttingdown(string appId, LockableAppDomainContext ac) { WaitCallback callBack = null; if ((DefaultHost != null) && UnsafeIISMethods.MgdHasConfigChanged()) { if (callBack == null) { callBack = delegate(object o) { lock (ac) { try { DefaultHost.PreloadApplicationIfRequired(appId, null, null, ac); } catch (Exception exception) { DefaultHost.ReportApplicationPreloadFailureWithAssert(ac.PreloadContext, -2147467259, Misc.FormatExceptionMessage(exception, new string[] { System.Web.SR.GetString("Failure_Preload_Application_Initialization") })); } } }; } ThreadPool.QueueUserWorkItem(callBack); } }
public void StopProcessing() { if (UnsafeIISMethods.MgdHasConfigChanged() && !HostingEnvironment.ShutdownInitiated) { HttpRuntime.SetShutdownReason(ApplicationShutdownReason.ConfigurationChange, "IIS configuration change"); } s_StopProcessingCalled = true; HostingEnvironment.InitiateShutdownWithoutDemand(); }
private static void InitializeRequestContext(IntPtr nativeRequestContext, int flags, out IIS7WorkerRequest wr, out HttpContext context) { wr = null; context = null; try { bool etwProviderEnabled = (flags & 0x40) == 0x40; wr = IIS7WorkerRequest.CreateWorkerRequest(nativeRequestContext, etwProviderEnabled); context = new HttpContext(wr, false); } catch { UnsafeIISMethods.MgdSetBadRequestStatus(nativeRequestContext); } }
private static void InitializeRequestContext(IntPtr nativeRequestContext, int flags, out IIS7WorkerRequest wr, out HttpContext context) { wr = null; context = null; try { bool etwEnabled = ((flags & HttpContext.FLAG_ETW_PROVIDER_ENABLED) == HttpContext.FLAG_ETW_PROVIDER_ENABLED); // this may throw, e.g. if the request Content-Length header has a value greater than Int32.MaxValue wr = IIS7WorkerRequest.CreateWorkerRequest(nativeRequestContext, etwEnabled); // this may throw, e.g. see WOS 1724573: ASP.Net v2.0: wrong error code returned when ? is used in the URL context = new HttpContext(wr, false); } catch { // treat as "400 Bad Request" since that's the only reason the HttpContext.ctor should throw IIS.MgdSetBadRequestStatus(nativeRequestContext); } }
public void InitializeApplication(IntPtr appContext) { s_ApplicationContext = appContext; HttpApplication app = null; try { HttpRuntime.UseIntegratedPipeline = true; if (!HttpRuntime.HostingInitFailed) { HttpWorkerRequest wr = new SimpleWorkerRequest("", "", new StringWriter(CultureInfo.InvariantCulture)); HttpContext context = new HttpContext(wr); app = HttpApplicationFactory.GetPipelineApplicationInstance(appContext, context); } } catch (Exception exception) { if (HttpRuntime.InitializationException == null) { HttpRuntime.InitializationException = exception; } } finally { s_InitializationCompleted = true; if (HttpRuntime.InitializationException != null) { int errorCode = UnsafeIISMethods.MgdRegisterEventSubscription(appContext, "AspNetInitializationExceptionModule", RequestNotification.BeginRequest, 0, "AspNetInitializationExceptionModule", "", new IntPtr(-1), false); if (errorCode < 0) { throw new COMException(System.Web.SR.GetString("Failed_Pipeline_Subscription", new object[] { "AspNetInitializationExceptionModule" }), errorCode); } errorCode = UnsafeIISMethods.MgdRegisterEventSubscription(appContext, "ManagedPipelineHandler", RequestNotification.ExecuteRequestHandler, 0, string.Empty, "managedHandler", new IntPtr(-1), false); if (errorCode < 0) { throw new COMException(System.Web.SR.GetString("Failed_Pipeline_Subscription", new object[] { "ManagedPipelineHandler" }), errorCode); } } if (app != null) { HttpApplicationFactory.RecyclePipelineApplicationInstance(app); } } }
internal static void RemoveThisAppDomainFromUnmanagedTable() { if (Interlocked.Exchange(ref s_isThisAppDomainRemovedFromUnmanagedTable, 1) == 0) { try { if ((s_thisAppDomainsIsapiAppId != null) && (s_ApplicationContext != IntPtr.Zero)) { UnsafeIISMethods.MgdAppDomainShutdown(s_ApplicationContext); } HttpRuntime.AddAppDomainTraceMessage(System.Web.SR.GetString("App_Domain_Restart")); } catch (Exception exception) { if (ShouldRethrowException(exception)) { throw; } } } }
internal static int ProcessRequestNotificationHelper( IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, int flags) { IIS7WorkerRequest wr = null; HttpContext context = null; RequestNotificationStatus status = RequestNotificationStatus.Continue; RootedObjects root; bool workerRequestWasJustCreated = false; if (rootedObjectsPointer == IntPtr.Zero) { InitializeRequestContext(nativeRequestContext, flags, out wr, out context); workerRequestWasJustCreated = true; if (context == null) { return((int)RequestNotificationStatus.FinishRequest); } root = RootedObjects.Create(); root.HttpContext = context; root.WorkerRequest = wr; root.WriteTransferEventIfNecessary(); context.RootedObjects = root; IIS.MgdSetManagedHttpContext(nativeRequestContext, root.Pointer); } else { root = RootedObjects.FromPointer(rootedObjectsPointer); context = root.HttpContext; wr = root.WorkerRequest as IIS7WorkerRequest; } Debug.Assert(root != null, "We should have a RootedObjects instance by this point."); Debug.Assert(wr != null, "We should have an IIS7WorkerRequest instance by this point."); using (root.WithinTraceBlock()) { if (workerRequestWasJustCreated) { AspNetEventSource.Instance.RequestStarted(wr); } int currentModuleIndex; bool isPostNotification; int currentNotification; IIS.MgdGetCurrentNotificationInfo(nativeRequestContext, out currentModuleIndex, out isPostNotification, out currentNotification); // If the HttpContext is null at this point, then we've already transitioned this request to a WebSockets request. // The WebSockets module should already be running, and asynchronous module-level events (like SendResponse) are // ineligible to be hooked by managed code. if (context == null || context.HasWebSocketRequestTransitionStarted) { return((int)RequestNotificationStatus.Continue); } // It is possible for a notification to complete asynchronously while we're in // a call to IndicateCompletion, in which case a new IIS thread might enter before // the call to IndicateCompletion returns. If this happens, block the thread until // IndicateCompletion returns. But never block a SendResponse notification, because // that can cause the request to hang (DevDiv Bugs 187441). if (context.InIndicateCompletion && context.ThreadInsideIndicateCompletion != Thread.CurrentThread && RequestNotification.SendResponse != (RequestNotification)currentNotification) { while (context.InIndicateCompletion) { Thread.Sleep(10); } } // RQ_SEND_RESPONSE fires out of band and completes synchronously only. // The pipeline must be reentrant to support this, so the notification // context for the previous notification must be saved and restored. NotificationContext savedNotificationContext = context.NotificationContext; bool cancellable = context.IsInCancellablePeriod; bool locked = false; try { if (cancellable) { context.EndCancellablePeriod(); } bool isReEntry = (savedNotificationContext != null); if (isReEntry) { context.ApplicationInstance.AcquireNotifcationContextLock(ref locked); } context.NotificationContext = new NotificationContext(flags /*CurrentNotificationFlags*/, isReEntry); status = HttpRuntime.ProcessRequestNotification(wr, context); } finally { if (status != RequestNotificationStatus.Pending) { // if we completed the notification, pop the notification context stack // if this is an asynchronous unwind, then the completion will clear the context context.NotificationContext = savedNotificationContext; // DevDiv 112755 restore cancellable state if its changed if (cancellable && !context.IsInCancellablePeriod) { context.BeginCancellablePeriod(); } else if (!cancellable && context.IsInCancellablePeriod) { context.EndCancellablePeriod(); } } if (locked) { context.ApplicationInstance.ReleaseNotifcationContextLock(); } } if (status != RequestNotificationStatus.Pending) { // The current notification may have changed due to the HttpApplication progressing the IIS state machine, so retrieve the info again. IIS.MgdGetCurrentNotificationInfo(nativeRequestContext, out currentModuleIndex, out isPostNotification, out currentNotification); // WOS 1785741: (Perf) In profiles, 8% of HelloWorld is transitioning from native to managed. // The fix is to keep managed code on the stack so that the AppDomain context remains on the // thread, and we can re-enter managed code without setting up the AppDomain context. // If this optimization is possible, MgdIndicateCompletion will execute one or more notifications // and return PENDING as the status. ThreadContext threadContext = context.IndicateCompletionContext; // DevDiv 482614: // Don't use local copy to detect if we can call MgdIndicateCompletion because another thread // unwinding from MgdIndicateCompletion may be changing context.IndicateCompletionContext at the same time. if (!context.InIndicateCompletion && context.IndicateCompletionContext != null) { if (status == RequestNotificationStatus.Continue) { try { context.InIndicateCompletion = true; Interlocked.Increment(ref _inIndicateCompletionCount); context.ThreadInsideIndicateCompletion = Thread.CurrentThread; IIS.MgdIndicateCompletion(nativeRequestContext, ref status); } finally { context.ThreadInsideIndicateCompletion = null; Interlocked.Decrement(ref _inIndicateCompletionCount); // Leave will have been called already if the last notification is returning pending // DTS267762: Make sure InIndicateCompletion is released, not based on the thread context state // Otherwise the next request notification may deadlock if (!threadContext.HasBeenDisassociatedFromThread || context.InIndicateCompletion) { lock (threadContext) { if (!threadContext.HasBeenDisassociatedFromThread) { threadContext.DisassociateFromCurrentThread(); } context.IndicateCompletionContext = null; context.InIndicateCompletion = false; } } } } else { if (!threadContext.HasBeenDisassociatedFromThread || context.InIndicateCompletion) { lock (threadContext) { if (!threadContext.HasBeenDisassociatedFromThread) { threadContext.DisassociateFromCurrentThread(); } context.IndicateCompletionContext = null; context.InIndicateCompletion = false; } } } } } if (context.HasWebSocketRequestTransitionStarted && status == RequestNotificationStatus.Pending) { // At this point, the WebSocket module event (PostEndRequest) has executed and set up the appropriate contexts for us. // However, there is a race condition that we need to avoid. It is possible that one thread has kicked off some async // work, e.g. via an IHttpAsyncHandler, and that thread is unwinding and has reached this line of execution. // Meanwhile, the IHttpAsyncHandler completed quickly (but asynchronously) and invoked MgdPostCompletion, which // resulted in a new thread calling ProcessRequestNotification. If this second thread starts the WebSocket transition, // then there's the risk that *both* threads might attempt to call WebSocketPipeline.ProcessRequest, which could AV // the process. // // We protect against this by allowing only the thread which started the transition to complete the transition, so in // the above scenario the original thread (which invoked the IHttpAsyncHandler) no-ops at this point and just returns // Pending to its caller. if (context.DidCurrentThreadStartWebSocketTransition) { // We'll mark the HttpContext as complete, call the continuation to kick off the socket send / receive loop, and return // Pending to IIS so that it doesn't advance the state machine until the WebSocket loop completes. root.ReleaseHttpContext(); root.WebSocketPipeline.ProcessRequest(); } } return((int)status); } }
public void InitializeApplication(IntPtr appContext) { s_ApplicationContext = appContext; // DevDiv #381425 - webengine4!RegisterModule runs *after* HostingEnvironment.Initialize (and thus the // HttpRuntime static ctor) when application preload is active. This means that any global state set // by RegisterModule (like the IIS version information, whether we're in integrated mode, misc server // info, etc.) will be unavailable to PreAppStart / preload code when the preload feature is active. // But since RegisterModule runs before InitializeApplication, we have one last chance here to collect // the information before the main part of the application starts, and the pipeline can depend on it // to be accurate. HttpRuntime.PopulateIISVersionInformation(); HttpApplication app = null; try { // if HttpRuntime.HostingInit failed, do not attempt to create the application (WOS #1653963) if (!HttpRuntime.HostingInitFailed) { // // On IIS7, application initialization does not provide an http context. Theoretically, // no one should be using the context during application initialization, but people do. // Create a dummy context that is used during application initialization // to prevent breakage (ISAPI mode always provides a context) // HttpWorkerRequest initWorkerRequest = new SimpleWorkerRequest("" /*page*/, "" /*query*/, new StringWriter(CultureInfo.InvariantCulture)); MimeMapping.SetIntegratedApplicationContext(appContext); HttpContext initHttpContext = new HttpContext(initWorkerRequest); app = HttpApplicationFactory.GetPipelineApplicationInstance(appContext, initHttpContext); } } catch (Exception e) { if (HttpRuntime.InitializationException == null) { HttpRuntime.InitializationException = e; } } finally { s_InitializationCompleted = true; if (HttpRuntime.InitializationException != null) { // at least one module must be registered so that we // call ProcessRequestNotification later and send the formatted // InitializationException to the client. int hresult = UnsafeIISMethods.MgdRegisterEventSubscription( appContext, InitExceptionModuleName, RequestNotification.BeginRequest, 0 /*postRequestNotifications*/, InitExceptionModuleName, s_InitExceptionModulePrecondition, new IntPtr(-1), false /*useHighPriority*/); if (hresult < 0) { throw new COMException(SR.GetString(SR.Failed_Pipeline_Subscription, InitExceptionModuleName), hresult); } // Always register a managed handler: // WOS 1990290: VS F5 Debugging: "AspNetInitializationExceptionModule" is registered for RQ_BEGIN_REQUEST, // but the DEBUG verb skips notifications until post RQ_AUTHENTICATE_REQUEST. hresult = UnsafeIISMethods.MgdRegisterEventSubscription( appContext, HttpApplication.IMPLICIT_HANDLER, RequestNotification.ExecuteRequestHandler /*requestNotifications*/, 0 /*postRequestNotifications*/, String.Empty /*type*/, HttpApplication.MANAGED_PRECONDITION /*precondition*/, new IntPtr(-1), false /*useHighPriority*/); if (hresult < 0) { throw new COMException(SR.GetString(SR.Failed_Pipeline_Subscription, HttpApplication.IMPLICIT_HANDLER), hresult); } } if (app != null) { HttpApplicationFactory.RecyclePipelineApplicationInstance(app); } } }
internal static int ProcessRequestNotificationHelper(IntPtr managedHttpContext, IntPtr nativeRequestContext, IntPtr moduleData, int flags) { IIS7WorkerRequest wr = null; HttpContext context = null; RequestNotificationStatus notificationStatus = RequestNotificationStatus.Continue; if (managedHttpContext == IntPtr.Zero) { InitializeRequestContext(nativeRequestContext, flags, out wr, out context); if (context == null) { return(2); } context.Root(); UnsafeIISMethods.MgdSetManagedHttpContext(nativeRequestContext, context.ContextPtr); HttpRuntime.IncrementActivePipelineCount(); } else { context = UnwrapContext(managedHttpContext); wr = context.WorkerRequest as IIS7WorkerRequest; } if ((context.InIndicateCompletion && (context.CurrentThread != Thread.CurrentThread)) && (0x20000000 != UnsafeIISMethods.MgdGetCurrentNotification(nativeRequestContext))) { while (context.InIndicateCompletion) { Thread.Sleep(10); } } NotificationContext notificationContext = context.NotificationContext; bool locked = false; try { bool isReEntry = notificationContext != null; if (isReEntry) { context.ApplicationInstance.AcquireNotifcationContextLock(ref locked); } context.NotificationContext = new NotificationContext(flags, isReEntry); notificationStatus = HttpRuntime.ProcessRequestNotification(wr, context); } finally { if (notificationStatus != RequestNotificationStatus.Pending) { context.NotificationContext = notificationContext; } if (locked) { context.ApplicationInstance.ReleaseNotifcationContextLock(); } } if (notificationStatus != RequestNotificationStatus.Pending) { HttpApplication.ThreadContext indicateCompletionContext = context.IndicateCompletionContext; if (!context.InIndicateCompletion && (indicateCompletionContext != null)) { if (notificationStatus == RequestNotificationStatus.Continue) { try { context.InIndicateCompletion = true; Interlocked.Increment(ref _inIndicateCompletionCount); UnsafeIISMethods.MgdIndicateCompletion(nativeRequestContext, ref notificationStatus); goto Label_01C2; } finally { Interlocked.Decrement(ref _inIndicateCompletionCount); if (!indicateCompletionContext.HasLeaveBeenCalled) { lock (indicateCompletionContext) { if (!indicateCompletionContext.HasLeaveBeenCalled) { indicateCompletionContext.Leave(); context.IndicateCompletionContext = null; context.InIndicateCompletion = false; } } } } } if (!indicateCompletionContext.HasLeaveBeenCalled) { lock (indicateCompletionContext) { if (!indicateCompletionContext.HasLeaveBeenCalled) { indicateCompletionContext.Leave(); context.IndicateCompletionContext = null; context.InIndicateCompletion = false; } } } } } Label_01C2: return((int)notificationStatus); }