536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
260 lines
9.6 KiB
C#
260 lines
9.6 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="PipelineModuleStepContainer.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* A simple container class for module events
|
|
*
|
|
* Copyright (c) 2005 Microsoft Corporation
|
|
*/
|
|
|
|
namespace System.Web {
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Web;
|
|
using Debug=System.Web.Util.Debug;
|
|
|
|
// this class is a container for application module events
|
|
// there is one instance of this class per module per application instance
|
|
// Since execution steps are tied to an application instance, this needs to be
|
|
// as well
|
|
internal sealed class PipelineModuleStepContainer {
|
|
|
|
#if DBG
|
|
string _moduleName;
|
|
|
|
internal string DebugModuleName {
|
|
set {
|
|
Debug.Assert( !String.IsNullOrEmpty(value), "!String.IsNullOrEmpty(value)");
|
|
if (_moduleName != null) {
|
|
// make sure we're not ever crossing the modules
|
|
Debug.Assert(value == _moduleName, "value == _moduleName");
|
|
}
|
|
|
|
_moduleName = value;
|
|
}
|
|
get {
|
|
return (String.IsNullOrEmpty(_moduleName)) ? String.Empty : _moduleName;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// request notifications are bit flags in a DWORD
|
|
// so we will won't have more than 12
|
|
// we could do with fewer but in order simplify indexing,
|
|
// we'll use the whole 12
|
|
// the arrays are lazily allocated so modules that only
|
|
// subscribe to one type of event will only get one type of step arr
|
|
List<HttpApplication.IExecutionStep>[] _moduleSteps;
|
|
List<HttpApplication.IExecutionStep>[] _modulePostSteps;
|
|
|
|
internal PipelineModuleStepContainer() {
|
|
}
|
|
|
|
private List<HttpApplication.IExecutionStep> GetStepArray(RequestNotification notification, bool isPostEvent) {
|
|
|
|
#if DBG
|
|
Debug.Trace("PipelineRuntime",
|
|
"GetStepArray for " + DebugModuleName + " for " + notification.ToString() +
|
|
" and " + isPostEvent + "\r\n");
|
|
#endif
|
|
|
|
List<HttpApplication.IExecutionStep>[] steps = _moduleSteps;
|
|
|
|
if (isPostEvent) {
|
|
steps = _modulePostSteps;
|
|
}
|
|
|
|
Debug.Assert(null != steps, "null != steps");
|
|
|
|
int index = EventToIndex(notification);
|
|
Debug.Assert(index != -1, "index != -1");
|
|
|
|
Debug.Trace("PipelineRuntime",
|
|
"GetStepArray: " + notification.ToString() + " mapped to index " + index.ToString(CultureInfo.InvariantCulture) + "\r\n");
|
|
|
|
List<HttpApplication.IExecutionStep> stepArray = steps[index];
|
|
// we shouldn't be asking for events that aren't mapped to this
|
|
// module at all
|
|
Debug.Assert(null != stepArray, "null != stepArray");
|
|
|
|
return stepArray;
|
|
}
|
|
|
|
internal int GetEventCount(RequestNotification notification, bool isPostEvent) {
|
|
List<HttpApplication.IExecutionStep> stepArray = GetStepArray(notification, isPostEvent);
|
|
if (null == stepArray) {
|
|
return 0;
|
|
}
|
|
|
|
return stepArray.Count;
|
|
}
|
|
|
|
internal HttpApplication.IExecutionStep GetNextEvent(RequestNotification notification, bool isPostEvent, int eventIndex) {
|
|
List<HttpApplication.IExecutionStep> stepArray = GetStepArray(notification, isPostEvent);
|
|
|
|
Debug.Assert(eventIndex >= 0, "eventIndex >= 0");
|
|
Debug.Assert(eventIndex < stepArray.Count, "eventIndex < stepArray.Count");
|
|
|
|
return stepArray[eventIndex];
|
|
}
|
|
|
|
internal void RemoveEvent(RequestNotification notification, bool isPostEvent, Delegate handler) {
|
|
|
|
// if module instances unregister multiple times, this can fail on subsequent attempts
|
|
// so don't use GetStepArray which does extra checked verification
|
|
List<HttpApplication.IExecutionStep>[] steps = _moduleSteps;
|
|
|
|
if (isPostEvent) {
|
|
steps = _modulePostSteps;
|
|
}
|
|
|
|
if (steps == null) {
|
|
return;
|
|
}
|
|
|
|
int index = EventToIndex(notification);
|
|
List<HttpApplication.IExecutionStep> stepArray = steps[index];
|
|
|
|
if (null == stepArray) {
|
|
return;
|
|
}
|
|
|
|
|
|
int toRemove = -1;
|
|
|
|
HttpApplication.SyncEventExecutionStep syncStep;
|
|
for (int i = 0; i < stepArray.Count; i++ ) {
|
|
|
|
// we don't support removing async event handlers
|
|
// but the event syntax forces us to handle sync events
|
|
syncStep = stepArray[i] as HttpApplication.SyncEventExecutionStep;
|
|
if (null != syncStep) {
|
|
if (syncStep.Handler == (EventHandler)handler) {
|
|
toRemove = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (toRemove != -1) {
|
|
stepArray.RemoveAt(toRemove);
|
|
}
|
|
}
|
|
|
|
|
|
internal void AddEvent(RequestNotification notification, bool isPostEvent, HttpApplication.IExecutionStep step) {
|
|
int index = EventToIndex(notification);
|
|
#if DBG
|
|
Debug.Trace("PipelineRuntime", "Adding event: " + DebugModuleName + " " + notification.ToString() + " " +
|
|
isPostEvent.ToString() + "@ index " + index.ToString(CultureInfo.InvariantCulture) + "\r\n");
|
|
#endif
|
|
|
|
Debug.Assert(index != -1, "index != -1");
|
|
|
|
List<HttpApplication.IExecutionStep>[] steps = null;
|
|
|
|
if (isPostEvent) {
|
|
if (null == _modulePostSteps) {
|
|
_modulePostSteps = new List<HttpApplication.IExecutionStep>[ 32 ];
|
|
}
|
|
steps = _modulePostSteps;
|
|
}
|
|
else {
|
|
if (null == _moduleSteps) {
|
|
_moduleSteps = new List<HttpApplication.IExecutionStep>[ 32 ];
|
|
}
|
|
|
|
steps = _moduleSteps;
|
|
}
|
|
|
|
Debug.Assert(steps != null, "steps != null");
|
|
|
|
// retrieve the steps for this event (typically none at this point)
|
|
// allocate a new container as necessary and add this step
|
|
// in the event that a single module has registered more than once
|
|
// for a given event, we'll have multiple steps here
|
|
List<HttpApplication.IExecutionStep> stepArray = steps[index];
|
|
if (null == stepArray) {
|
|
// first touch, instantiate and save it
|
|
stepArray = new List<HttpApplication.IExecutionStep>();
|
|
steps[index] = stepArray;
|
|
}
|
|
|
|
stepArray.Add(step);
|
|
}
|
|
|
|
// we have tried various techniques here for converting a request notification
|
|
// into an index but a simple switch statement has so far performed the best
|
|
// basically, the problem is converting a single on bit to its position
|
|
// so 0x00000001 == 0, 0x00000002 == 1, etc.
|
|
// Managed code doesn't support all the request flags so we only translate
|
|
// the ones we deal with to keep the switch table as simple as possible
|
|
private static int EventToIndex(RequestNotification notification) {
|
|
int index = -1;
|
|
|
|
switch (notification) {
|
|
// 0x00000001
|
|
case RequestNotification.BeginRequest:
|
|
return 0;
|
|
|
|
// 0x00000002
|
|
case RequestNotification.AuthenticateRequest:
|
|
return 1;
|
|
|
|
// 0x00000004
|
|
case RequestNotification.AuthorizeRequest:
|
|
return 2;
|
|
|
|
// 0x00000008
|
|
case RequestNotification.ResolveRequestCache:
|
|
return 3;
|
|
|
|
// 0x00000010
|
|
case RequestNotification.MapRequestHandler:
|
|
return 4;
|
|
|
|
// 0x00000020
|
|
case RequestNotification.AcquireRequestState:
|
|
return 5;
|
|
|
|
// 0x00000040
|
|
case RequestNotification.PreExecuteRequestHandler:
|
|
return 6;
|
|
|
|
// 0x00000080
|
|
case RequestNotification.ExecuteRequestHandler:
|
|
return 7;
|
|
|
|
// 0x00000100
|
|
case RequestNotification.ReleaseRequestState:
|
|
return 8;
|
|
|
|
// 0x00000200
|
|
case RequestNotification.UpdateRequestCache:
|
|
return 9;
|
|
|
|
// 0x00000400
|
|
case RequestNotification.LogRequest:
|
|
return 10;
|
|
|
|
// 0x00000800
|
|
case RequestNotification.EndRequest:
|
|
return 11;
|
|
|
|
// 0x20000000
|
|
case RequestNotification.SendResponse :
|
|
return 12;
|
|
|
|
default:
|
|
Debug.Assert(index != -1, "invalid request notification--need to update switch table?");
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|