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();
     }
 }
Ejemplo n.º 4
0
        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);
        }