1 // 2 // System.Web.HttpApplication.cs 3 // 4 // Author: 5 // Miguel de Icaza (miguel@novell.com) 6 // Gonzalo Paniagua (gonzalo@ximian.com) 7 // Matthias Bogad (bogad@cs.tum.edu) 8 // 9 // 10 // Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com) 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining 13 // a copy of this software and associated documentation files (the 14 // "Software"), to deal in the Software without restriction, including 15 // without limitation the rights to use, copy, modify, merge, publish, 16 // distribute, sublicense, and/or sell copies of the Software, and to 17 // permit persons to whom the Software is furnished to do so, subject to 18 // the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be 21 // included in all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 // 31 // The Application Processing Pipeline. 32 // 33 // The Http application pipeline implemented in this file is a 34 // beautiful thing. The application pipeline invokes a number of 35 // hooks at various stages of the processing of a request. These 36 // hooks can be either synchronous or can be asynchronous. 37 // 38 // The pipeline must ensure that every step is completed before 39 // moving to the next step. A trivial thing for synchronous 40 // hooks, but asynchronous hooks introduce an extra layer of 41 // complexity: when the hook is invoked, the thread must 42 // relinquish its control so that the thread can be reused in 43 // another operation while waiting. 44 // 45 // To implement this functionality we used C# iterators manually; 46 // we drive the pipeline by executing the various hooks from the 47 // `RunHooks' routine which is an enumerator that will yield the 48 // value `false' if execution must proceed or `true' if execution 49 // must be stopped. 50 // 51 // By yielding values we can suspend execution of RunHooks. 52 // 53 // Special attention must be given to `in_begin' and `must_yield' 54 // variables. These are used in the case that an async hook 55 // completes synchronously as its important to not yield in that 56 // case or we would hang. 57 // 58 // Many of Mono modules used to be declared async, but they would 59 // actually be completely synchronous, this might resurface in the 60 // future with other modules. 61 // 62 // TODO: 63 // Events Disposed 64 // 65 66 using System; 67 using System.IO; 68 using System.Collections; 69 using System.Collections.Generic; 70 using System.ComponentModel; 71 using System.Configuration; 72 using System.Diagnostics; 73 using System.Globalization; 74 using System.Reflection; 75 using System.Security.Permissions; 76 using System.Security.Principal; 77 using System.Threading; 78 using System.Web.Caching; 79 using System.Web.Compilation; 80 using System.Web.Configuration; 81 using System.Web.Management; 82 using System.Web.SessionState; 83 using System.Web.UI; 84 using System.Web.Util; 85 86 87 namespace System.Web 88 { 89 // CAS 90 [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] 91 [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)] 92 // attributes 93 [ToolboxItem(false)] 94 public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable 95 { 96 static readonly object disposedEvent = new object (); 97 static readonly object errorEvent = new object (); 98 99 // we do this static rather than per HttpApplication because 100 // mono's perfcounters use the counter instance parameter for 101 // the process to access shared memory. 102 internal static PerformanceCounter requests_total_counter = new PerformanceCounter ("ASP.NET", "Requests Total"); 103 104 internal static readonly string [] BinDirs = {"Bin", "bin"}; 105 object this_lock = new object(); 106 107 HttpContext context; 108 HttpSessionState session; 109 ISite isite; 110 111 // The source, and the exposed API (cache). 112 volatile HttpModuleCollection modcoll; 113 114 string assemblyLocation; 115 116 // 117 // The factory for the handler currently running. 118 // 119 IHttpHandlerFactory factory; 120 121 // 122 // Whether the thread culture is to be auto-set. 123 // Used only in the 2.0 profile, always false for 1.x 124 // 125 bool autoCulture; 126 bool autoUICulture; 127 128 // 129 // Whether the pipeline should be stopped 130 // 131 bool stop_processing; 132 133 // 134 // See https://bugzilla.novell.com/show_bug.cgi?id=381971 135 // 136 bool in_application_start; 137 138 // 139 // The Pipeline 140 // 141 IEnumerator pipeline; 142 143 // To flag when we are done processing a request from BeginProcessRequest. 144 ManualResetEvent done; 145 146 // The current IAsyncResult for the running async request handler in the pipeline 147 AsyncRequestState begin_iar; 148 149 // Tracks the current AsyncInvocation being dispatched 150 AsyncInvoker current_ai; 151 152 EventHandlerList events; 153 EventHandlerList nonApplicationEvents = new EventHandlerList (); 154 155 // Culture and IPrincipal 156 CultureInfo app_culture; 157 CultureInfo appui_culture; 158 CultureInfo prev_app_culture; 159 CultureInfo prev_appui_culture; 160 IPrincipal prev_user; 161 162 static string binDirectory; 163 164 static volatile Exception initialization_exception; 165 bool removeConfigurationFromCache; 166 bool fullInitComplete = false; 167 168 static DynamicModuleManager dynamicModuleManeger = new DynamicModuleManager (); 169 170 // 171 // These are used to detect the case where the EndXXX method is invoked 172 // from within the BeginXXXX delegate, so we detect whether we kick the 173 // pipeline from here, or from the the RunHook routine 174 // 175 bool must_yield; 176 bool in_begin; 177 178 public virtual event EventHandler Disposed { 179 add { nonApplicationEvents.AddHandler (disposedEvent, value); } 180 remove { nonApplicationEvents.RemoveHandler (disposedEvent, value); } 181 } 182 183 public virtual event EventHandler Error { 184 add { nonApplicationEvents.AddHandler (errorEvent, value); } 185 remove { nonApplicationEvents.RemoveHandler (errorEvent, value); } 186 } 187 HttpApplication()188 public HttpApplication () 189 { 190 done = new ManualResetEvent (false); 191 } 192 InitOnce(bool full_init)193 internal void InitOnce (bool full_init) 194 { 195 if (initialization_exception != null) 196 return; 197 198 if (modcoll != null) 199 return; 200 201 lock (this_lock) { 202 if (initialization_exception != null) 203 return; 204 205 if (modcoll != null) 206 return; 207 208 bool mustNullContext = context == null; 209 try { 210 HttpModulesSection modules; 211 modules = (HttpModulesSection) WebConfigurationManager.GetWebApplicationSection ("system.web/httpModules"); 212 HttpContext saved = HttpContext.Current; 213 HttpContext.Current = new HttpContext (new System.Web.Hosting.SimpleWorkerRequest (String.Empty, String.Empty, new StringWriter())); 214 if (context == null) 215 context = HttpContext.Current; 216 HttpModuleCollection coll = modules.LoadModules (this); 217 218 HttpModuleCollection dynMods = CreateDynamicModules (); 219 220 for (int i = 0; i < dynMods.Count; i++) { 221 coll.AddModule (dynMods.GetKey (i), dynMods.Get (i)); 222 } 223 224 Interlocked.CompareExchange (ref modcoll, coll, null); 225 HttpContext.Current = saved; 226 227 if (full_init) { 228 HttpApplicationFactory.AttachEvents (this); 229 Init (); 230 fullInitComplete = true; 231 } 232 } catch (Exception e) { 233 initialization_exception = e; 234 Console.Error.WriteLine("Exception while initOnce: "+e.ToString()); 235 // Once initialization_exception != null, we always respond with this exception 236 // You have to restart the HttpApplication to "unlock" it 237 Console.Error.WriteLine("Please restart your app to unlock it"); 238 } finally { 239 if (mustNullContext) 240 context = null; 241 } 242 } 243 } 244 245 internal bool InApplicationStart { 246 get { return in_application_start; } 247 set { in_application_start = value; } 248 } 249 250 internal string AssemblyLocation { 251 get { 252 if (assemblyLocation == null) 253 assemblyLocation = GetType ().Assembly.Location; 254 return assemblyLocation; 255 } 256 } 257 258 internal static Exception InitializationException { 259 get { return initialization_exception; } 260 } 261 262 [Browsable (false)] 263 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 264 public HttpApplicationState Application { 265 get { 266 return HttpApplicationFactory.ApplicationState; 267 } 268 } 269 270 [Browsable (false)] 271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 272 public HttpContext Context { 273 get { 274 return context; 275 } 276 } 277 278 protected EventHandlerList Events { 279 get { 280 if (events == null) 281 events = new EventHandlerList (); 282 283 return events; 284 } 285 } 286 287 [Browsable (false)] 288 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 289 public HttpModuleCollection Modules { 290 [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)] 291 get { 292 if (modcoll == null) 293 modcoll = new HttpModuleCollection (); 294 295 return modcoll; 296 } 297 } 298 299 [Browsable (false)] 300 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 301 public HttpRequest Request { 302 get { 303 if (context == null) 304 throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort); 305 306 if (false == HttpApplicationFactory.ContextAvailable) 307 throw HttpException.NewWithCode (Locale.GetText ("Request is not available in this context."), WebEventCodes.RuntimeErrorRequestAbort); 308 309 return context.Request; 310 } 311 } 312 313 [Browsable (false)] 314 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 315 public HttpResponse Response { 316 get { 317 if (context == null) 318 throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort); 319 320 if (false == HttpApplicationFactory.ContextAvailable) 321 throw HttpException.NewWithCode (Locale.GetText ("Response is not available in this context."), WebEventCodes.RuntimeErrorRequestAbort); 322 323 return context.Response; 324 } 325 } 326 327 [Browsable (false)] 328 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 329 public HttpServerUtility Server { 330 get { 331 if (context != null) 332 return context.Server; 333 334 // 335 // This is so we can get the Server and call a few methods 336 // which are not context sensitive, see HttpServerUtilityTest 337 // 338 return new HttpServerUtility ((HttpContext) null); 339 } 340 } 341 342 [Browsable (false)] 343 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 344 public HttpSessionState Session { 345 get { 346 // Only used for Session_End 347 if (session != null) 348 return session; 349 350 if (context == null) 351 throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort); 352 353 HttpSessionState ret = context.Session; 354 if (ret == null) 355 throw HttpException.NewWithCode (Locale.GetText ("Session state is not available in the context."), WebEventCodes.RuntimeErrorRequestAbort); 356 357 return ret; 358 } 359 } 360 361 [Browsable (false)] 362 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 363 public ISite Site { 364 get { return isite; } 365 366 set { isite = value; } 367 } 368 369 [Browsable (false)] 370 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 371 public IPrincipal User { 372 get { 373 if (context == null) 374 throw new HttpException (Locale.GetText ("No context is available.")); 375 if (context.User == null) 376 throw new HttpException (Locale.GetText ("No currently authenticated user.")); 377 378 return context.User; 379 } 380 } 381 382 static object PreSendRequestHeadersEvent = new object (); 383 public event EventHandler PreSendRequestHeaders 384 { 385 add { AddEventHandler (PreSendRequestHeadersEvent, value); } 386 remove { RemoveEventHandler (PreSendRequestHeadersEvent, value); } 387 } 388 TriggerPreSendRequestHeaders()389 internal void TriggerPreSendRequestHeaders () 390 { 391 EventHandler handler = Events [PreSendRequestHeadersEvent] as EventHandler; 392 if (handler != null) 393 handler (this, EventArgs.Empty); 394 } 395 396 static object PreSendRequestContentEvent = new object (); 397 public event EventHandler PreSendRequestContent 398 { 399 add { AddEventHandler (PreSendRequestContentEvent, value); } 400 remove { RemoveEventHandler (PreSendRequestContentEvent, value); } 401 } 402 TriggerPreSendRequestContent()403 internal void TriggerPreSendRequestContent () 404 { 405 EventHandler handler = Events [PreSendRequestContentEvent] as EventHandler; 406 if (handler != null) 407 handler (this, EventArgs.Empty); 408 } 409 410 static object AcquireRequestStateEvent = new object (); 411 public event EventHandler AcquireRequestState 412 { 413 add { AddEventHandler (AcquireRequestStateEvent, value); } 414 remove { RemoveEventHandler (AcquireRequestStateEvent, value); } 415 } 416 AddOnAcquireRequestStateAsync(BeginEventHandler bh, EndEventHandler eh)417 public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh) 418 { 419 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 420 AcquireRequestState += new EventHandler (invoker.Invoke); 421 } 422 423 static object AuthenticateRequestEvent = new object (); 424 public event EventHandler AuthenticateRequest 425 { 426 add { AddEventHandler (AuthenticateRequestEvent, value); } 427 remove { RemoveEventHandler (AuthenticateRequestEvent, value); } 428 } 429 AddOnAuthenticateRequestAsync(BeginEventHandler bh, EndEventHandler eh)430 public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh) 431 { 432 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 433 AuthenticateRequest += new EventHandler (invoker.Invoke); 434 } 435 436 static object AuthorizeRequestEvent = new object (); 437 public event EventHandler AuthorizeRequest 438 { 439 add { AddEventHandler (AuthorizeRequestEvent, value); } 440 remove { RemoveEventHandler (AuthorizeRequestEvent, value); } 441 } 442 AddOnAuthorizeRequestAsync(BeginEventHandler bh, EndEventHandler eh)443 public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh) 444 { 445 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 446 AuthorizeRequest += new EventHandler (invoker.Invoke); 447 } 448 449 static object BeginRequestEvent = new object (); 450 public event EventHandler BeginRequest 451 { 452 add { 453 // See https://bugzilla.novell.com/show_bug.cgi?id=381971 454 if (InApplicationStart) 455 return; 456 AddEventHandler (BeginRequestEvent, value); 457 } 458 remove { 459 if (InApplicationStart) 460 return; 461 RemoveEventHandler (BeginRequestEvent, value); 462 } 463 } 464 AddOnBeginRequestAsync(BeginEventHandler bh, EndEventHandler eh)465 public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh) 466 { 467 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 468 BeginRequest += new EventHandler (invoker.Invoke); 469 } 470 471 static object EndRequestEvent = new object (); 472 public event EventHandler EndRequest 473 { 474 add { 475 // See https://bugzilla.novell.com/show_bug.cgi?id=381971 476 if (InApplicationStart) 477 return; 478 AddEventHandler (EndRequestEvent, value); 479 } 480 remove { 481 if (InApplicationStart) 482 return; 483 RemoveEventHandler (EndRequestEvent, value); 484 } 485 } 486 AddOnEndRequestAsync(BeginEventHandler bh, EndEventHandler eh)487 public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh) 488 { 489 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 490 EndRequest += new EventHandler (invoker.Invoke); 491 } 492 493 static object PostRequestHandlerExecuteEvent = new object (); 494 public event EventHandler PostRequestHandlerExecute 495 { 496 add { AddEventHandler (PostRequestHandlerExecuteEvent, value); } 497 remove { RemoveEventHandler (PostRequestHandlerExecuteEvent, value); } 498 } 499 AddOnPostRequestHandlerExecuteAsync(BeginEventHandler bh, EndEventHandler eh)500 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh) 501 { 502 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 503 PostRequestHandlerExecute += new EventHandler (invoker.Invoke); 504 } 505 506 static object PreRequestHandlerExecuteEvent = new object (); 507 public event EventHandler PreRequestHandlerExecute 508 { 509 add { AddEventHandler (PreRequestHandlerExecuteEvent, value); } 510 remove { RemoveEventHandler (PreRequestHandlerExecuteEvent, value); } 511 } 512 AddOnPreRequestHandlerExecuteAsync(BeginEventHandler bh, EndEventHandler eh)513 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh) 514 { 515 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 516 PreRequestHandlerExecute += new EventHandler (invoker.Invoke); 517 } 518 519 static object ReleaseRequestStateEvent = new object (); 520 public event EventHandler ReleaseRequestState 521 { 522 add { AddEventHandler (ReleaseRequestStateEvent, value); } 523 remove { RemoveEventHandler (ReleaseRequestStateEvent, value); } 524 } 525 AddOnReleaseRequestStateAsync(BeginEventHandler bh, EndEventHandler eh)526 public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh) 527 { 528 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 529 ReleaseRequestState += new EventHandler (invoker.Invoke); 530 } 531 532 static object ResolveRequestCacheEvent = new object (); 533 public event EventHandler ResolveRequestCache 534 { 535 add { AddEventHandler (ResolveRequestCacheEvent, value); } 536 remove { RemoveEventHandler (ResolveRequestCacheEvent, value); } 537 } 538 AddOnResolveRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh)539 public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh) 540 { 541 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 542 ResolveRequestCache += new EventHandler (invoker.Invoke); 543 } 544 545 static object UpdateRequestCacheEvent = new object (); 546 public event EventHandler UpdateRequestCache 547 { 548 add { AddEventHandler (UpdateRequestCacheEvent, value); } 549 remove { RemoveEventHandler (UpdateRequestCacheEvent, value); } 550 } 551 AddOnUpdateRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh)552 public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh) 553 { 554 AsyncInvoker invoker = new AsyncInvoker (bh, eh, this); 555 UpdateRequestCache += new EventHandler (invoker.Invoke); 556 } 557 558 static object PostAuthenticateRequestEvent = new object (); 559 public event EventHandler PostAuthenticateRequest 560 { 561 add { AddEventHandler (PostAuthenticateRequestEvent, value); } 562 remove { RemoveEventHandler (PostAuthenticateRequestEvent, value); } 563 } 564 AddOnPostAuthenticateRequestAsync(BeginEventHandler bh, EndEventHandler eh)565 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh) 566 { 567 AddOnPostAuthenticateRequestAsync (bh, eh, null); 568 } 569 AddOnPostAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)570 public void AddOnPostAuthenticateRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 571 { 572 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 573 PostAuthenticateRequest += new EventHandler (invoker.Invoke); 574 } 575 576 static object PostAuthorizeRequestEvent = new object (); 577 public event EventHandler PostAuthorizeRequest 578 { 579 add { AddEventHandler (PostAuthorizeRequestEvent, value); } 580 remove { RemoveEventHandler (PostAuthorizeRequestEvent, value); } 581 } 582 AddOnPostAuthorizeRequestAsync(BeginEventHandler bh, EndEventHandler eh)583 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh) 584 { 585 AddOnPostAuthorizeRequestAsync (bh, eh, null); 586 } 587 AddOnPostAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)588 public void AddOnPostAuthorizeRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 589 { 590 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 591 PostAuthorizeRequest += new EventHandler (invoker.Invoke); 592 } 593 594 static object PostResolveRequestCacheEvent = new object (); 595 public event EventHandler PostResolveRequestCache 596 { 597 add { AddEventHandler (PostResolveRequestCacheEvent, value); } 598 remove { RemoveEventHandler (PostResolveRequestCacheEvent, value); } 599 } 600 AddOnPostResolveRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh)601 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh) 602 { 603 AddOnPostResolveRequestCacheAsync (bh, eh, null); 604 } 605 AddOnPostResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)606 public void AddOnPostResolveRequestCacheAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 607 { 608 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 609 PostResolveRequestCache += new EventHandler (invoker.Invoke); 610 } 611 612 static object PostMapRequestHandlerEvent = new object (); 613 public event EventHandler PostMapRequestHandler 614 { 615 add { AddEventHandler (PostMapRequestHandlerEvent, value); } 616 remove { RemoveEventHandler (PostMapRequestHandlerEvent, value); } 617 } 618 AddOnPostMapRequestHandlerAsync(BeginEventHandler bh, EndEventHandler eh)619 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh) 620 { 621 AddOnPostMapRequestHandlerAsync (bh, eh, null); 622 } 623 AddOnPostMapRequestHandlerAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)624 public void AddOnPostMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 625 { 626 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 627 PostMapRequestHandler += new EventHandler (invoker.Invoke); 628 } 629 630 static object PostAcquireRequestStateEvent = new object (); 631 public event EventHandler PostAcquireRequestState 632 { 633 add { AddEventHandler (PostAcquireRequestStateEvent, value); } 634 remove { RemoveEventHandler (PostAcquireRequestStateEvent, value); } 635 } 636 AddOnPostAcquireRequestStateAsync(BeginEventHandler bh, EndEventHandler eh)637 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh) 638 { 639 AddOnPostAcquireRequestStateAsync (bh, eh, null); 640 } 641 AddOnPostAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)642 public void AddOnPostAcquireRequestStateAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 643 { 644 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 645 PostAcquireRequestState += new EventHandler (invoker.Invoke); 646 } 647 648 static object PostReleaseRequestStateEvent = new object (); 649 public event EventHandler PostReleaseRequestState 650 { 651 add { AddEventHandler (PostReleaseRequestStateEvent, value); } 652 remove { RemoveEventHandler (PostReleaseRequestStateEvent, value); } 653 } 654 AddOnPostReleaseRequestStateAsync(BeginEventHandler bh, EndEventHandler eh)655 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh) 656 { 657 AddOnPostReleaseRequestStateAsync (bh, eh, null); 658 } 659 AddOnPostReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)660 public void AddOnPostReleaseRequestStateAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 661 { 662 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 663 PostReleaseRequestState += new EventHandler (invoker.Invoke); 664 } 665 666 static object PostUpdateRequestCacheEvent = new object (); 667 public event EventHandler PostUpdateRequestCache 668 { 669 add { AddEventHandler (PostUpdateRequestCacheEvent, value); } 670 remove { RemoveEventHandler (PostUpdateRequestCacheEvent, value); } 671 } 672 AddOnPostUpdateRequestCacheAsync(BeginEventHandler bh, EndEventHandler eh)673 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh) 674 { 675 AddOnPostUpdateRequestCacheAsync (bh, eh, null); 676 } 677 AddOnPostUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)678 public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 679 { 680 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 681 PostUpdateRequestCache += new EventHandler (invoker.Invoke); 682 } 683 684 // 685 // The new overloads that take a data parameter 686 // AddOnAcquireRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)687 public void AddOnAcquireRequestStateAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 688 { 689 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 690 AcquireRequestState += new EventHandler (invoker.Invoke); 691 } 692 AddOnAuthenticateRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)693 public void AddOnAuthenticateRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 694 { 695 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 696 AuthenticateRequest += new EventHandler (invoker.Invoke); 697 } 698 AddOnAuthorizeRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)699 public void AddOnAuthorizeRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 700 { 701 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 702 AuthorizeRequest += new EventHandler (invoker.Invoke); 703 } 704 AddOnBeginRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)705 public void AddOnBeginRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 706 { 707 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 708 BeginRequest += new EventHandler (invoker.Invoke); 709 } 710 AddOnEndRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)711 public void AddOnEndRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 712 { 713 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 714 EndRequest += new EventHandler (invoker.Invoke); 715 } 716 AddOnPostRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)717 public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 718 { 719 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 720 PostRequestHandlerExecute += new EventHandler (invoker.Invoke); 721 } 722 AddOnPreRequestHandlerExecuteAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)723 public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 724 { 725 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 726 PreRequestHandlerExecute += new EventHandler (invoker.Invoke); 727 } 728 AddOnReleaseRequestStateAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)729 public void AddOnReleaseRequestStateAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 730 { 731 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 732 ReleaseRequestState += new EventHandler (invoker.Invoke); 733 } 734 AddOnResolveRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)735 public void AddOnResolveRequestCacheAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 736 { 737 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 738 ResolveRequestCache += new EventHandler (invoker.Invoke); 739 } 740 AddOnUpdateRequestCacheAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)741 public void AddOnUpdateRequestCacheAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 742 { 743 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 744 UpdateRequestCache += new EventHandler (invoker.Invoke); 745 } 746 747 // Added in 2.0 SP1 748 // They are for use with the IIS7 integrated mode, but have been added for 749 // compatibility 750 static object LogRequestEvent = new object (); 751 public event EventHandler LogRequest 752 { 753 add { AddEventHandler (LogRequestEvent, value); } 754 remove { RemoveEventHandler (LogRequestEvent, value); } 755 } 756 AddOnLogRequestAsync(BeginEventHandler bh, EndEventHandler eh)757 public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh) 758 { 759 AddOnLogRequestAsync (bh, eh, null); 760 } 761 AddOnLogRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)762 public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 763 { 764 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 765 LogRequest += new EventHandler (invoker.Invoke); 766 } 767 768 static object MapRequestHandlerEvent = new object (); 769 public event EventHandler MapRequestHandler 770 { 771 add { AddEventHandler (MapRequestHandlerEvent, value); } 772 remove { RemoveEventHandler (MapRequestHandlerEvent, value); } 773 } 774 AddOnMapRequestHandlerAsync(BeginEventHandler bh, EndEventHandler eh)775 public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh) 776 { 777 AddOnMapRequestHandlerAsync (bh, eh, null); 778 } 779 AddOnMapRequestHandlerAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)780 public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 781 { 782 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 783 MapRequestHandler += new EventHandler (invoker.Invoke); 784 } 785 786 static object PostLogRequestEvent = new object (); 787 public event EventHandler PostLogRequest 788 { 789 add { AddEventHandler (PostLogRequestEvent, value); } 790 remove { RemoveEventHandler (PostLogRequestEvent, value); } 791 } 792 AddOnPostLogRequestAsync(BeginEventHandler bh, EndEventHandler eh)793 public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh) 794 { 795 AddOnPostLogRequestAsync (bh, eh, null); 796 } 797 AddOnPostLogRequestAsync(BeginEventHandler beginHandler, EndEventHandler endHandler, object state)798 public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state) 799 { 800 AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, this, state); 801 PostLogRequest += new EventHandler (invoker.Invoke); 802 } 803 804 internal event EventHandler DefaultAuthentication; 805 AddEventHandler(object key, EventHandler handler)806 void AddEventHandler (object key, EventHandler handler) 807 { 808 if (fullInitComplete) 809 return; 810 811 Events.AddHandler (key, handler); 812 } 813 RemoveEventHandler(object key, EventHandler handler)814 void RemoveEventHandler (object key, EventHandler handler) 815 { 816 if (fullInitComplete) 817 return; 818 819 Events.RemoveHandler (key, handler); 820 } 821 822 // 823 // Bypass all the event on the Http pipeline and go directly to EndRequest 824 // CompleteRequest()825 public void CompleteRequest () 826 { 827 stop_processing = true; 828 } 829 830 internal bool RequestCompleted { 831 set { stop_processing = value; } 832 } 833 DisposeInternal()834 internal void DisposeInternal () 835 { 836 Dispose (); 837 HttpModuleCollection coll = new HttpModuleCollection (); 838 Interlocked.Exchange (ref modcoll, coll); 839 if (coll != null) { 840 for (int i = coll.Count - 1; i >= 0; i--) { 841 coll.Get (i).Dispose (); 842 } 843 coll = null; 844 } 845 846 EventHandler eh = nonApplicationEvents [disposedEvent] as EventHandler; 847 if (eh != null) 848 eh (this, EventArgs.Empty); 849 850 done.Close (); 851 done = null; 852 } 853 Dispose()854 public virtual void Dispose () 855 { 856 } 857 GetOutputCacheProviderName(HttpContext context)858 public virtual string GetOutputCacheProviderName (HttpContext context) 859 { 860 // LAMESPEC: doesn't throw ProviderException if context is null 861 return OutputCache.DefaultProviderName; 862 } 863 GetVaryByCustomString(HttpContext context, string custom)864 public virtual string GetVaryByCustomString (HttpContext context, string custom) 865 { 866 if (custom == null) // Sigh 867 throw new NullReferenceException (); 868 869 if (0 == String.Compare (custom, "browser", true, Helpers.InvariantCulture)) 870 return context.Request.Browser.Type; 871 872 return null; 873 } 874 ShouldHandleException(Exception e)875 bool ShouldHandleException (Exception e) 876 { 877 if (e is ParseException) 878 return false; 879 880 return true; 881 } 882 883 // 884 // If we catch an error, queue this error 885 // ProcessError(Exception e)886 internal void ProcessError (Exception e) 887 { 888 bool first = context.Error == null; 889 context.AddError (e); 890 if (first && ShouldHandleException (e)) { 891 EventHandler eh = nonApplicationEvents [errorEvent] as EventHandler; 892 if (eh != null){ 893 try { 894 eh (this, EventArgs.Empty); 895 if (stop_processing) 896 context.ClearError (); 897 } catch (ThreadAbortException taex){ 898 context.ClearError (); 899 if (FlagEnd.Value == taex.ExceptionState || HttpRuntime.DomainUnloading) 900 // This happens on Redirect(), End() and 901 // when unloading the AppDomain 902 Thread.ResetAbort (); 903 else 904 // This happens on Thread.Abort() 905 context.AddError (taex); 906 } catch (Exception ee){ 907 context.AddError (ee); 908 } 909 } 910 } 911 stop_processing = true; 912 913 // we want to remove configuration from the cache in case of 914 // invalid resource not exists to prevent DOS attack. 915 HttpException httpEx = e as HttpException; 916 if (httpEx != null && httpEx.GetHttpCode () == 404) { 917 removeConfigurationFromCache = true; 918 } 919 } 920 921 // 922 // Ticks the clock: next step on the pipeline. 923 // Tick()924 internal void Tick () 925 { 926 try { 927 if (pipeline.MoveNext ()){ 928 if ((bool)pipeline.Current) 929 PipelineDone (); 930 } 931 } catch (ThreadAbortException taex) { 932 object obj = taex.ExceptionState; 933 Thread.ResetAbort (); 934 if (obj is StepTimeout) 935 ProcessError (HttpException.NewWithCode ("The request timed out.", WebEventCodes.RequestTransactionAbort)); 936 else { 937 context.ClearError (); 938 if (FlagEnd.Value != obj && !HttpRuntime.DomainUnloading) 939 context.AddError (taex); 940 } 941 942 stop_processing = true; 943 PipelineDone (); 944 } catch (Exception e) { 945 ThreadAbortException inner = e.InnerException as ThreadAbortException; 946 if (inner != null && FlagEnd.Value == inner.ExceptionState && !HttpRuntime.DomainUnloading) { 947 context.ClearError (); 948 Thread.ResetAbort (); 949 } else { 950 ProcessError (e); 951 } 952 stop_processing = true; 953 PipelineDone (); 954 } 955 } 956 Resume()957 void Resume () 958 { 959 if (in_begin) 960 must_yield = false; 961 else 962 Tick (); 963 } 964 965 // 966 // Invoked when our async callback called from RunHooks completes, 967 // we restart the pipeline here. 968 // async_callback_completed_cb(IAsyncResult ar)969 void async_callback_completed_cb (IAsyncResult ar) 970 { 971 if (current_ai.end != null){ 972 try { 973 current_ai.end (ar); 974 } catch (Exception e) { 975 ProcessError (e); 976 } 977 } 978 979 Resume (); 980 } 981 async_handler_complete_cb(IAsyncResult ar)982 void async_handler_complete_cb (IAsyncResult ar) 983 { 984 IHttpAsyncHandler async_handler = ar != null ? ar.AsyncState as IHttpAsyncHandler : null; 985 986 try { 987 if (async_handler != null) 988 async_handler.EndProcessRequest (ar); 989 } catch (Exception e){ 990 ProcessError (e); 991 } 992 993 Resume (); 994 } 995 996 // 997 // This enumerator yields whether processing must be stopped: 998 // true: processing of the pipeline must be stopped 999 // false: processing of the pipeline must not be stopped 1000 // RunHooks(Delegate list)1001 IEnumerable RunHooks (Delegate list) 1002 { 1003 Delegate [] delegates = list.GetInvocationList (); 1004 1005 foreach (EventHandler d in delegates){ 1006 if (d.Target != null && (d.Target is AsyncInvoker)){ 1007 current_ai = (AsyncInvoker) d.Target; 1008 1009 try { 1010 must_yield = true; 1011 in_begin = true; 1012 context.BeginTimeoutPossible (); 1013 current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data); 1014 } finally { 1015 in_begin = false; 1016 context.EndTimeoutPossible (); 1017 } 1018 1019 // 1020 // If things are still moving forward, yield this 1021 // thread now 1022 // 1023 if (must_yield) 1024 yield return stop_processing; 1025 else if (stop_processing) 1026 yield return true; 1027 } else { 1028 try { 1029 context.BeginTimeoutPossible (); 1030 d (this, EventArgs.Empty); 1031 } finally { 1032 context.EndTimeoutPossible (); 1033 } 1034 if (stop_processing) 1035 yield return true; 1036 } 1037 } 1038 } 1039 FinalErrorWrite(HttpResponse response, string error)1040 static void FinalErrorWrite (HttpResponse response, string error) 1041 { 1042 try { 1043 response.Write (error); 1044 response.Flush (true); 1045 } catch { 1046 response.Close (); 1047 } 1048 } 1049 OutputPage()1050 void OutputPage () 1051 { 1052 if (context.Error == null){ 1053 try { 1054 context.Response.Flush (true); 1055 } catch (Exception e){ 1056 context.AddError (e); 1057 } 1058 } 1059 1060 Exception error = context.Error; 1061 if (error != null){ 1062 HttpResponse response = context.Response; 1063 1064 if (!response.HeadersSent){ 1065 response.ClearHeaders (); 1066 response.ClearContent (); 1067 1068 if (error is HttpException){ 1069 response.StatusCode = ((HttpException)error).GetHttpCode (); 1070 } else { 1071 error = HttpException.NewWithCode (String.Empty, error, WebEventCodes.WebErrorOtherError); 1072 response.StatusCode = 500; 1073 } 1074 HttpException httpEx = (HttpException) error; 1075 if (!RedirectCustomError (ref httpEx)) 1076 FinalErrorWrite (response, httpEx.GetHtmlErrorMessage ()); 1077 else 1078 response.Flush (true); 1079 } else { 1080 if (!(error is HttpException)) 1081 error = HttpException.NewWithCode (String.Empty, error, WebEventCodes.WebErrorOtherError); 1082 FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ()); 1083 } 1084 } 1085 1086 } 1087 1088 // 1089 // Invoked at the end of the pipeline execution 1090 // PipelineDone()1091 void PipelineDone () 1092 { 1093 try { 1094 EventHandler handler = Events [EndRequestEvent] as EventHandler; 1095 if (handler != null) 1096 handler (this, EventArgs.Empty); 1097 } catch (Exception e){ 1098 ProcessError (e); 1099 } 1100 1101 try { 1102 OutputPage (); 1103 } catch (ThreadAbortException taex) { 1104 ProcessError (taex); 1105 Thread.ResetAbort (); 1106 } catch (Exception e) { 1107 Console.WriteLine ("Internal error: OutputPage threw an exception " + e); 1108 } finally { 1109 context.WorkerRequest.EndOfRequest(); 1110 if (factory != null && context.Handler != null){ 1111 factory.ReleaseHandler (context.Handler); 1112 context.Handler = null; 1113 factory = null; 1114 } 1115 context.PopHandler (); 1116 1117 // context = null; -> moved to PostDone 1118 pipeline = null; 1119 current_ai = null; 1120 } 1121 PostDone (); 1122 1123 if (begin_iar != null) 1124 begin_iar.Complete (); 1125 else 1126 done.Set (); 1127 1128 requests_total_counter.Increment (); 1129 } 1130 1131 class Tim { 1132 string name; 1133 DateTime start; 1134 Tim()1135 public Tim () { 1136 } 1137 Tim(string name)1138 public Tim (string name) { 1139 this.name = name; 1140 } 1141 1142 public string Name { 1143 get { return name; } 1144 set { name = value; } 1145 } 1146 Start()1147 public void Start () { 1148 start = DateTime.UtcNow; 1149 } 1150 Stop()1151 public void Stop () { 1152 Console.WriteLine ("{0}: {1}ms", name, (DateTime.UtcNow - start).TotalMilliseconds); 1153 } 1154 } 1155 1156 Tim tim; 1157 [Conditional ("PIPELINE_TIMER")] StartTimer(string name)1158 void StartTimer (string name) 1159 { 1160 if (tim == null) 1161 tim = new Tim (); 1162 tim.Name = name; 1163 tim.Start (); 1164 } 1165 1166 [Conditional ("PIPELINE_TIMER")] StopTimer()1167 void StopTimer () 1168 { 1169 tim.Stop (); 1170 } 1171 1172 // 1173 // Events fired as described in `Http Runtime Support, HttpModules, 1174 // Handling Public Events' 1175 // Pipeline()1176 IEnumerator Pipeline () 1177 { 1178 Delegate eventHandler; 1179 if (stop_processing) 1180 yield return true; 1181 HttpRequest req = context.Request; 1182 if (req != null) 1183 req.Validate (); 1184 context.MapRequestHandlerDone = false; 1185 StartTimer ("BeginRequest"); 1186 eventHandler = Events [BeginRequestEvent]; 1187 if (eventHandler != null) { 1188 foreach (bool stop in RunHooks (eventHandler)) 1189 yield return stop; 1190 } 1191 StopTimer (); 1192 1193 StartTimer ("AuthenticateRequest"); 1194 eventHandler = Events [AuthenticateRequestEvent]; 1195 if (eventHandler != null) 1196 foreach (bool stop in RunHooks (eventHandler)) 1197 yield return stop; 1198 StopTimer (); 1199 1200 StartTimer ("DefaultAuthentication"); 1201 if (DefaultAuthentication != null) 1202 foreach (bool stop in RunHooks (DefaultAuthentication)) 1203 yield return stop; 1204 StopTimer (); 1205 1206 StartTimer ("PostAuthenticateRequest"); 1207 eventHandler = Events [PostAuthenticateRequestEvent]; 1208 if (eventHandler != null) 1209 foreach (bool stop in RunHooks (eventHandler)) 1210 yield return stop; 1211 StopTimer (); 1212 1213 StartTimer ("AuthorizeRequest"); 1214 eventHandler = Events [AuthorizeRequestEvent]; 1215 if (eventHandler != null) 1216 foreach (bool stop in RunHooks (eventHandler)) 1217 yield return stop; 1218 StopTimer (); 1219 1220 StartTimer ("PostAuthorizeRequest"); 1221 eventHandler = Events [PostAuthorizeRequestEvent]; 1222 if (eventHandler != null) 1223 foreach (bool stop in RunHooks (eventHandler)) 1224 yield return stop; 1225 StopTimer (); 1226 1227 StartTimer ("ResolveRequestCache"); 1228 eventHandler = Events [ResolveRequestCacheEvent]; 1229 if (eventHandler != null) 1230 foreach (bool stop in RunHooks (eventHandler)) 1231 yield return stop; 1232 StopTimer (); 1233 1234 StartTimer ("PostResolveRequestCache"); 1235 eventHandler = Events [PostResolveRequestCacheEvent]; 1236 if (eventHandler != null) 1237 foreach (bool stop in RunHooks (eventHandler)) 1238 yield return stop; 1239 StopTimer (); 1240 1241 StartTimer ("MapRequestHandler"); 1242 // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx 1243 eventHandler = Events [MapRequestHandlerEvent]; 1244 if (eventHandler != null) 1245 foreach (bool stop in RunHooks (eventHandler)) 1246 yield return stop; 1247 StopTimer (); 1248 context.MapRequestHandlerDone = true; 1249 1250 StartTimer ("GetHandler"); 1251 // Obtain the handler for the request. 1252 IHttpHandler handler = null; 1253 try { 1254 handler = GetHandler (context, context.Request.CurrentExecutionFilePath); 1255 context.Handler = handler; 1256 context.PushHandler (handler); 1257 } catch (FileNotFoundException fnf){ 1258 if (context.Request.IsLocal) 1259 ProcessError (HttpException.NewWithCode (404, 1260 String.Format ("File not found {0}", fnf.FileName), 1261 fnf, 1262 context.Request.FilePath, 1263 WebEventCodes.RuntimeErrorRequestAbort)); 1264 else 1265 ProcessError (HttpException.NewWithCode (404, 1266 "File not found: " + Path.GetFileName (fnf.FileName), 1267 context.Request.FilePath, 1268 WebEventCodes.RuntimeErrorRequestAbort)); 1269 } catch (DirectoryNotFoundException dnf){ 1270 if (!context.Request.IsLocal) 1271 dnf = null; // Do not "leak" real path information 1272 ProcessError (HttpException.NewWithCode (404, "Directory not found", dnf, WebEventCodes.RuntimeErrorRequestAbort)); 1273 } catch (Exception e) { 1274 ProcessError (e); 1275 } 1276 1277 StopTimer (); 1278 if (stop_processing) 1279 yield return true; 1280 1281 StartTimer ("PostMapRequestHandler"); 1282 eventHandler = Events [PostMapRequestHandlerEvent]; 1283 if (eventHandler != null) 1284 foreach (bool stop in RunHooks (eventHandler)) 1285 yield return stop; 1286 StopTimer (); 1287 1288 StartTimer ("AcquireRequestState"); 1289 eventHandler = Events [AcquireRequestStateEvent]; 1290 if (eventHandler != null){ 1291 foreach (bool stop in RunHooks (eventHandler)) 1292 yield return stop; 1293 } 1294 StopTimer (); 1295 1296 StartTimer ("PostAcquireRequestState"); 1297 eventHandler = Events [PostAcquireRequestStateEvent]; 1298 if (eventHandler != null){ 1299 foreach (bool stop in RunHooks (eventHandler)) 1300 yield return stop; 1301 } 1302 StopTimer (); 1303 1304 // 1305 // From this point on, we need to ensure that we call 1306 // ReleaseRequestState, so the code below jumps to 1307 // `release:' to guarantee it rather than yielding. 1308 // 1309 StartTimer ("PreRequestHandlerExecute"); 1310 eventHandler = Events [PreRequestHandlerExecuteEvent]; 1311 if (eventHandler != null) 1312 foreach (bool stop in RunHooks (eventHandler)) 1313 if (stop) 1314 goto release; 1315 StopTimer (); 1316 1317 1318 1319 IHttpHandler ctxHandler = context.Handler; 1320 if (ctxHandler != null && handler != ctxHandler) { 1321 context.PopHandler (); 1322 handler = ctxHandler; 1323 context.PushHandler (handler); 1324 } 1325 1326 StartTimer ("ProcessRequest"); 1327 try { 1328 context.BeginTimeoutPossible (); 1329 if (handler != null){ 1330 IHttpAsyncHandler async_handler = handler as IHttpAsyncHandler; 1331 1332 if (async_handler != null){ 1333 must_yield = true; 1334 in_begin = true; 1335 async_handler.BeginProcessRequest (context, async_handler_complete_cb, handler); 1336 } else { 1337 must_yield = false; 1338 handler.ProcessRequest (context); 1339 } 1340 } else 1341 throw new InvalidOperationException ("No handler for the current request."); 1342 if (context.Error != null) 1343 throw new TargetInvocationException(context.Error); 1344 } finally { 1345 in_begin = false; 1346 context.EndTimeoutPossible (); 1347 } 1348 StopTimer (); 1349 if (must_yield) 1350 yield return stop_processing; 1351 else if (stop_processing) 1352 goto release; 1353 1354 // These are executed after the application has returned 1355 1356 StartTimer ("PostRequestHandlerExecute"); 1357 eventHandler = Events [PostRequestHandlerExecuteEvent]; 1358 if (eventHandler != null) 1359 foreach (bool stop in RunHooks (eventHandler)) 1360 if (stop) 1361 goto release; 1362 StopTimer (); 1363 1364 release: 1365 StartTimer ("ReleaseRequestState"); 1366 eventHandler = Events [ReleaseRequestStateEvent]; 1367 if (eventHandler != null){ 1368 #pragma warning disable 219 1369 foreach (bool stop in RunHooks (eventHandler)) { 1370 // 1371 // Ignore the stop signal while release the state 1372 // 1373 1374 } 1375 #pragma warning restore 219 1376 } 1377 StopTimer (); 1378 1379 if (stop_processing) 1380 yield return true; 1381 1382 StartTimer ("PostReleaseRequestState"); 1383 eventHandler = Events [PostReleaseRequestStateEvent]; 1384 if (eventHandler != null) 1385 foreach (bool stop in RunHooks (eventHandler)) 1386 yield return stop; 1387 StopTimer (); 1388 1389 StartTimer ("Filter"); 1390 if (context.Error == null) 1391 context.Response.DoFilter (true); 1392 StopTimer (); 1393 1394 StartTimer ("UpdateRequestCache"); 1395 eventHandler = Events [UpdateRequestCacheEvent]; 1396 if (eventHandler != null) 1397 foreach (bool stop in RunHooks (eventHandler)) 1398 yield return stop; 1399 StopTimer (); 1400 1401 StartTimer ("PostUpdateRequestCache"); 1402 eventHandler = Events [PostUpdateRequestCacheEvent]; 1403 if (eventHandler != null) 1404 foreach (bool stop in RunHooks (eventHandler)) 1405 yield return stop; 1406 StopTimer (); 1407 1408 StartTimer ("LogRequest"); 1409 eventHandler = Events [LogRequestEvent]; 1410 if (eventHandler != null) 1411 foreach (bool stop in RunHooks (eventHandler)) 1412 yield return stop; 1413 StopTimer (); 1414 1415 StartTimer ("PostLogRequest"); 1416 eventHandler = Events [PostLogRequestEvent]; 1417 if (eventHandler != null) 1418 foreach (bool stop in RunHooks (eventHandler)) 1419 yield return stop; 1420 StopTimer (); 1421 1422 StartTimer ("PipelineDone"); 1423 PipelineDone (); 1424 StopTimer (); 1425 } 1426 1427 GetThreadCulture(HttpRequest request, CultureInfo culture, bool isAuto)1428 internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto) 1429 { 1430 if (!isAuto) 1431 return culture; 1432 CultureInfo ret = null; 1433 string[] languages = request.UserLanguages; 1434 try { 1435 if (languages != null && languages.Length > 0) 1436 ret = CultureInfo.CreateSpecificCulture (languages[0]); 1437 } catch { 1438 } 1439 1440 if (ret == null) 1441 ret = culture; 1442 1443 return ret; 1444 } 1445 1446 PreStart()1447 void PreStart () 1448 { 1449 GlobalizationSection cfg; 1450 cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization"); 1451 app_culture = cfg.GetCulture (); 1452 autoCulture = cfg.IsAutoCulture; 1453 appui_culture = cfg.GetUICulture (); 1454 autoUICulture = cfg.IsAutoUICulture; 1455 context.StartTimeoutTimer (); 1456 Thread th = Thread.CurrentThread; 1457 if (app_culture != null) { 1458 prev_app_culture = th.CurrentCulture; 1459 CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture); 1460 if (!new_app_culture.Equals (Helpers.InvariantCulture)) 1461 th.CurrentCulture = new_app_culture; 1462 } 1463 1464 if (appui_culture != null) { 1465 prev_appui_culture = th.CurrentUICulture; 1466 CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture); 1467 if (!new_app_culture.Equals (Helpers.InvariantCulture)) 1468 th.CurrentUICulture = new_app_culture; 1469 } 1470 1471 prev_user = Thread.CurrentPrincipal; 1472 } 1473 PostDone()1474 void PostDone () 1475 { 1476 if (removeConfigurationFromCache) { 1477 WebConfigurationManager.RemoveConfigurationFromCache (context); 1478 removeConfigurationFromCache = false; 1479 } 1480 1481 Thread th = Thread.CurrentThread; 1482 if (Thread.CurrentPrincipal != prev_user) 1483 Thread.CurrentPrincipal = prev_user; 1484 if (prev_appui_culture != null && prev_appui_culture != th.CurrentUICulture) 1485 th.CurrentUICulture = prev_appui_culture; 1486 if (prev_app_culture != null && prev_app_culture != th.CurrentCulture) 1487 th.CurrentCulture = prev_app_culture; 1488 1489 if (context == null) 1490 context = HttpContext.Current; 1491 context.StopTimeoutTimer (); 1492 context.Request.ReleaseResources (); 1493 context.Response.ReleaseResources (); 1494 context = null; 1495 session = null; 1496 HttpContext.Current = null; 1497 } 1498 Start(object x)1499 void Start (object x) 1500 { 1501 var cultures = x as CultureInfo []; 1502 if (cultures != null && cultures.Length == 2) { 1503 Thread ct = Thread.CurrentThread; 1504 ct.CurrentCulture = cultures [0]; 1505 ct.CurrentUICulture = cultures [1]; 1506 } 1507 1508 InitOnce (true); 1509 if (initialization_exception != null) { 1510 Exception e = initialization_exception; 1511 HttpException exc = HttpException.NewWithCode (String.Empty, e, WebEventCodes.RuntimeErrorRequestAbort); 1512 context.Response.StatusCode = 500; 1513 FinalErrorWrite (context.Response, exc.GetHtmlErrorMessage ()); 1514 PipelineDone (); 1515 return; 1516 } 1517 1518 HttpContext.Current = Context; 1519 PreStart (); 1520 pipeline = Pipeline (); 1521 Tick (); 1522 } 1523 1524 const string HANDLER_CACHE = "@@HttpHandlerCache@@"; 1525 GetHandlerCache()1526 internal static Hashtable GetHandlerCache () 1527 { 1528 Cache cache = HttpRuntime.InternalCache; 1529 Hashtable ret = cache [HANDLER_CACHE] as Hashtable; 1530 1531 if (ret == null) { 1532 ret = new Hashtable (); 1533 cache.Insert (HANDLER_CACHE, ret); 1534 } 1535 1536 return ret; 1537 } 1538 ClearHandlerCache()1539 internal static void ClearHandlerCache () 1540 { 1541 Hashtable cache = GetHandlerCache (); 1542 cache.Clear (); 1543 } 1544 LocateHandler(HttpRequest req, string verb, string url)1545 object LocateHandler (HttpRequest req, string verb, string url) 1546 { 1547 Hashtable cache = GetHandlerCache (); 1548 string id = String.Concat (verb, url); 1549 object ret = cache [id]; 1550 1551 if (ret != null) 1552 return ret; 1553 1554 bool allowCache; 1555 HttpHandlersSection httpHandlersSection = WebConfigurationManager.GetSection ("system.web/httpHandlers", req.Path, req.Context) as HttpHandlersSection; 1556 ret = httpHandlersSection.LocateHandler (verb, url, out allowCache); 1557 1558 IHttpHandler handler = ret as IHttpHandler; 1559 if (allowCache && handler != null && handler.IsReusable) 1560 cache [id] = ret; 1561 1562 return ret; 1563 } 1564 GetHandler(HttpContext context, string url)1565 internal IHttpHandler GetHandler (HttpContext context, string url) 1566 { 1567 return GetHandler (context, url, false); 1568 } 1569 1570 // Used by HttpServerUtility.Execute GetHandler(HttpContext context, string url, bool ignoreContextHandler)1571 internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler) 1572 { 1573 if (!ignoreContextHandler && context.Handler != null) 1574 return context.Handler; 1575 1576 HttpRequest request = context.Request; 1577 string verb = request.RequestType; 1578 1579 IHttpHandler handler = null; 1580 object o = LocateHandler (request, verb, url); 1581 1582 factory = o as IHttpHandlerFactory; 1583 if (factory == null) { 1584 handler = (IHttpHandler) o; 1585 } else { 1586 handler = factory.GetHandler (context, verb, url, request.MapPath (url)); 1587 } 1588 1589 return handler; 1590 } 1591 IHttpHandler.ProcessRequest(HttpContext context)1592 void IHttpHandler.ProcessRequest (HttpContext context) 1593 { 1594 begin_iar = null; 1595 this.context = context; 1596 done.Reset (); 1597 1598 Start (null); 1599 done.WaitOne (); 1600 } 1601 1602 // 1603 // This is used by FireOnAppStart, when we init the application 1604 // as the context is required to be set at that point (the user 1605 // might call methods that require it on that hook). 1606 // SetContext(HttpContext context)1607 internal void SetContext (HttpContext context) 1608 { 1609 this.context = context; 1610 } 1611 SetSession(HttpSessionState session)1612 internal void SetSession (HttpSessionState session) 1613 { 1614 this.session = session; 1615 } 1616 IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)1617 IAsyncResult IHttpAsyncHandler.BeginProcessRequest (HttpContext context, AsyncCallback cb, object extraData) 1618 { 1619 this.context = context; 1620 done.Reset (); 1621 1622 begin_iar = new AsyncRequestState (done, cb, extraData); 1623 1624 CultureInfo[] cultures = new CultureInfo [2]; 1625 cultures [0] = Thread.CurrentThread.CurrentCulture; 1626 cultures [1] = Thread.CurrentThread.CurrentUICulture; 1627 1628 if (Thread.CurrentThread.IsThreadPoolThread) 1629 Start (null); 1630 else 1631 ThreadPool.QueueUserWorkItem (x => { 1632 try { 1633 Start (x); 1634 } catch (Exception e) { 1635 Console.Error.WriteLine (e); 1636 } 1637 }); 1638 1639 return begin_iar; 1640 } 1641 IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)1642 void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result) 1643 { 1644 if (!result.IsCompleted) 1645 result.AsyncWaitHandle.WaitOne (); 1646 begin_iar = null; 1647 } 1648 Init()1649 public virtual void Init () 1650 { 1651 } 1652 1653 bool IHttpHandler.IsReusable { 1654 get { 1655 return true; 1656 } 1657 } 1658 RegisterModule(Type moduleType)1659 public static void RegisterModule (Type moduleType) 1660 { 1661 HttpRuntimeSection config = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime"); 1662 1663 if (!config.AllowDynamicModuleRegistration) 1664 throw new InvalidOperationException ("The Application has requested to register a dynamic Module, but dynamic module registration is disabled in web.config."); 1665 1666 dynamicModuleManeger.Add (moduleType); 1667 } 1668 1669 CreateDynamicModules()1670 HttpModuleCollection CreateDynamicModules () 1671 { 1672 HttpModuleCollection modules = new HttpModuleCollection (); 1673 1674 foreach (var module in dynamicModuleManeger.LockAndGetModules ()) { 1675 IHttpModule httpModule = CreateModuleInstance (module.Type); 1676 httpModule.Init (this); 1677 modules.AddModule (module.Name, httpModule); 1678 } 1679 return modules; 1680 } 1681 CreateModuleInstance(Type type)1682 IHttpModule CreateModuleInstance (Type type) 1683 { 1684 return (IHttpModule) Activator.CreateInstance (type, 1685 BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance, 1686 null, 1687 null, 1688 null); 1689 } 1690 1691 #region internals ClearError()1692 internal void ClearError () 1693 { 1694 context.ClearError (); 1695 } 1696 RedirectErrorPage(string error_page)1697 bool RedirectErrorPage (string error_page) 1698 { 1699 if (context.Request.QueryString ["aspxerrorpath"] != null) 1700 return false; 1701 1702 Response.Redirect (error_page + "?aspxerrorpath=" + Request.Path, false); 1703 return true; 1704 } 1705 RedirectCustomError(ref HttpException httpEx)1706 bool RedirectCustomError (ref HttpException httpEx) 1707 { 1708 try { 1709 if (!context.IsCustomErrorEnabledUnsafe) 1710 return false; 1711 1712 CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors"); 1713 if (config == null) { 1714 if (context.ErrorPage != null) 1715 return RedirectErrorPage (context.ErrorPage); 1716 1717 return false; 1718 } 1719 1720 CustomError err = config.Errors [context.Response.StatusCode.ToString()]; 1721 string redirect = err == null ? null : err.Redirect; 1722 if (redirect == null) { 1723 redirect = context.ErrorPage; 1724 if (redirect == null) 1725 redirect = config.DefaultRedirect; 1726 } 1727 1728 if (redirect == null) 1729 return false; 1730 1731 if (config.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite) { 1732 context.Server.Execute (redirect); 1733 return true; 1734 } 1735 1736 return RedirectErrorPage (redirect); 1737 } 1738 catch (Exception ex) { 1739 httpEx = HttpException.NewWithCode (500, String.Empty, ex, WebEventCodes.WebErrorOtherError); 1740 return false; 1741 } 1742 } 1743 #endregion 1744 internal static string BinDirectory 1745 { 1746 get { 1747 if (binDirectory == null) { 1748 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; 1749 string baseDir = setup.ApplicationBase; 1750 string bindir; 1751 1752 foreach (string dir in BinDirs) { 1753 bindir = Path.Combine (baseDir, dir); 1754 if (!Directory.Exists (bindir)) 1755 continue; 1756 binDirectory = bindir; 1757 break; 1758 } 1759 } 1760 1761 return binDirectory; 1762 } 1763 } 1764 1765 internal static string[] BinDirectoryAssemblies 1766 { 1767 get { 1768 ArrayList binDlls = null; 1769 string[] dlls; 1770 1771 string bindir = BinDirectory; 1772 if (bindir != null) { 1773 binDlls = new ArrayList (); 1774 dlls = Directory.GetFiles (bindir, "*.dll"); 1775 binDlls.AddRange (dlls); 1776 } 1777 1778 if (binDlls == null) 1779 return new string[] {}; 1780 1781 return (string[]) binDlls.ToArray (typeof (string)); 1782 } 1783 } 1784 LoadType(string typeName)1785 internal static Type LoadType (string typeName) 1786 { 1787 return LoadType (typeName, false); 1788 } 1789 LoadType(string typeName, bool throwOnMissing)1790 internal static Type LoadType (string typeName, bool throwOnMissing) 1791 { 1792 Type type = Type.GetType (typeName); 1793 if (type != null) 1794 return type; 1795 1796 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies (); 1797 foreach (Assembly ass in assemblies) { 1798 type = ass.GetType (typeName, false); 1799 if (type != null) 1800 return type; 1801 } 1802 1803 IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies; 1804 if (tla != null && tla.Count > 0) { 1805 foreach (Assembly asm in tla) { 1806 if (asm == null) 1807 continue; 1808 type = asm.GetType (typeName, false); 1809 if (type != null) 1810 return type; 1811 } 1812 } 1813 1814 Exception loadException = null; 1815 try { 1816 type = null; 1817 type = LoadTypeFromBin (typeName); 1818 } catch (Exception ex) { 1819 loadException = ex; 1820 } 1821 1822 if (type != null) 1823 return type; 1824 if (throwOnMissing) 1825 throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName), loadException); 1826 1827 return null; 1828 } 1829 LoadType(string typeName, bool throwOnMissing)1830 internal static Type LoadType <TBaseType> (string typeName, bool throwOnMissing) 1831 { 1832 Type ret = LoadType (typeName, throwOnMissing); 1833 1834 if (typeof (TBaseType).IsAssignableFrom (ret)) 1835 return ret; 1836 1837 if (throwOnMissing) 1838 throw new TypeLoadException (String.Format ("Type '{0}' found but it doesn't derive from base type '{1}'.", typeName, typeof (TBaseType))); 1839 1840 return null; 1841 } 1842 LoadTypeFromBin(string typeName)1843 internal static Type LoadTypeFromBin (string typeName) 1844 { 1845 Type type = null; 1846 1847 foreach (string s in BinDirectoryAssemblies) { 1848 Assembly binA = null; 1849 1850 try { 1851 binA = Assembly.LoadFrom (s); 1852 } catch (FileLoadException) { 1853 // ignore 1854 continue; 1855 } catch (BadImageFormatException) { 1856 // ignore 1857 continue; 1858 } 1859 1860 type = binA.GetType (typeName, false); 1861 if (type == null) 1862 continue; 1863 1864 return type; 1865 } 1866 1867 return null; 1868 } 1869 } 1870 1871 // 1872 // Based on Fritz' Onion's AsyncRequestState class for asynchronous IHttpAsyncHandlers 1873 // 1874 class AsyncRequestState : IAsyncResult { 1875 AsyncCallback cb; 1876 object cb_data; 1877 bool completed; 1878 ManualResetEvent complete_event = null; 1879 AsyncRequestState(ManualResetEvent complete_event, AsyncCallback cb, object cb_data)1880 internal AsyncRequestState (ManualResetEvent complete_event, AsyncCallback cb, object cb_data) 1881 { 1882 this.cb = cb; 1883 this.cb_data = cb_data; 1884 this.complete_event = complete_event; 1885 } 1886 Complete()1887 internal void Complete () 1888 { 1889 completed = true; 1890 try { 1891 // 1892 // TODO: if this throws an error, we have no way of reporting it 1893 // Not really too bad, since the only failure might be 1894 // `HttpRuntime.request_processed'. 1895 // 1896 if (cb != null) 1897 cb (this); 1898 } catch { 1899 } 1900 1901 complete_event.Set (); 1902 } 1903 1904 public object AsyncState { 1905 get { 1906 return cb_data; 1907 } 1908 } 1909 1910 public bool CompletedSynchronously { 1911 get { 1912 return false; 1913 } 1914 } 1915 1916 public bool IsCompleted { 1917 get { 1918 return completed; 1919 } 1920 } 1921 1922 public WaitHandle AsyncWaitHandle { 1923 get { 1924 return complete_event; 1925 } 1926 } 1927 } 1928 1929 #region Helper classes 1930 1931 // 1932 // A wrapper to keep track of begin/end pairs 1933 // 1934 class AsyncInvoker { 1935 public BeginEventHandler begin; 1936 public EndEventHandler end; 1937 public object data; 1938 HttpApplication app; 1939 AsyncCallback callback; 1940 AsyncInvoker(BeginEventHandler bh, EndEventHandler eh, HttpApplication a, object d)1941 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, HttpApplication a, object d) 1942 { 1943 begin = bh; 1944 end = eh; 1945 data = d; 1946 app = a; 1947 callback = new AsyncCallback (doAsyncCallback); 1948 } 1949 AsyncInvoker(BeginEventHandler bh, EndEventHandler eh, HttpApplication app)1950 public AsyncInvoker (BeginEventHandler bh, EndEventHandler eh, HttpApplication app) : this(bh, eh, app, null) { } 1951 Invoke(object sender, EventArgs e)1952 public void Invoke (object sender, EventArgs e) 1953 { 1954 IAsyncResult res; 1955 res = begin (app, e, callback, data); 1956 } 1957 doAsyncCallback(IAsyncResult res)1958 void doAsyncCallback (IAsyncResult res) 1959 { 1960 ThreadPool.QueueUserWorkItem ((object ores) => { 1961 IAsyncResult tres = (IAsyncResult) ores; 1962 try { 1963 end (tres); 1964 } catch (Exception ee) { 1965 // I tried using ProcessError(), but we only come here frome an Invokation in PipelineDone(). 1966 // Using ProcessError, I still get a blank screen, this way, we at least log the error to console... 1967 Console.Error.WriteLine (ee.ToString ()); 1968 } 1969 }, res); 1970 } 1971 } 1972 #endregion 1973 } 1974 1975