Welcome to mirror list, hosted at ThFree Co, Russian Federation.

PipelineModuleStepContainer.cs « System.Web « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0d2b49071d8f8b494918c8415c29bda5f36c7141 (plain)
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;
            }
        }
    }
}