2002-10-08 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpApplication.cs
1 // \r
2 // System.Web.HttpApplication\r
3 //\r
4 // Author:\r
5 //   Patrik Torstensson (ptorsten@hotmail.com)\r
6 //      Tim Coleman (tim@timcoleman.com)\r
7 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)\r
8 //\r
9 using System;\r
10 using System.Collections;\r
11 using System.ComponentModel;\r
12 using System.Threading;\r
13 using System.Security.Principal;\r
14 using System.Runtime.Remoting.Messaging;\r
15 using System.Web.UI;\r
16 using System.Web.Configuration;\r
17 using System.Web.SessionState;\r
18 \r
19 namespace System.Web {\r
20         [ToolboxItem(true)]\r
21         [MonoTODO()]\r
22    public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable {\r
23 \r
24                 #region Event Handlers\r
25 \r
26                 // Async event holders\r
27                 AsyncEvents _acquireRequestStateAsync;\r
28                 AsyncEvents _authenticateRequestAsync;\r
29                 AsyncEvents _endRequestAsync;\r
30                 AsyncEvents _beginRequestAsync;\r
31                 AsyncEvents _authorizeRequestAsync;\r
32                 AsyncEvents _updateRequestCacheAsync;\r
33                 AsyncEvents _resolveRequestCacheAsync;\r
34                 AsyncEvents _releaseRequestStateAsync;\r
35                 AsyncEvents _preRequestHandlerExecuteAsync;\r
36                 AsyncEvents _postRequestHandlerExecuteAsync;\r
37                 \r
38                 // ID objects used to indentify the event\r
39                 static object AcquireRequestStateId = new Object();\r
40                 static object AuthenticateRequestId = new Object();\r
41                 static object EndRequestId = new Object();\r
42                 static object DisposedId = new Object();\r
43                 static object BeginRequestId = new Object();\r
44                 static object AuthorizeRequestId = new Object();\r
45                 static object UpdateRequestCacheId = new Object();\r
46                 static object ResolveRequestCacheId = new Object();\r
47                 static object ReleaseRequestStateId = new Object();\r
48                 static object PreSendRequestContentId = new Object();\r
49                 static object PreSendRequestHeadersId = new Object();\r
50                 static object PreRequestHandlerExecuteId = new Object();\r
51                 static object PostRequestHandlerExecuteId = new Object();\r
52                 static object ErrorId = new Object();\r
53 \r
54                 // List of events\r
55                 private EventHandlerList _Events;\r
56 \r
57                 public event EventHandler AcquireRequestState {\r
58                         add                     { Events.AddHandler(AcquireRequestStateId, value); }\r
59                         remove  { Events.RemoveHandler(AcquireRequestStateId, value); }\r
60                 }\r
61 \r
62                 public event EventHandler AuthenticateRequest {\r
63                         add                     { Events.AddHandler(AuthenticateRequestId, value); }\r
64                         remove  { Events.RemoveHandler(AuthenticateRequestId, value); }\r
65                 }\r
66                 \r
67                 public event EventHandler AuthorizeRequest {\r
68                         add                     { Events.AddHandler(AuthorizeRequestId, value); }\r
69                         remove  { Events.RemoveHandler(AuthorizeRequestId, value); }\r
70                 }\r
71                 \r
72                 public event EventHandler BeginRequest {\r
73                         add                     { Events.AddHandler(BeginRequestId, value); }\r
74                         remove  { Events.RemoveHandler(BeginRequestId, value); }\r
75                 }\r
76 \r
77                 public event EventHandler Disposed {\r
78                         add                     { Events.AddHandler(DisposedId, value); }\r
79                         remove  { Events.RemoveHandler(DisposedId, value); }\r
80                 }\r
81 \r
82                 public event EventHandler EndRequest {\r
83                         add                     { Events.AddHandler(EndRequestId, value); }\r
84                         remove  { Events.RemoveHandler(EndRequestId, value); }\r
85                 }\r
86 \r
87                 public event EventHandler Error {\r
88                         add                     { Events.AddHandler(ErrorId, value); }\r
89                         remove  { Events.RemoveHandler(ErrorId, value); }\r
90                 }\r
91 \r
92                 public event EventHandler PostRequestHandlerExecute {\r
93                         add                     { Events.AddHandler(PostRequestHandlerExecuteId, value); }\r
94                         remove  { Events.RemoveHandler(PostRequestHandlerExecuteId, value); }\r
95                 }\r
96 \r
97                 public event EventHandler PreRequestHandlerExecute {\r
98                         add                     { Events.AddHandler(PreRequestHandlerExecuteId, value); }\r
99                         remove  { Events.RemoveHandler(PreRequestHandlerExecuteId, value); }\r
100                 }\r
101 \r
102                 public event EventHandler PreSendRequestContent {\r
103                         add                     { Events.AddHandler(PreSendRequestContentId, value); }\r
104                         remove  { Events.RemoveHandler(PreSendRequestContentId, value); }\r
105                 }\r
106 \r
107                 public event EventHandler ReleaseRequestState {\r
108                         add                     { Events.AddHandler(ReleaseRequestStateId, value); }\r
109                         remove  { Events.RemoveHandler(ReleaseRequestStateId, value); }\r
110                 }\r
111 \r
112                 public event EventHandler ResolveRequestCache {\r
113                         add                     { Events.AddHandler(ResolveRequestCacheId, value); }\r
114                         remove  { Events.RemoveHandler(ResolveRequestCacheId, value); }\r
115                 }\r
116       \r
117                 public event EventHandler UpdateRequestCache {\r
118                         add                     { Events.AddHandler(UpdateRequestCacheId, value); }\r
119                         remove  { Events.RemoveHandler(UpdateRequestCacheId, value); }\r
120                 }\r
121         \r
122                 public event EventHandler PreSendRequestHeaders\r
123                 {\r
124                         add {\r
125                                 Events.AddHandler (PreSendRequestHeadersId, value);\r
126                         }\r
127                         remove {\r
128                                 Events.RemoveHandler (PreSendRequestHeadersId, value);\r
129                         }\r
130                 }\r
131         \r
132                 public void AddOnAcquireRequestStateAsync(BeginEventHandler beg, EndEventHandler end) {\r
133                         if (null == _acquireRequestStateAsync)\r
134                                 _acquireRequestStateAsync = new AsyncEvents();\r
135 \r
136                         _acquireRequestStateAsync.Add(beg, end);\r
137                 }\r
138                 \r
139                 public void AddOnAuthenticateRequestAsync(BeginEventHandler beg, EndEventHandler end) {\r
140                         if (null == _authenticateRequestAsync)\r
141                                 _authenticateRequestAsync = new AsyncEvents();\r
142 \r
143                         _authenticateRequestAsync.Add(beg, end);\r
144                 }\r
145                 \r
146                 public void AddOnAuthorizeRequestAsync(BeginEventHandler beg, EndEventHandler end) {\r
147                         if (null == _authorizeRequestAsync)\r
148                                 _authorizeRequestAsync= new AsyncEvents();\r
149 \r
150                         _authorizeRequestAsync.Add(beg, end);\r
151                 }\r
152                 \r
153                 public void AddOnBeginRequestAsync(BeginEventHandler beg, EndEventHandler end) {\r
154                         if (null == _beginRequestAsync)\r
155                                 _beginRequestAsync = new AsyncEvents();\r
156 \r
157                         _beginRequestAsync.Add(beg, end);\r
158                 }\r
159                 \r
160                 public void AddOnEndRequestAsync(BeginEventHandler beg, EndEventHandler end) {\r
161                         if (null == _endRequestAsync)\r
162                                 _endRequestAsync = new AsyncEvents();\r
163 \r
164                         _endRequestAsync.Add(beg, end);\r
165                 }\r
166                 \r
167                 public void AddOnPostRequestHandlerExecuteAsync(BeginEventHandler beg, EndEventHandler end) {\r
168                         if (null == _postRequestHandlerExecuteAsync)\r
169                                 _postRequestHandlerExecuteAsync = new AsyncEvents();\r
170 \r
171                         _postRequestHandlerExecuteAsync.Add(beg, end);\r
172                 }\r
173                 \r
174                 public void AddOnPreRequestHandlerExecuteAsync(BeginEventHandler beg, EndEventHandler end) {\r
175                         if (null == _preRequestHandlerExecuteAsync)\r
176                                 _preRequestHandlerExecuteAsync = new AsyncEvents();\r
177 \r
178                         _preRequestHandlerExecuteAsync.Add(beg, end);\r
179                 }\r
180                 \r
181                 public void AddOnReleaseRequestStateAsync(BeginEventHandler beg, EndEventHandler end) {\r
182                         if (null == _releaseRequestStateAsync)\r
183                                 _releaseRequestStateAsync = new AsyncEvents();\r
184 \r
185                         _releaseRequestStateAsync.Add(beg, end);\r
186                 }\r
187                 \r
188                 public void AddOnResolveRequestCacheAsync(BeginEventHandler beg, EndEventHandler end) {\r
189                         if (null == _resolveRequestCacheAsync)\r
190                                 _resolveRequestCacheAsync = new AsyncEvents();\r
191 \r
192                         _resolveRequestCacheAsync.Add(beg, end);\r
193                 }\r
194                 \r
195                 public void AddOnUpdateRequestCacheAsync(BeginEventHandler beg, EndEventHandler end) {\r
196                         if (null == _updateRequestCacheAsync)\r
197                                 _updateRequestCacheAsync = new AsyncEvents();\r
198 \r
199                         _updateRequestCacheAsync.Add(beg, end);\r
200                 }\r
201 \r
202                 #endregion\r
203 \r
204                 #region State Machine \r
205 \r
206                 interface IStateHandler {\r
207                         void Execute();\r
208                         \r
209                         bool CompletedSynchronously {\r
210                                 get;\r
211                         }\r
212 \r
213                         bool PossibleToTimeout {\r
214                                 get;\r
215                         }\r
216                 }\r
217 \r
218 \r
219                 class EventState : IStateHandler {\r
220                         private HttpApplication _app;\r
221                         private EventHandler            _event;\r
222 \r
223                         public EventState(HttpApplication app, EventHandler evt) {\r
224                                 _app = app;\r
225                                 _event = evt;\r
226                         }\r
227 \r
228                         public void Execute() {\r
229                                 if (null != _event) {\r
230                                         _event(_app, EventArgs.Empty);  \r
231                                 }\r
232                         }\r
233                         \r
234                         public bool CompletedSynchronously {\r
235                                 get {\r
236                                         return true;\r
237                                 }\r
238                         }\r
239 \r
240                         public bool PossibleToTimeout {\r
241                                 get {\r
242                                         return true;\r
243                                 }\r
244                         }\r
245                 }\r
246 \r
247                 class AsyncEventState : IStateHandler {\r
248                         private HttpApplication         _app;\r
249                         private BeginEventHandler       _begin;\r
250                         private EndEventHandler         _end;\r
251                         private AsyncCallback                   _callback;\r
252                         private bool _async;\r
253 \r
254                         public AsyncEventState(HttpApplication app, BeginEventHandler begin, EndEventHandler end) {\r
255                                 _async = false;\r
256                                 _app = app;\r
257                                 _begin = begin;\r
258                                 _end = end;\r
259                                 _callback = new AsyncCallback(OnAsyncReady);\r
260                         }\r
261                         \r
262                         public void Execute() {\r
263                                 _async = true;\r
264                                 IAsyncResult ar = _begin(_app, EventArgs.Empty, _callback, null);\r
265                                 if (ar.CompletedSynchronously) {\r
266                                         _async = false;\r
267                                         _end(ar);\r
268                                 }\r
269                         }\r
270                         \r
271                         public bool CompletedSynchronously {\r
272                                 get {\r
273                                         return (!_async);\r
274                                 }\r
275                         }\r
276 \r
277                         public bool PossibleToTimeout {\r
278                                 get {\r
279                                         // We can't cancel a async event\r
280                                         return false;\r
281                                 }\r
282                         }\r
283 \r
284                         private void OnAsyncReady(IAsyncResult ar) {\r
285                                 if (ar.CompletedSynchronously) return;\r
286 \r
287                                 Exception error = null;\r
288 \r
289                                 try {\r
290                                         // Invoke end handler\r
291                                         _end(ar);\r
292                                 }\r
293                                 catch (System.Exception exc) {\r
294                                         // Flow this error to the next state (handle during state execution)\r
295                                         error = exc;\r
296                                 }\r
297 \r
298                                 _app._state.ExecuteNextAsync(error);\r
299                         }\r
300                 }\r
301 \r
302                 class AsyncEvents {\r
303                         private ArrayList _events;\r
304                         private class EventRecord {\r
305                                 public EventRecord(BeginEventHandler beg, EndEventHandler end) {\r
306                                         Begin = beg;\r
307                                         End = end;\r
308                                 }\r
309 \r
310                                 public BeginEventHandler        Begin;\r
311                                 public EndEventHandler          End;\r
312                         }\r
313 \r
314                         public AsyncEvents() {\r
315                                 _events = new ArrayList();\r
316                         }\r
317         \r
318                         public void Add(BeginEventHandler begin, EndEventHandler end) {\r
319                                 _events.Add(new EventRecord(begin, end));\r
320                         }\r
321 \r
322                         public void GetAsStates(HttpApplication app, ArrayList states) {\r
323                                 foreach (object obj in _events) {\r
324                                         states.Add(new AsyncEventState(app, ((EventRecord) obj).Begin, ((EventRecord) obj).End));\r
325                                 }\r
326                         }\r
327                 }\r
328 \r
329 \r
330                 class ExecuteHandlerState : IStateHandler {\r
331                         private HttpApplication                 _app;\r
332                         private AsyncCallback                           _callback;\r
333                         private IHttpAsyncHandler               _handler;\r
334                         private bool _async;\r
335 \r
336                         public ExecuteHandlerState(HttpApplication app) {\r
337                                 _app = app;\r
338                                 _callback = new AsyncCallback(OnAsyncReady);\r
339                         }\r
340 \r
341                         private void OnAsyncReady(IAsyncResult ar) {\r
342                                 if (ar.CompletedSynchronously) return;\r
343 \r
344                                 Exception error = null;\r
345 \r
346                                 try {\r
347                                         // Invoke end handler\r
348                                         _handler.EndProcessRequest(ar);\r
349                                 }\r
350                                 catch (System.Exception exc) {\r
351                                         // Flow this error to the next state (handle during state execution)\r
352                                         error = exc;\r
353                                 }\r
354 \r
355                                 _handler = null;\r
356                                 _app._state.ExecuteNextAsync(error);\r
357                         }\r
358 \r
359                         public void Execute() {\r
360                                 IHttpHandler handler = _app.Context.Handler;\r
361                                 if (null != handler) {\r
362                                         // Check if we can execute async\r
363                                         if (handler is IHttpAsyncHandler) {\r
364                                                 _async = true;\r
365                                                 _handler = (IHttpAsyncHandler) handler;\r
366                                                 \r
367                                                 IAsyncResult ar = _handler.BeginProcessRequest(_app.Context, _callback, null);\r
368                                                 if (ar.CompletedSynchronously) {\r
369                                                         _async = false;\r
370                                                         _handler = null;\r
371                                                         ((IHttpAsyncHandler) handler).EndProcessRequest(ar);\r
372                                                 }\r
373                                         } else {\r
374                                                 _async = false;\r
375 \r
376                                                 // Sync handler\r
377                                                 handler.ProcessRequest( _app.Context);\r
378                                         }\r
379                                 }\r
380                         }\r
381                         \r
382                         public bool CompletedSynchronously {\r
383                                 get {\r
384                                         return (!_async);\r
385                                 }\r
386                         }\r
387 \r
388                         public bool PossibleToTimeout {\r
389                                 get {\r
390                                         if (_app.Context.Handler is IHttpAsyncHandler)\r
391                                                 return false;\r
392                                         //else\r
393 \r
394                                         return true;\r
395                                 }\r
396                         }\r
397                 }\r
398 \r
399                 class CreateHandlerState : IStateHandler {\r
400                         private HttpApplication _app;\r
401 \r
402                         public CreateHandlerState(HttpApplication app) {\r
403                                 _app = app;\r
404                         }\r
405 \r
406                         public void Execute() {\r
407                                 _app.Context.Handler = _app.CreateHttpHandler ( _app.Context,\r
408                                                                                 _app.Request.RequestType,\r
409                                                                                 _app.Request.FilePath,\r
410                                                                                 _app.Request.PhysicalPath);\r
411                         }\r
412                         \r
413                         public bool CompletedSynchronously {\r
414                                 get {\r
415                                         return true;\r
416                                 }\r
417                         }\r
418 \r
419                         public bool PossibleToTimeout {\r
420                                 get {\r
421                                         return false;\r
422                                 }\r
423                         }\r
424                 }\r
425 \r
426                 class FilterHandlerState : IStateHandler  {\r
427                         private HttpApplication _app;\r
428 \r
429                         public FilterHandlerState(HttpApplication app) {\r
430                                 _app = app;\r
431                         }\r
432 \r
433                         public void Execute() {\r
434                                 _app.Context.Response.DoFilter();\r
435                         }\r
436                         \r
437                         public bool CompletedSynchronously {\r
438                                 get {\r
439                                         return true;\r
440                                 }\r
441                         }\r
442 \r
443                         public bool PossibleToTimeout {\r
444                                 get {\r
445                                         return true;\r
446                                 }\r
447                         }\r
448                 }\r
449 \r
450                 class StateMachine {\r
451                         private HttpApplication _app;\r
452                         private WaitCallback _asynchandler;\r
453 \r
454                         private IStateHandler [] _handlers;\r
455                         private int     _currentStateIdx;\r
456                         private int _endStateIdx;\r
457                         private int _countSteps;\r
458                         private int _countSyncSteps;\r
459 \r
460                         // Helper to create the states for a normal event\r
461                         private void GetAsStates(object Event, ArrayList states) {\r
462                                 // Get list of clients for the sync events\r
463                                 Delegate evnt = _app.Events[Event];\r
464                                 if (null != evnt) {\r
465                                         System.Delegate [] clients = evnt.GetInvocationList();\r
466                                         \r
467                                         foreach (Delegate client in clients) {\r
468                                                 states.Add(new EventState(_app, (EventHandler) client));\r
469                                         }\r
470                                 }\r
471                         }\r
472 \r
473                         internal StateMachine(HttpApplication app) {\r
474                                 _app = app;\r
475                         }\r
476 \r
477                         internal void Init() {\r
478                                 _asynchandler = new WaitCallback(OnAsyncCallback);\r
479 \r
480                                 // Create a arraylist of states to execute\r
481                                 ArrayList states = new ArrayList();\r
482 \r
483                                 // BeginRequest\r
484                                 if (null != _app._beginRequestAsync)\r
485                                         _app._beginRequestAsync.GetAsStates(_app, states);\r
486                                 GetAsStates(HttpApplication.BeginRequestId, states);\r
487 \r
488                                 // AuthenticateRequest\r
489                                 if (null != _app._authenticateRequestAsync)\r
490                                         _app._authenticateRequestAsync.GetAsStates(_app, states);\r
491                                 GetAsStates(HttpApplication.AuthenticateRequestId, states);\r
492 \r
493                                 // AuthorizeRequest\r
494                                 if (null != _app._authorizeRequestAsync)\r
495                                         _app._authorizeRequestAsync.GetAsStates(_app, states);\r
496                                 GetAsStates(HttpApplication.AuthorizeRequestId, states);\r
497 \r
498                                 // ResolveRequestCache\r
499                                 if (null != _app._resolveRequestCacheAsync)\r
500                                         _app._resolveRequestCacheAsync.GetAsStates(_app, states);\r
501                                 GetAsStates(HttpApplication.ResolveRequestCacheId, states);\r
502 \r
503                                 // [A handler (a page corresponding to the request URL) is created at this point.]\r
504                                 states.Add(new CreateHandlerState(_app));\r
505 \r
506                                 // AcquireRequestState\r
507                                 if (null != _app._acquireRequestStateAsync)\r
508                                         _app._acquireRequestStateAsync.GetAsStates(_app, states);\r
509                                 GetAsStates(HttpApplication.AcquireRequestStateId, states);\r
510 \r
511                                 // PreRequestHandlerExecute\r
512                                 if (null != _app._preRequestHandlerExecuteAsync)\r
513                                         _app._preRequestHandlerExecuteAsync.GetAsStates(_app, states);\r
514                                 GetAsStates(HttpApplication.PreRequestHandlerExecuteId, states);\r
515 \r
516                                 // [The handler is executed.]\r
517                                 states.Add(new ExecuteHandlerState(_app));\r
518 \r
519                                 // PostRequestHandlerExecute\r
520                                 if (null != _app._postRequestHandlerExecuteAsync)\r
521                                         _app._postRequestHandlerExecuteAsync.GetAsStates(_app, states);\r
522                                 GetAsStates(HttpApplication.PostRequestHandlerExecuteId, states);\r
523 \r
524                                 // ReleaseRequestState\r
525                                 if (null != _app._releaseRequestStateAsync)\r
526                                         _app._releaseRequestStateAsync.GetAsStates(_app, states);\r
527                                 GetAsStates(HttpApplication.ReleaseRequestStateId, states);\r
528 \r
529                                 // [Response filters, if any, filter the output.]\r
530                                 states.Add(new FilterHandlerState(_app));\r
531 \r
532                                 // UpdateRequestCache\r
533                                 if (null != _app._updateRequestCacheAsync)\r
534                                         _app._updateRequestCacheAsync.GetAsStates(_app, states);\r
535                                 GetAsStates(HttpApplication.UpdateRequestCacheId, states);\r
536 \r
537                                 // EndRequest\r
538                                 if (null != _app._updateRequestCacheAsync)\r
539                                         _app._updateRequestCacheAsync.GetAsStates(_app, states);\r
540                                 GetAsStates(HttpApplication.EndRequestId, states);\r
541 \r
542                                 // Make list ready to execute\r
543                                 _handlers = new IStateHandler[states.Count];\r
544                                 states.CopyTo(_handlers);\r
545                         }\r
546 \r
547 \r
548                         internal void Reset() {\r
549                                 _countSyncSteps = 0;\r
550                                 _countSteps = 0;\r
551                                 _currentStateIdx = -1;\r
552                                 _endStateIdx = _handlers.Length - 1;\r
553                         }\r
554 \r
555                         internal void Start() {\r
556                                 Reset();\r
557                                 ExecuteNextAsync(null);\r
558                         }\r
559 \r
560                         internal void ExecuteNextAsync(Exception lasterror) {\r
561                         //FIXME: something is wrong with this: the socket is closed before compilation finishes.\r
562                         //      if (!Thread.CurrentThread.IsThreadPoolThread) {\r
563                         //              ThreadPool.QueueUserWorkItem(_asynchandler, lasterror);\r
564                         //      } else {\r
565                                         ExecuteNext(lasterror);\r
566                         //      }\r
567                         }\r
568 \r
569                         private void ExecuteNext(Exception lasterror) {\r
570                                 bool ready_sync = false;\r
571                                 IStateHandler handler;\r
572 \r
573                                 lock (_app) {\r
574                                         _app.OnStateExecuteEnter();\r
575                                         try {\r
576                                                 do {\r
577                                                         if (null != lasterror)\r
578                                                                 _app.HandleError(lasterror);\r
579 \r
580                                                         // Check if request flow is to be stopped\r
581                                                         if (_app._CompleteRequest)\r
582                                                                 _currentStateIdx = _endStateIdx;\r
583 \r
584                                                         // Get next state handler\r
585                                                         if (_currentStateIdx < _endStateIdx) {\r
586                                                                 _currentStateIdx++;\r
587                                                                 handler = _handlers[_currentStateIdx];\r
588 \r
589                                                                 _countSteps++;\r
590                                                                 lasterror = ExecuteState(handler, ref ready_sync);\r
591                                                                 if (ready_sync) \r
592                                                                         _countSyncSteps++;\r
593                                                         }\r
594                                                 } while (ready_sync && _currentStateIdx < _endStateIdx);\r
595                                         }\r
596                                         finally {\r
597                                                 _app.OnStateExecuteLeave();\r
598                                         }\r
599                                 }\r
600 \r
601                                 // Finish the request off..\r
602                                 if (_currentStateIdx == _endStateIdx) {\r
603                                         _app._asyncWebResult.Complete((_countSyncSteps == _countSteps),  null, null);\r
604                                         _app.Context.Handler = null;\r
605                                         _app.Context.ApplicationInstance = null;\r
606                                         _app.RecycleHandlers();\r
607                                         _app._asyncWebResult = null;\r
608 \r
609                                         HttpApplicationFactory.RecycleInstance(_app);\r
610                                 }\r
611                         }\r
612 \r
613                         private void OnAsyncCallback(object obj) {\r
614                                 ExecuteNext((Exception) obj);\r
615                         }\r
616 \r
617                         [MonoTODO()]\r
618                         private Exception ExecuteState(IStateHandler state, ref bool readysync) {\r
619                                 Exception lasterror = null;\r
620                                 try {\r
621                                         try {\r
622 \r
623                                                 if (state.PossibleToTimeout) {\r
624                                                         // TODO: Start timeout possible\r
625                                                         try {\r
626                                                                 state.Execute();        \r
627                                                         } \r
628                                                         finally {\r
629                                                                 // TODO: end timeout possible\r
630                                                         }\r
631 \r
632                                                         // Check if we have a timeout and wait for the exception.\r
633                                                 } else {\r
634                                                         state.Execute();\r
635                                                 }\r
636 \r
637                                                 if (state.CompletedSynchronously)\r
638                                                         readysync = true;\r
639                                                 else \r
640                                                         readysync = false;\r
641 \r
642                                         } \r
643                                         catch (System.Exception obj) {\r
644                                                 lasterror = obj;\r
645                                         }\r
646                                 }\r
647                                 catch (System.Threading.ThreadAbortException obj) {\r
648                                         obj = obj;\r
649                                         // TODO!\r
650                                         // handle request timeout and return timeout httpexception\r
651                                 }\r
652 \r
653                                 return lasterror;\r
654                         }\r
655                 }\r
656 \r
657                 #endregion\r
658 \r
659                 #region Fields\r
660 \r
661                 private StateMachine _state;\r
662 \r
663                 private bool _CompleteRequest;\r
664                 private HttpContext _Context;\r
665                 private Exception _lastError;\r
666 \r
667                 private HttpContext _savedContext;\r
668                 private IPrincipal _savedUser;\r
669                 private HttpAsyncResult _asyncWebResult;\r
670          \r
671                 private ISite _Site;\r
672                 private HttpModuleCollection _ModuleCollection;\r
673                 private HttpSessionState _Session;\r
674                 private HttpApplicationState _appState;\r
675 \r
676                 private bool _InPreRequestResponseMode;\r
677                 #endregion\r
678 \r
679                 #region Constructor\r
680       public HttpApplication() {\r
681       }\r
682                 #endregion\r
683 \r
684                 #region Methods\r
685                 private IHttpHandler CreateHttpHandler (HttpContext context, string type, string file, string path)\r
686                 {\r
687                         HandlerFactoryConfiguration handler = HttpContext.GetAppConfig ("system.web/httpHandlers")\r
688                                                                 as HandlerFactoryConfiguration;\r
689                         if (handler == null)\r
690                                 throw new HttpException ("Cannot get system.web/httpHandlers handler.");\r
691 \r
692                         return (IHttpHandler) handler.FindHandler (type, path).Create ();\r
693                 }\r
694 \r
695                 [MonoTODO()]\r
696                 internal void RecycleHandlers() {\r
697                         // TODO: Recycle the created handlers (via factory?)\r
698                 }\r
699 \r
700                 internal void InitModules() {\r
701                         ModulesConfiguration modules;\r
702 \r
703                         modules = (ModulesConfiguration) HttpContext.GetAppConfig("system.web/httpmodules");\r
704                         if (null == modules)\r
705                                 throw new HttpException(HttpRuntime.FormatResourceString("missing_modules_config"));\r
706 \r
707                         _ModuleCollection = modules.CreateCollection();\r
708                         if (null != _ModuleCollection) {\r
709                                 int pos, count;\r
710 \r
711                                 count = _ModuleCollection.Count;\r
712                                 for (pos = 0; pos != count; pos++) {\r
713                                         ((IHttpModule) _ModuleCollection.Get(pos)).Init(this);\r
714                                 }\r
715                         }\r
716                 }\r
717 \r
718                 internal void InitCulture() {\r
719                         // TODO: Read culture info from globalization from config\r
720                 }\r
721 \r
722                 internal void OnStateExecuteEnter() {\r
723                         // TODO: Set correct culture for the thread\r
724                         // TODO: Register in timeout manager\r
725 \r
726                         _savedContext = HttpContext.Context;\r
727                         HttpContext.Context = _Context;\r
728 \r
729                         _savedUser = System.Threading.Thread.CurrentPrincipal;\r
730                         System.Threading.Thread.CurrentPrincipal = Context.User;        \r
731                 }\r
732 \r
733                 internal void OnStateExecuteLeave() {\r
734                         // TODO: Restore culture for the thread\r
735                         // TODO: Remove from timeout manager\r
736 \r
737                         HttpContext.Context = _savedContext;\r
738                         if (null != _savedUser)  {\r
739                                 System.Threading.Thread.CurrentPrincipal = _savedUser;\r
740                                 _savedUser = null;\r
741                         }\r
742                 }\r
743 \r
744                 internal void ClearError() {\r
745                         _lastError = null;\r
746                 }\r
747 \r
748                 internal void HandleError(Exception obj) {\r
749                         EventHandler handler;                   \r
750                         bool fire = true;\r
751 \r
752                         if (null != _Context) {\r
753                                 if (null != _Context.Error) \r
754                                         fire = false;\r
755 \r
756                                 _Context.AddError(obj);\r
757                         } else {\r
758                                 if (null != _lastError)\r
759                                         fire = false;\r
760                         }\r
761 \r
762                         if (fire) {\r
763                                 // Fire OnError event here\r
764                                 handler = (EventHandler) Events[HttpApplication.ErrorId];\r
765                                 if (null != handler) {\r
766                                         try {\r
767                                                 handler(this, EventArgs.Empty);\r
768                                         }\r
769                                         catch (Exception excp) {\r
770                                                 if (null != _Context)\r
771                                                         _Context.AddError(excp);\r
772                                         }\r
773                                 }\r
774                         }\r
775                 }\r
776 \r
777                 [MonoTODO]\r
778                 internal void Startup(HttpContext context, HttpApplicationState state) {\r
779                         // TODO: Need to attach methods in global.asax to correct events\r
780                         _Context = context;\r
781 \r
782                         _appState = state;\r
783                         _state = new StateMachine(this);\r
784 \r
785                         // Initialize all IHttpModule(s)\r
786                         InitModules();\r
787                         \r
788                         // Initialize custom application\r
789                         _InPreRequestResponseMode = true;\r
790                         try {\r
791                                 Init();\r
792                         }\r
793                         catch (Exception obj) {\r
794                                 HandleError(obj);\r
795                         }\r
796 \r
797                         _InPreRequestResponseMode = false;\r
798 \r
799                         _state.Init();\r
800                 }\r
801 \r
802                 internal void Cleanup() {\r
803                         try {\r
804                                 Dispose();\r
805                         }\r
806                         catch (Exception obj) {\r
807                                 HandleError(obj);\r
808                         }\r
809 \r
810                         if (null != _ModuleCollection) {\r
811                                 int pos;\r
812                                 int count = _ModuleCollection.Count;\r
813 \r
814                                 for (pos = 0; pos != count; pos++) {\r
815                                         ((IHttpModule) _ModuleCollection.Get(pos)).Dispose();\r
816                                 }\r
817 \r
818                                 _ModuleCollection = null;\r
819                         }\r
820 \r
821                         _state = null;\r
822                 }\r
823 \r
824                 public void CompleteRequest() {\r
825                         _CompleteRequest = true;\r
826                 }\r
827 \r
828                 public virtual void Dispose() {\r
829                         _Site = null;\r
830                         EventHandler disposed = (EventHandler) Events[HttpApplication.DisposedId];\r
831                         if (null != disposed) \r
832                                 disposed(this, EventArgs.Empty);\r
833                 }\r
834 \r
835                 public virtual void Init() {\r
836                 }\r
837                 \r
838                 public virtual string GetVaryByCustomString(HttpContext context, string custom) {\r
839          if (custom.ToLower() == "browser") {\r
840             return context.Request.Browser.Type;\r
841          }\r
842 \r
843          return null;\r
844       }\r
845 \r
846       IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) {\r
847                         _Context = context;\r
848                         Context.ApplicationInstance = this;\r
849                         _CompleteRequest = false;\r
850 \r
851                         _asyncWebResult = new HttpAsyncResult(cb, extraData);\r
852 \r
853                         _state.Start();\r
854 \r
855                         return _asyncWebResult;\r
856       }\r
857 \r
858                 void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) {\r
859          HttpAsyncResult ar = (HttpAsyncResult) result;\r
860 \r
861                         if (null != ar.Error) \r
862                                 throw ar.Error;\r
863       }\r
864 \r
865       void IHttpHandler.ProcessRequest(HttpContext context) {\r
866          throw new NotSupportedException(HttpRuntime.FormatResourceString("sync_not_supported"));\r
867       }\r
868 \r
869       bool IHttpHandler.IsReusable {\r
870          get {\r
871                                 return true;\r
872          }\r
873       }\r
874                 #endregion              \r
875 \r
876                 #region Properties\r
877 \r
878                 [Browsable (false)]\r
879                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
880                 public HttpApplicationState Application {\r
881                         get { \r
882                                 return HttpApplicationFactory.ApplicationState;\r
883                         }\r
884                 }\r
885 \r
886                 [Browsable (false)]\r
887                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
888                 public HttpContext Context {\r
889                         get {\r
890                                 return _Context;\r
891                         }\r
892                 }\r
893 \r
894                 protected EventHandlerList Events {\r
895                         get {\r
896                                 if (null == _Events) {\r
897                                         _Events = new EventHandlerList();\r
898                                 }\r
899 \r
900                                 return _Events;\r
901                         }\r
902                 }\r
903                 \r
904                 [Browsable (false)]\r
905                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
906                 public HttpModuleCollection Modules {\r
907                         get {\r
908                                 if (null == _ModuleCollection) {\r
909                                         _ModuleCollection = new HttpModuleCollection();\r
910                                 }\r
911 \r
912                                 return _ModuleCollection;\r
913                         }\r
914                 }\r
915 \r
916                 [Browsable (false)]\r
917                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
918                 public HttpRequest Request {\r
919                         get {\r
920                                 if (null != _Context && (!_InPreRequestResponseMode)) {\r
921                                         return _Context.Request;\r
922                                 }\r
923 \r
924                                 throw new HttpException("Can't get request object");\r
925                         }\r
926                 }\r
927 \r
928                 [Browsable (false)]\r
929                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
930                 public HttpResponse Response {\r
931                         get {\r
932                                 if (null != _Context && (!_InPreRequestResponseMode)) {\r
933                                         return _Context.Response;\r
934                                 }\r
935 \r
936                                 throw new HttpException("Can't get response object");\r
937                         }\r
938                 }\r
939 \r
940                 [Browsable (false)]\r
941                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
942                 public HttpServerUtility Server {\r
943                         get {\r
944                                 if (null != _Context) {\r
945                                         return _Context.Server;\r
946                                 }\r
947 \r
948                                 return new HttpServerUtility(this);\r
949                         }\r
950                 }\r
951 \r
952                 [Browsable (false)]\r
953                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
954                 public HttpSessionState Session {\r
955                         get {\r
956                                 if (null != _Session) {\r
957                                         return _Session;\r
958                                 }\r
959 \r
960                                 if (null != _Context && null != _Context.Session) {\r
961                                         return _Context.Session;\r
962                                 }\r
963 \r
964                                 throw new HttpException("Failed to get session object");\r
965                         }\r
966                 }\r
967 \r
968                 [Browsable (false)]\r
969                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
970                 public IPrincipal User {\r
971                         get { \r
972                                 return _Context.User; \r
973                         }\r
974                 }\r
975                 \r
976                 [Browsable (false)]\r
977                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]\r
978                 public ISite Site {\r
979          get {\r
980             return _Site;\r
981          }\r
982 \r
983          set {\r
984             _Site = value;\r
985          }\r
986       }\r
987                 #endregion Properties\r
988         }\r
989 }\r