1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
|
//------------------------------------------------------------------------------
// <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;
}
}
}
}
|