2010-05-05 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpApplication.cs
index dec51e2363d8d51e8faae0e6f3326f539541a5f5..d9972ceddec874d60ed40d8dafba25186e78fad8 100644 (file)
@@ -6,7 +6,7 @@
 //     Gonzalo Paniagua (gonzalo@ximian.com)
 //    
 //
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -66,31 +66,43 @@ using System.IO;
 using System.Collections;
 using System.ComponentModel;
 using System.Configuration;
+using System.Diagnostics;
 using System.Globalization;
 using System.Reflection;
 using System.Security.Permissions;
 using System.Security.Principal;
 using System.Threading;
 using System.Web.Caching;
+using System.Web.Compilation;
 using System.Web.Configuration;
+using System.Web.Management;
 using System.Web.SessionState;
 using System.Web.UI;
+using System.Web.Util;
 
 #if TARGET_J2EE
 using Mainsoft.Web;
 #endif
        
-namespace System.Web {
-
+namespace System.Web
+{
        // CAS
        [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
        // attributes
        [ToolboxItem(false)]
-       public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable {
-               object this_lock = new object();
-
+       public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable
+       {
+               static readonly object disposedEvent = new object ();
+               static readonly object errorEvent = new object ();
+               
+               // we do this static rather than per HttpApplication because
+               // mono's perfcounters use the counter instance parameter for
+               // the process to access shared memory.
+               internal static PerformanceCounter requests_total_counter = new PerformanceCounter ("ASP.NET", "Requests Total");
+               
                internal static readonly string [] BinDirs = {"Bin", "bin"};
+               object this_lock = new object();
                
                HttpContext context;
                HttpSessionState session;
@@ -118,6 +130,11 @@ namespace System.Web {
                //
                bool stop_processing;
 
+               //
+               // See https://bugzilla.novell.com/show_bug.cgi?id=381971
+               //
+               bool in_application_start;
+               
                //
                // The Pipeline
                //
@@ -132,9 +149,9 @@ namespace System.Web {
                // Tracks the current AsyncInvocation being dispatched
                AsyncInvoker current_ai;
 
-               // We don't use the EventHandlerList here, but derived classes might do
                EventHandlerList events;
-
+               EventHandlerList nonApplicationEvents = new EventHandlerList ();
+               
                // Culture and IPrincipal
                CultureInfo app_culture;
                CultureInfo appui_culture;
@@ -142,9 +159,8 @@ namespace System.Web {
                CultureInfo prev_appui_culture;
                IPrincipal prev_user;
 
-               static bool _runningOnWindows;
+               static string binDirectory;
                
-#if NET_2_0
 #if TARGET_J2EE
                const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
                static Exception initialization_exception {
@@ -155,8 +171,8 @@ namespace System.Web {
                static Exception initialization_exception;
 #endif
                bool removeConfigurationFromCache;
-#endif
-
+               bool fullInitComplete = false;
+               
                //
                // These are used to detect the case where the EndXXX method is invoked
                // from within the BeginXXXX delegate, so we detect whether we kick the
@@ -165,12 +181,16 @@ namespace System.Web {
                bool must_yield;
                bool in_begin;
 
-               static HttpApplication ()
-               {
-                       PlatformID pid = Environment.OSVersion.Platform;
-                       _runningOnWindows = ((int) pid != 128 && (int) pid != 4);
+               public virtual event EventHandler Disposed {
+                       add { nonApplicationEvents.AddHandler (disposedEvent, value); }
+                       remove { nonApplicationEvents.RemoveHandler (disposedEvent, value); }
                }
                
+               public virtual event EventHandler Error {
+                       add { nonApplicationEvents.AddHandler (errorEvent, value); }
+                       remove { nonApplicationEvents.RemoveHandler (errorEvent, value); }
+               }
+
                public HttpApplication ()
                {
                        done = new ManualResetEvent (false);
@@ -181,25 +201,27 @@ namespace System.Web {
                        lock (this_lock) {
                                if (modcoll != null)
                                        return;
-
-#if NET_2_0
+                               
                                HttpModulesSection modules;
-                               modules = (HttpModulesSection) WebConfigurationManager.GetSection ("system.web/httpModules", HttpRuntime.AppDomainAppVirtualPath);
-#else
-                               ModulesConfiguration modules;
-
-                               modules = (ModulesConfiguration) HttpContext.GetAppConfig ("system.web/httpModules");
-#endif
-
+                               modules = (HttpModulesSection) WebConfigurationManager.GetWebApplicationSection ("system.web/httpModules");
+                               HttpContext saved = HttpContext.Current;
+                               HttpContext.Current = new HttpContext (new System.Web.Hosting.SimpleWorkerRequest (String.Empty, String.Empty, new StringWriter()));
                                modcoll = modules.LoadModules (this);
+                               HttpContext.Current = saved;
 
                                if (full_init) {
                                        HttpApplicationFactory.AttachEvents (this);
                                        Init ();
+                                       fullInitComplete = true;
                                }
                        }
                }
 
+               internal bool InApplicationStart {
+                       get { return in_application_start; }
+                       set { in_application_start = value; }
+               }
+               
                internal string AssemblyLocation {
                        get {
                                if (assemblyLocation == null)
@@ -208,11 +230,9 @@ namespace System.Web {
                        }
                }
 
-#if NET_2_0
                internal static Exception InitializationException {
                        get { return initialization_exception; }
                }
-#endif
 
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -244,8 +264,10 @@ namespace System.Web {
                public HttpModuleCollection Modules {
                        [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.High)]
                        get {
-                               if (modcoll == null)
-                                       modcoll = new HttpModuleCollection ();
+                               lock (this_lock) {
+                                       if (modcoll == null)
+                                               modcoll = new HttpModuleCollection ();
+                               }
                                
                                return modcoll;
                        }
@@ -256,10 +278,10 @@ namespace System.Web {
                public HttpRequest Request {
                        get {
                                if (context == null)
-                                       throw new HttpException (Locale.GetText ("No context is available."));
+                                       throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort);
 
                                if (false == HttpApplicationFactory.ContextAvailable)
-                                       throw new HttpException (Locale.GetText ("Request is not available in this context."));
+                                       throw HttpException.NewWithCode (Locale.GetText ("Request is not available in this context."), WebEventCodes.RuntimeErrorRequestAbort);
 
                                return context.Request;
                        }
@@ -270,10 +292,10 @@ namespace System.Web {
                public HttpResponse Response {
                        get {
                                if (context == null)
-                                       throw new HttpException (Locale.GetText ("No context is available."));
+                                       throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort);
 
                                if (false == HttpApplicationFactory.ContextAvailable)
-                                       throw new HttpException (Locale.GetText ("Response is not available in this context."));
+                                       throw HttpException.NewWithCode (Locale.GetText ("Response is not available in this context."), WebEventCodes.RuntimeErrorRequestAbort);
 
                                return context.Response;
                        }
@@ -303,25 +325,22 @@ namespace System.Web {
                                        return session;
 
                                if (context == null)
-                                       throw new HttpException (Locale.GetText ("No context is available."));
-                               return context.Session;
+                                       throw HttpException.NewWithCode (Locale.GetText ("No context is available."), WebEventCodes.RuntimeErrorRequestAbort);
+
+                               HttpSessionState ret = context.Session;
+                               if (ret == null)
+                                       throw HttpException.NewWithCode (Locale.GetText ("Session state is not available in the context."), WebEventCodes.RuntimeErrorRequestAbort);
+                               
+                               return ret;
                        }
                }
 
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
-#if NET_2_0
                public ISite Site {
-#else
-               public virtual ISite Site {
-#endif
-                       get {
-                               return isite;
-                       }
+                       get { return isite; }
 
-                       set {
-                               isite = value;
-                       }
+                       set { isite = value; }
                }
 
                [Browsable (false)]
@@ -337,95 +356,189 @@ namespace System.Web {
                        }
                }
                
-               public virtual event EventHandler Disposed;
-               public virtual event EventHandler Error;
-
-               public event EventHandler PreSendRequestHeaders;
+               static object PreSendRequestHeadersEvent = new object ();
+               public event EventHandler PreSendRequestHeaders
+               {
+                       add { AddEventHandler (PreSendRequestHeadersEvent, value); }
+                       remove { RemoveEventHandler (PreSendRequestHeadersEvent, value); }
+               }
+               
                internal void TriggerPreSendRequestHeaders ()
                {
-                       if (PreSendRequestHeaders != null)
-                               PreSendRequestHeaders (this, EventArgs.Empty);
+                       EventHandler handler = Events [PreSendRequestHeadersEvent] as EventHandler;
+                       if (handler != null)
+                               handler (this, EventArgs.Empty);
                }
 
-               public event EventHandler PreSendRequestContent;
+               static object PreSendRequestContentEvent = new object ();
+               public event EventHandler PreSendRequestContent
+               {
+                       add { AddEventHandler (PreSendRequestContentEvent, value); }
+                       remove { RemoveEventHandler (PreSendRequestContentEvent, value); }
+               }
+               
                internal void TriggerPreSendRequestContent ()
                {
-                       if (PreSendRequestContent != null)
-                               PreSendRequestContent (this, EventArgs.Empty);
+                       EventHandler handler = Events [PreSendRequestContentEvent] as EventHandler;
+                       if (handler != null)
+                               handler (this, EventArgs.Empty);
+               }
+
+               static object AcquireRequestStateEvent = new object ();
+               public event EventHandler AcquireRequestState
+               {
+                       add { AddEventHandler (AcquireRequestStateEvent, value); }
+                       remove { RemoveEventHandler (AcquireRequestStateEvent, value); }
                }
                
-               public event EventHandler AcquireRequestState;
                public void AddOnAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        AcquireRequestState += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler AuthenticateRequest;
+               static object AuthenticateRequestEvent = new object ();
+               public event EventHandler AuthenticateRequest
+               {
+                       add { AddEventHandler (AuthenticateRequestEvent, value); }
+                       remove { RemoveEventHandler (AuthenticateRequestEvent, value); }
+               }
+               
                public void AddOnAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        AuthenticateRequest += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler AuthorizeRequest;
+               static object AuthorizeRequestEvent = new object ();
+               public event EventHandler AuthorizeRequest
+               {
+                       add { AddEventHandler (AuthorizeRequestEvent, value); }
+                       remove { RemoveEventHandler (AuthorizeRequestEvent, value); }
+               }
+               
                public void AddOnAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        AuthorizeRequest += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler BeginRequest;
+               static object BeginRequestEvent = new object ();
+               public event EventHandler BeginRequest          
+               {
+                       add {
+                               // See https://bugzilla.novell.com/show_bug.cgi?id=381971
+                               if (InApplicationStart)
+                                       return;
+                               AddEventHandler (BeginRequestEvent, value);
+                       }
+                       remove {
+                               if (InApplicationStart)
+                                       return;
+                               RemoveEventHandler (BeginRequestEvent, value);
+                       }
+               }
+               
                public void AddOnBeginRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        BeginRequest += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler EndRequest;
+               static object EndRequestEvent = new object ();
+               public event EventHandler EndRequest
+               {
+                       add {
+                               // See https://bugzilla.novell.com/show_bug.cgi?id=381971
+                               if (InApplicationStart)
+                                       return;
+                               AddEventHandler (EndRequestEvent, value);
+                       }
+                       remove {
+                               if (InApplicationStart)
+                                       return;
+                               RemoveEventHandler (EndRequestEvent, value);
+                       }
+               }
+               
                public void AddOnEndRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        EndRequest += new EventHandler (invoker.Invoke);
                }
+
+               static object PostRequestHandlerExecuteEvent = new object ();
+               public event EventHandler PostRequestHandlerExecute
+               {
+                       add { AddEventHandler (PostRequestHandlerExecuteEvent, value); }
+                       remove { RemoveEventHandler (PostRequestHandlerExecuteEvent, value); }
+               }
                
-               public event EventHandler PostRequestHandlerExecute;
                public void AddOnPostRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        PostRequestHandlerExecute += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler PreRequestHandlerExecute;
+               static object PreRequestHandlerExecuteEvent = new object ();
+               public event EventHandler PreRequestHandlerExecute
+               {
+                       add { AddEventHandler (PreRequestHandlerExecuteEvent, value); }
+                       remove { RemoveEventHandler (PreRequestHandlerExecuteEvent, value); }
+               }
+               
                public void AddOnPreRequestHandlerExecuteAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        PreRequestHandlerExecute += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler ReleaseRequestState;
+               static object ReleaseRequestStateEvent = new object ();
+               public event EventHandler ReleaseRequestState
+               {
+                       add { AddEventHandler (ReleaseRequestStateEvent, value); }
+                       remove { RemoveEventHandler (ReleaseRequestStateEvent, value); }
+               }
+               
                public void AddOnReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        ReleaseRequestState += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler ResolveRequestCache;
+               static object ResolveRequestCacheEvent = new object ();
+               public event EventHandler ResolveRequestCache
+               {
+                       add { AddEventHandler (ResolveRequestCacheEvent, value); }
+                       remove { RemoveEventHandler (ResolveRequestCacheEvent, value); }
+               }
+               
                public void AddOnResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        ResolveRequestCache += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler UpdateRequestCache;
+               static object UpdateRequestCacheEvent = new object ();
+               public event EventHandler UpdateRequestCache
+               {
+                       add { AddEventHandler (UpdateRequestCacheEvent, value); }
+                       remove { RemoveEventHandler (UpdateRequestCacheEvent, value); }
+               }
+               
                public void AddOnUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh);
                        UpdateRequestCache += new EventHandler (invoker.Invoke);
                }
 
-#if NET_2_0
-               public event EventHandler PostAuthenticateRequest;
+               static object PostAuthenticateRequestEvent = new object ();
+               public event EventHandler PostAuthenticateRequest
+               {
+                       add { AddEventHandler (PostAuthenticateRequestEvent, value); }
+                       remove { RemoveEventHandler (PostAuthenticateRequestEvent, value); }
+               }
+               
                public void AddOnPostAuthenticateRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostAuthenticateRequestAsync (bh, eh, null);
@@ -436,8 +549,14 @@ namespace System.Web {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
                        PostAuthenticateRequest += new EventHandler (invoker.Invoke);
                }
+
+               static object PostAuthorizeRequestEvent = new object ();
+               public event EventHandler PostAuthorizeRequest
+               {
+                       add { AddEventHandler (PostAuthorizeRequestEvent, value); }
+                       remove { RemoveEventHandler (PostAuthorizeRequestEvent, value); }
+               }
                
-               public event EventHandler PostAuthorizeRequest;
                public void AddOnPostAuthorizeRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostAuthorizeRequestAsync (bh, eh, null);
@@ -448,8 +567,14 @@ namespace System.Web {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
                        PostAuthorizeRequest += new EventHandler (invoker.Invoke);
                }
-
-               public event EventHandler PostResolveRequestCache;
+               
+               static object PostResolveRequestCacheEvent = new object ();
+               public event EventHandler PostResolveRequestCache
+               {
+                       add { AddEventHandler (PostResolveRequestCacheEvent, value); }
+                       remove { RemoveEventHandler (PostResolveRequestCacheEvent, value); }
+               }
+               
                public void AddOnPostResolveRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostResolveRequestCacheAsync (bh, eh, null);
@@ -461,7 +586,13 @@ namespace System.Web {
                        PostResolveRequestCache += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler PostMapRequestHandler;
+               static object PostMapRequestHandlerEvent = new object ();
+               public event EventHandler PostMapRequestHandler
+               {
+                       add { AddEventHandler (PostMapRequestHandlerEvent, value); }
+                       remove { RemoveEventHandler (PostMapRequestHandlerEvent, value); }
+               }
+               
                public void AddOnPostMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostMapRequestHandlerAsync (bh, eh, null);
@@ -472,8 +603,14 @@ namespace System.Web {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
                        PostMapRequestHandler += new EventHandler (invoker.Invoke);
                }
+
+               static object PostAcquireRequestStateEvent = new object ();
+               public event EventHandler PostAcquireRequestState
+               {
+                       add { AddEventHandler (PostAcquireRequestStateEvent, value); }
+                       remove { RemoveEventHandler (PostAcquireRequestStateEvent, value); }
+               }
                
-               public event EventHandler PostAcquireRequestState;
                public void AddOnPostAcquireRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostAcquireRequestStateAsync (bh, eh, null);
@@ -484,8 +621,14 @@ namespace System.Web {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
                        PostAcquireRequestState += new EventHandler (invoker.Invoke);
                }
+
+               static object PostReleaseRequestStateEvent = new object ();
+               public event EventHandler PostReleaseRequestState
+               {
+                       add { AddEventHandler (PostReleaseRequestStateEvent, value); }
+                       remove { RemoveEventHandler (PostReleaseRequestStateEvent, value); }
+               }
                
-               public event EventHandler PostReleaseRequestState;
                public void AddOnPostReleaseRequestStateAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostReleaseRequestStateAsync (bh, eh, null);
@@ -497,7 +640,13 @@ namespace System.Web {
                        PostReleaseRequestState += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler PostUpdateRequestCache;
+               static object PostUpdateRequestCacheEvent = new object ();
+               public event EventHandler PostUpdateRequestCache
+               {
+                       add { AddEventHandler (PostUpdateRequestCacheEvent, value); }
+                       remove { RemoveEventHandler (PostUpdateRequestCacheEvent, value); }
+               }
+               
                public void AddOnPostUpdateRequestCacheAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostUpdateRequestCacheAsync (bh, eh, null);
@@ -573,8 +722,15 @@ namespace System.Web {
                }
 
                // Added in 2.0 SP1
-               // They are for use with the IIS7 integrated mode, but have been added for compatibility
-               public event EventHandler LogRequest;
+               // They are for use with the IIS7 integrated mode, but have been added for
+               // compatibility
+               static object LogRequestEvent = new object ();
+               public event EventHandler LogRequest
+               {
+                       add { AddEventHandler (LogRequestEvent, value); }
+                       remove { RemoveEventHandler (LogRequestEvent, value); }
+               }
+               
                public void AddOnLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnLogRequestAsync (bh, eh, null);
@@ -586,7 +742,13 @@ namespace System.Web {
                        LogRequest += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler MapRequestHandler;
+               static object MapRequestHandlerEvent = new object ();
+               public event EventHandler MapRequestHandler
+               {
+                       add { AddEventHandler (MapRequestHandlerEvent, value); }
+                       remove { RemoveEventHandler (MapRequestHandlerEvent, value); }
+               }
+               
                public void AddOnMapRequestHandlerAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnMapRequestHandlerAsync (bh, eh, null);
@@ -598,7 +760,13 @@ namespace System.Web {
                        MapRequestHandler += new EventHandler (invoker.Invoke);
                }
 
-               public event EventHandler PostLogRequest;
+               static object PostLogRequestEvent = new object ();
+               public event EventHandler PostLogRequest
+               {
+                       add { AddEventHandler (PostLogRequestEvent, value); }
+                       remove { RemoveEventHandler (PostLogRequestEvent, value); }
+               }
+               
                public void AddOnPostLogRequestAsync (BeginEventHandler bh, EndEventHandler eh)
                {
                        AddOnPostLogRequestAsync (bh, eh, null);
@@ -609,10 +777,24 @@ namespace System.Web {
                        AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
                        PostLogRequest += new EventHandler (invoker.Invoke);
                }
-
-#endif
                
                internal event EventHandler DefaultAuthentication;
+
+               void AddEventHandler (object key, EventHandler handler)
+               {
+                       if (fullInitComplete)
+                               return;
+
+                       Events.AddHandler (key, handler);
+               }
+
+               void RemoveEventHandler (object key, EventHandler handler)
+               {
+                       if (fullInitComplete)
+                               return;
+
+                       Events.RemoveHandler (key, handler);
+               }
                
                //
                // Bypass all the event on the Http pipeline and go directly to EndRequest
@@ -626,33 +808,57 @@ namespace System.Web {
                        set { stop_processing = value; }
                }
 
-               public virtual void Dispose ()
+               internal void DisposeInternal ()
                {
-                       if (modcoll != null) {
-                               for (int i = modcoll.Count - 1; i >= 0; i--) {
-                                       modcoll.Get (i).Dispose ();
+                       Dispose ();
+                       lock (this_lock) {
+                               if (modcoll != null) {
+                                       for (int i = modcoll.Count - 1; i >= 0; i--) {
+                                               modcoll.Get (i).Dispose ();
+                                       }
+                                       modcoll = null;
                                }
-                               modcoll = null;
                        }
 
-                       if (Disposed != null)
-                               Disposed (this, EventArgs.Empty);
+                       EventHandler eh = nonApplicationEvents [disposedEvent] as EventHandler;
+                       if (eh != null)
+                               eh (this, EventArgs.Empty);
                        
                        done.Close ();
                        done = null;
                }
+               
+               public virtual void Dispose ()
+               {
+               }
 
+#if NET_4_0
+               public virtual string GetOutputCacheProviderName (HttpContext context)
+               {
+                       // LAMESPEC: doesn't throw ProviderException if context is null
+                       return OutputCache.DefaultProviderName;
+               }
+#endif
+               
                public virtual string GetVaryByCustomString (HttpContext context, string custom)
                {
                        if (custom == null) // Sigh
                                throw new NullReferenceException ();
 
-                       if (0 == String.Compare (custom, "browser", true, CultureInfo.InvariantCulture))
+                       if (0 == String.Compare (custom, "browser", true, Helpers.InvariantCulture))
                                return context.Request.Browser.Type;
 
                        return null;
                }
 
+               bool ShouldHandleException (Exception e)
+               {
+                       if (e is ParseException)
+                               return false;
+
+                       return true;
+               }
+               
                //
                // If we catch an error, queue this error
                //
@@ -660,14 +866,18 @@ namespace System.Web {
                {
                        bool first = context.Error == null;
                        context.AddError (e);
-                       if (first){
-                               if (Error != null){
+                       if (first && ShouldHandleException (e)) {
+                               EventHandler eh = nonApplicationEvents [errorEvent] as EventHandler;
+                               if (eh != null){
                                        try {
-                                               Error (this, EventArgs.Empty);
+                                               eh (this, EventArgs.Empty);
+                                               if (stop_processing)
+                                                       context.ClearError ();
                                        } catch (ThreadAbortException taex){
                                                context.ClearError ();
-                                               if (FlagEnd.Value == taex.ExceptionState)
-                                                       // This happens on Redirect() or End()
+                                               if (FlagEnd.Value == taex.ExceptionState || HttpRuntime.DomainUnloading)
+                                                       // This happens on Redirect(), End() and
+                                                       // when unloading the AppDomain
                                                        Thread.ResetAbort ();
                                                else
                                                        // This happens on Thread.Abort()
@@ -678,14 +888,13 @@ namespace System.Web {
                                }
                        }
                        stop_processing = true;
-#if NET_2_0
+
                        // we want to remove configuration from the cache in case of 
                        // invalid resource not exists to prevent DOS attack.
                        HttpException httpEx = e as HttpException;
                        if (httpEx != null && httpEx.GetHttpCode () == 404) {
                                removeConfigurationFromCache = true;
                        }
-#endif
                }
                
                //
@@ -694,26 +903,49 @@ namespace System.Web {
                internal void Tick ()
                {
                        try {
+#if TARGET_J2EE
+                               if (context.Error is UnifyRequestException) {
+                                       Exception ex = context.Error.InnerException;
+                                       context.ClearError ();
+                                       vmw.common.TypeUtils.Throw (ex);
+                               }
+                               try {
+#endif         
                                if (pipeline.MoveNext ()){
                                        if ((bool)pipeline.Current)
                                                PipelineDone ();
                                }
+#if TARGET_J2EE
+                               }
+                               catch (Exception ex) {
+                                       if (ex is ThreadAbortException && 
+                                               ((ThreadAbortException) ex).ExceptionState == FlagEnd.Value)
+                                               throw;
+                                       if (context.WorkerRequest is IHttpUnifyWorkerRequest) {
+                                               context.ClearError ();
+                                               context.AddError (new UnifyRequestException (ex));
+                                               return;
+                                       }
+                                       else
+                                               throw;
+                               }
+#endif
                        } catch (ThreadAbortException taex) {
                                object obj = taex.ExceptionState;
                                Thread.ResetAbort ();
-                               stop_processing = true;
                                if (obj is StepTimeout)
-                                       ProcessError (new HttpException ("The request timed out."));
+                                       ProcessError (HttpException.NewWithCode ("The request timed out.", WebEventCodes.RequestTransactionAbort));
                                else {
                                        context.ClearError ();
-                                       if (FlagEnd.Value != obj)
+                                       if (FlagEnd.Value != obj && !HttpRuntime.DomainUnloading)
                                                context.AddError (taex);
                                }
-
+                               
+                               stop_processing = true;
                                PipelineDone ();
                        } catch (Exception e) {
-                               stop_processing = true;
                                ProcessError (e);
+                               stop_processing = true;
                                PipelineDone ();
                        }
                }
@@ -745,10 +977,11 @@ namespace System.Web {
 
                void async_handler_complete_cb (IAsyncResult ar)
                {
-                       IHttpAsyncHandler async_handler = ((IHttpAsyncHandler) ar.AsyncState);
+                       IHttpAsyncHandler async_handler = ar != null ? ar.AsyncState as IHttpAsyncHandler : null;
 
                        try {
-                               async_handler.EndProcessRequest (ar);
+                               if (async_handler != null)
+                                       async_handler.EndProcessRequest (ar);
                        } catch (Exception e){
                                ProcessError (e);
                        }
@@ -831,7 +1064,7 @@ namespace System.Web {
                                        if (error is HttpException){
                                                response.StatusCode = ((HttpException)error).GetHttpCode ();
                                        } else {
-                                               error = new HttpException ("", error);
+                                               error = HttpException.NewWithCode (String.Empty, error, WebEventCodes.WebErrorOtherError);
                                                response.StatusCode = 500;
                                        }
                                        HttpException httpEx = (HttpException) error;
@@ -841,7 +1074,7 @@ namespace System.Web {
                                                response.Flush (true);
                                } else {
                                        if (!(error is HttpException))
-                                               error = new HttpException ("", error);
+                                               error = HttpException.NewWithCode (String.Empty, error, WebEventCodes.WebErrorOtherError);
                                        FinalErrorWrite (response, ((HttpException) error).GetHtmlErrorMessage ());
                                }
                        }
@@ -854,14 +1087,18 @@ namespace System.Web {
                void PipelineDone ()
                {
                        try {
-                               if (EndRequest != null)
-                                       EndRequest (this, EventArgs.Empty);
+                               EventHandler handler = Events [EndRequestEvent] as EventHandler;
+                               if (handler != null)
+                                       handler (this, EventArgs.Empty);
                        } catch (Exception e){
                                ProcessError (e);
                        }
 
                        try {
                                OutputPage ();
+                       } catch (ThreadAbortException taex) {
+                               ProcessError (taex);
+                               Thread.ResetAbort ();
                        } catch (Exception e) {
                                Console.WriteLine ("Internal error: OutputPage threw an exception " + e);
                        } finally {
@@ -871,9 +1108,8 @@ namespace System.Web {
                                        context.Handler = null;
                                        factory = null;
                                }
-#if NET_2_0
                                context.PopHandler ();
-#endif
+
                                // context = null; -> moved to PostDone
                                pipeline = null;
                                current_ai = null;
@@ -884,118 +1120,227 @@ namespace System.Web {
                                begin_iar.Complete ();
                        else
                                done.Set ();
+
+                       requests_total_counter.Increment ();
                }
-               
+
+               class Tim {
+                       string name;
+                       DateTime start;
+
+                       public Tim () {
+                       }
+
+                       public Tim (string name) {
+                               this.name = name;
+                       }
+
+                       public string Name {
+                               get { return name; }
+                               set { name = value; }
+                       }
+
+                       public void Start () {
+                               start = DateTime.UtcNow;
+                       }
+
+                       public void Stop () {
+                               Console.WriteLine ("{0}: {1}ms", name, (DateTime.UtcNow - start).TotalMilliseconds);
+                       }
+               }
+
+               Tim tim;
+               [Conditional ("PIPELINE_TIMER")]
+               void StartTimer (string name)
+               {
+                       if (tim == null)
+                               tim = new Tim ();
+                       tim.Name = name;
+                       tim.Start ();
+               }
+
+               [Conditional ("PIPELINE_TIMER")]
+               void StopTimer ()
+               {
+                       tim.Stop ();
+               }
+
                //
                // Events fired as described in `Http Runtime Support, HttpModules,
                // Handling Public Events'
                //
                IEnumerator Pipeline ()
                {
+                       Delegate eventHandler;
                        if (stop_processing)
                                yield return true;
 
-                       if (BeginRequest != null)
-                               foreach (bool stop in RunHooks (BeginRequest))
+#if NET_4_0
+                       if (HttpRequest.ValidateRequestNewMode) {
+                               char[] invalidChars = HttpRequest.RequestPathInvalidCharacters;
+                               HttpRequest req = context.Request;
+                               if (invalidChars != null && req != null) {
+                                       string path = req.PathNoValidation;
+                                       int idx = path != null ? path.IndexOfAny (invalidChars) : -1;
+                                       if (idx != -1)
+                                               throw HttpException.NewWithCode (
+                                                       String.Format ("A potentially dangerous Request.Path value was detected from the client ({0}).", path [idx]),
+                                                       WebEventCodes.RuntimeErrorValidationFailure
+                                               );
+                               }
+                       }
+#endif
+                       context.MapRequestHandlerDone = false;
+                       StartTimer ("BeginRequest");
+                       eventHandler = Events [BeginRequestEvent];
+                       if (eventHandler != null) {
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-
-                       if (AuthenticateRequest != null)
-                               foreach (bool stop in RunHooks (AuthenticateRequest))
+                       }
+                       StopTimer ();
+                       
+                       StartTimer ("AuthenticateRequest");
+                       eventHandler = Events [AuthenticateRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
+                       StopTimer ();
 
+                       StartTimer ("DefaultAuthentication");
                        if (DefaultAuthentication != null)
                                foreach (bool stop in RunHooks (DefaultAuthentication))
                                        yield return stop;
+                       StopTimer ();
 
-#if NET_2_0
-                       if (PostAuthenticateRequest != null)
-                               foreach (bool stop in RunHooks (PostAuthenticateRequest))
+                       StartTimer ("PostAuthenticateRequest");
+                       eventHandler = Events [PostAuthenticateRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-#endif
-                       if (AuthorizeRequest != null)
-                               foreach (bool stop in RunHooks (AuthorizeRequest))
+                       StopTimer ();
+
+                       StartTimer ("AuthorizeRequest");
+                       eventHandler = Events [AuthorizeRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-#if NET_2_0
-                       if (PostAuthorizeRequest != null)
-                               foreach (bool stop in RunHooks (PostAuthorizeRequest))
+                       StopTimer ();
+
+                       StartTimer ("PostAuthorizeRequest");
+                       eventHandler = Events [PostAuthorizeRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-#endif
+                       StopTimer ();
 
-                       if (ResolveRequestCache != null)
-                               foreach (bool stop in RunHooks (ResolveRequestCache))
+                       StartTimer ("ResolveRequestCache");
+                       eventHandler = Events [ResolveRequestCacheEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
+                       StopTimer ();
 
-#if NET_2_0
-                       if (PostResolveRequestCache != null)
-                               foreach (bool stop in RunHooks (PostResolveRequestCache))
+                       StartTimer ("PostResolveRequestCache");
+                       eventHandler = Events [PostResolveRequestCacheEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
+                       StopTimer ();
 
+                       StartTimer ("MapRequestHandler");
                        // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
-                       if (MapRequestHandler != null)
-                               foreach (bool stop in RunHooks (MapRequestHandler))
+                       eventHandler = Events [MapRequestHandlerEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-#endif
+                       StopTimer ();
+                       context.MapRequestHandlerDone = true;
                        
+                       StartTimer ("GetHandler");
                        // Obtain the handler for the request.
                        IHttpHandler handler = null;
                        try {
-                               handler = GetHandler (context, context.Request.FilePath);
+                               handler = GetHandler (context, context.Request.CurrentExecutionFilePath);
                                context.Handler = handler;
-#if NET_2_0
                                context.PushHandler (handler);
-#endif
                        } catch (FileNotFoundException fnf){
 #if TARGET_JVM
                                Console.WriteLine ("$$$$$$$$$$:Sys.Web Pipeline");
                                Console.WriteLine (fnf.ToString ());
 #endif
                                if (context.Request.IsLocal)
-                                       ProcessError (new HttpException (404, String.Format ("File not found {0}", fnf.FileName), fnf, context.Request.FilePath));
+                                       ProcessError (HttpException.NewWithCode (404,
+                                                                                String.Format ("File not found {0}", fnf.FileName),
+                                                                                fnf,
+                                                                                context.Request.FilePath,
+                                                                                WebEventCodes.RuntimeErrorRequestAbort));
                                else
-                                       ProcessError (new HttpException (404, "File not found: " + Path.GetFileName (fnf.FileName), context.Request.FilePath));
+                                       ProcessError (HttpException.NewWithCode (404,
+                                                                                "File not found: " + Path.GetFileName (fnf.FileName),
+                                                                                context.Request.FilePath,
+                                                                                WebEventCodes.RuntimeErrorRequestAbort));
                        } catch (DirectoryNotFoundException dnf){
                                if (!context.Request.IsLocal)
                                        dnf = null; // Do not "leak" real path information
-                               ProcessError (new HttpException (404, "Directory not found", dnf));
+                               ProcessError (HttpException.NewWithCode (404, "Directory not found", dnf, WebEventCodes.RuntimeErrorRequestAbort));
                        } catch (Exception e) {
                                ProcessError (e);
                        }
 
+                       StopTimer ();
                        if (stop_processing)
                                yield return true;
 
-#if NET_2_0
-                       if (PostMapRequestHandler != null)
-                               foreach (bool stop in RunHooks (PostMapRequestHandler))
+                       StartTimer ("PostMapRequestHandler");
+                       eventHandler = Events [PostMapRequestHandlerEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-                       
-#endif
-                       if (AcquireRequestState != null){
-                               foreach (bool stop in RunHooks (AcquireRequestState))
+                       StopTimer ();
+
+                       StartTimer ("AcquireRequestState");
+                       eventHandler = Events [AcquireRequestStateEvent];
+                       if (eventHandler != null){
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
                        }
-
-#if NET_2_0
-                       if (PostAcquireRequestState != null){
-                               foreach (bool stop in RunHooks (PostAcquireRequestState))
+                       StopTimer ();
+                       
+                       StartTimer ("PostAcquireRequestState");
+                       eventHandler = Events [PostAcquireRequestStateEvent];
+                       if (eventHandler != null){
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
                        }
-#endif
+                       StopTimer ();
                        
                        //
                        // From this point on, we need to ensure that we call
                        // ReleaseRequestState, so the code below jumps to
                        // `release:' to guarantee it rather than yielding.
                        //
-                       if (PreRequestHandlerExecute != null)
-                               foreach (bool stop in RunHooks (PreRequestHandlerExecute))
+                       StartTimer ("PreRequestHandlerExecute");
+                       eventHandler = Events [PreRequestHandlerExecuteEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        if (stop)
                                                goto release;
+                       StopTimer ();
+                       
                                
 #if TARGET_J2EE
                processHandler:
                        bool doProcessHandler = false;
 #endif
+                       
+                       IHttpHandler ctxHandler = context.Handler;
+                       if (ctxHandler != null && handler != ctxHandler) {
+                               context.PopHandler ();
+                               handler = ctxHandler;
+                               context.PushHandler (handler);
+                       }
+
+                       StartTimer ("ProcessRequest");
                        try {
                                context.BeginTimeoutPossible ();
                                if (handler != null){
@@ -1020,6 +1365,7 @@ namespace System.Web {
                                in_begin = false;
                                context.EndTimeoutPossible ();
                        }
+                       StopTimer ();
 #if TARGET_J2EE
                        if (doProcessHandler) {
                                yield return false;
@@ -1033,59 +1379,80 @@ namespace System.Web {
                        
                        // These are executed after the application has returned
                        
-                       if (PostRequestHandlerExecute != null)
-                               foreach (bool stop in RunHooks (PostRequestHandlerExecute))
+                       StartTimer ("PostRequestHandlerExecute");
+                       eventHandler = Events [PostRequestHandlerExecuteEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        if (stop)
                                                goto release;
+                       StopTimer ();
                        
                release:
-                       if (ReleaseRequestState != null){
-#pragma warning disable 168
-                               foreach (bool stop in RunHooks (ReleaseRequestState)){
+                       StartTimer ("ReleaseRequestState");
+                       eventHandler = Events [ReleaseRequestStateEvent];
+                       if (eventHandler != null){
+#pragma warning disable 219
+                               foreach (bool stop in RunHooks (eventHandler)) {
                                        //
                                        // Ignore the stop signal while release the state
                                        //
                                        
                                }
-#pragma warning restore 168
+#pragma warning restore 219
                        }
+                       StopTimer ();
                        
                        if (stop_processing)
                                yield return true;
 
-#if NET_2_0
-                       if (PostReleaseRequestState != null)
-                               foreach (bool stop in RunHooks (PostReleaseRequestState))
+                       StartTimer ("PostReleaseRequestState");
+                       eventHandler = Events [PostReleaseRequestStateEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-#endif
+                       StopTimer ();
 
+                       StartTimer ("Filter");
                        if (context.Error == null)
                                context.Response.DoFilter (true);
+                       StopTimer ();
 
-                       if (UpdateRequestCache != null)
-                               foreach (bool stop in RunHooks (UpdateRequestCache))
+                       StartTimer ("UpdateRequestCache");
+                       eventHandler = Events [UpdateRequestCacheEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
+                       StopTimer ();
 
-#if NET_2_0
-                       if (PostUpdateRequestCache != null)
-                               foreach (bool stop in RunHooks (PostUpdateRequestCache))
+                       StartTimer ("PostUpdateRequestCache");
+                       eventHandler = Events [PostUpdateRequestCacheEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
+                       StopTimer ();
 
-                       if (LogRequest != null)
-                               foreach (bool stop in RunHooks (LogRequest))
+                       StartTimer ("LogRequest");
+                       eventHandler = Events [LogRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
+                       StopTimer ();
 
-                       if (PostLogRequest != null)
-                               foreach (bool stop in RunHooks (PostLogRequest))
+                       StartTimer ("PostLogRequest");
+                       eventHandler = Events [PostLogRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
                                        yield return stop;
-#endif
+                       StopTimer ();
+
+                       StartTimer ("PipelineDone");
                        PipelineDone ();
+                       StopTimer ();
                }
 
 
                internal CultureInfo GetThreadCulture (HttpRequest request, CultureInfo culture, bool isAuto)
                {
-#if NET_2_0
                        if (!isAuto)
                                return culture;
                        CultureInfo ret = null;
@@ -1100,30 +1467,17 @@ namespace System.Web {
                                ret = culture;
                        
                        return ret;
-#else
-                       return culture;
-#endif
                }
 
 
                void PreStart ()
                {
-#if NET_2_0
                        GlobalizationSection cfg;
                        cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
                        app_culture = cfg.GetCulture ();
                        autoCulture = cfg.IsAutoCulture;
                        appui_culture = cfg.GetUICulture ();
                        autoUICulture = cfg.IsAutoUICulture;
-#else
-                       GlobalizationConfiguration cfg;
-                       cfg = GlobalizationConfiguration.GetInstance (null);
-                       if (cfg != null) {
-                               app_culture = cfg.Culture;
-                               appui_culture = cfg.UICulture;
-                       }
-#endif
-
 #if !TARGET_J2EE
                        context.StartTimeoutTimer ();
 #endif
@@ -1131,14 +1485,14 @@ namespace System.Web {
                        if (app_culture != null) {
                                prev_app_culture = th.CurrentCulture;
                                CultureInfo new_app_culture = GetThreadCulture (Request, app_culture, autoCulture);
-                               if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
+                               if (!new_app_culture.Equals (Helpers.InvariantCulture))
                                        th.CurrentCulture = new_app_culture;
                        }
 
                        if (appui_culture != null) {
                                prev_appui_culture = th.CurrentUICulture;
                                CultureInfo new_app_culture = GetThreadCulture (Request, appui_culture, autoUICulture);
-                               if (!new_app_culture.Equals (CultureInfo.InvariantCulture))
+                               if (!new_app_culture.Equals (Helpers.InvariantCulture))
                                        th.CurrentUICulture = new_app_culture;
                        }
 
@@ -1149,12 +1503,11 @@ namespace System.Web {
 
                void PostDone ()
                {
-#if NET_2_0
                        if (removeConfigurationFromCache) {
                                WebConfigurationManager.RemoveConfigurationFromCache (context);
                                removeConfigurationFromCache = false;
                        }
-#endif
+
                        Thread th = Thread.CurrentThread;
 #if !TARGET_JVM
                        if (Thread.CurrentPrincipal != prev_user)
@@ -1170,6 +1523,8 @@ namespace System.Web {
                                context = HttpContext.Current;
                        context.StopTimeoutTimer ();
 #endif
+                       context.Request.ReleaseResources ();
+                       context.Response.ReleaseResources ();
                        context = null;
                        session = null;
                        HttpContext.Current = null;
@@ -1177,13 +1532,18 @@ namespace System.Web {
 
                void Start (object x)
                {
+                       CultureInfo[] cultures = x as CultureInfo[];
+                       if (cultures != null && cultures.Length == 2) {
+                               Thread ct = Thread.CurrentThread;
+                               ct.CurrentCulture = cultures [0];
+                               ct.CurrentUICulture = cultures [1];
+                       }
+                       
                        try {
                                InitOnce (true);
                        } catch (Exception e) {
-#if NET_2_0
                                initialization_exception = e;
-#endif
-                               FinalErrorWrite (context.Response, new HttpException ("", e).GetHtmlErrorMessage ());
+                               FinalErrorWrite (context.Response, HttpException.NewWithCode (String.Empty, e, WebEventCodes.RuntimeErrorRequestAbort).GetHtmlErrorMessage ());
                                PipelineDone ();
                                return;
                        }
@@ -1215,7 +1575,7 @@ namespace System.Web {
                        cache.Clear ();
                }
                
-               internal object LocateHandler (string verb, string url)
+               object LocateHandler (HttpRequest req, string verb, string url)
                {
                        Hashtable cache = GetHandlerCache ();
                        string id = String.Concat (verb, url);
@@ -1223,30 +1583,36 @@ namespace System.Web {
 
                        if (ret != null)
                                return ret;
-                       
-#if NET_2_0
-                       HttpHandlersSection     httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
-                       ret = httpHandlersSection.LocateHandler (verb, url);
-#else
-                       HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
-                       ret = factory_config.LocateHandler (verb, url);
-#endif
 
-                       cache [id] = ret;
+                       bool allowCache;
+                       HttpHandlersSection httpHandlersSection = WebConfigurationManager.GetSection ("system.web/httpHandlers", req.Path, req.Context) as HttpHandlersSection;
+                       ret = httpHandlersSection.LocateHandler (verb, url, out allowCache);
+
+                       IHttpHandler handler = ret as IHttpHandler;
+                       if (allowCache && handler != null && handler.IsReusable)
+                               cache [id] = ret;
+                       
                        return ret;
                }
+
+               internal IHttpHandler GetHandler (HttpContext context, string url)
+               {
+                       return GetHandler (context, url, false);
+               }
                
                // Used by HttpServerUtility.Execute
-               internal IHttpHandler GetHandler (HttpContext context,string url)
+               internal IHttpHandler GetHandler (HttpContext context, string url, bool ignoreContextHandler)
                {
+                       if (!ignoreContextHandler && context.Handler != null)
+                               return context.Handler;
+                       
                        HttpRequest request = context.Request;
                        string verb = request.RequestType;
                        
                        IHttpHandler handler = null;
-                       object o = LocateHandler (verb, url);
+                       object o = LocateHandler (request, verb, url);
                        
                        factory = o as IHttpHandlerFactory;
-                       
                        if (factory == null) {
                                handler = (IHttpHandler) o;
                        } else {
@@ -1288,6 +1654,10 @@ namespace System.Web {
                        
                        begin_iar = new AsyncRequestState (done, cb, extraData);
 
+                       CultureInfo[] cultures = new CultureInfo [2];
+                       cultures [0] = Thread.CurrentThread.CurrentCulture;
+                       cultures [1] = Thread.CurrentThread.CurrentUICulture;
+                       
 #if TARGET_JVM
                        if (true)
 #else
@@ -1295,7 +1665,7 @@ namespace System.Web {
 #endif
                                Start (null);
                        else
-                               ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
+                               ThreadPool.QueueUserWorkItem (new WaitCallback (Start), cultures);
                        
                        return begin_iar;
                }
@@ -1342,15 +1712,7 @@ namespace System.Web {
                        if (!context.IsCustomErrorEnabledUnsafe)
                                return false;
                        
-#if NET_2_0
-                       CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");
-#else
-                       CustomErrorsConfig config = null;
-                       try {
-                               config = (CustomErrorsConfig) context.GetConfig ("system.web/customErrors");
-                       } catch { }
-#endif
-                       
+                       CustomErrorsSection config = (CustomErrorsSection)WebConfigurationManager.GetSection ("system.web/customErrors");                       
                        if (config == null) {
                                if (context.ErrorPage != null)
                                        return RedirectErrorPage (context.ErrorPage);
@@ -1358,12 +1720,8 @@ namespace System.Web {
                                return false;
                        }
                        
-#if NET_2_0
                        CustomError err = config.Errors [context.Response.StatusCode.ToString()];
                        string redirect = err == null ? null : err.Redirect;
-#else
-                       string redirect =  config [context.Response.StatusCode];
-#endif
                        if (redirect == null) {
                                redirect = context.ErrorPage;
                                if (redirect == null)
@@ -1376,34 +1734,29 @@ namespace System.Web {
                        return RedirectErrorPage (redirect);
                        }
                        catch (Exception ex) {
-                               httpEx = new HttpException (500, "", ex);
+                               httpEx = HttpException.NewWithCode (500, String.Empty, ex, WebEventCodes.WebErrorOtherError);
                                return false;
                        }
                }
-#endregion
-               internal static bool IsRunningOnWindows {
-                        get { return _runningOnWindows; }
-                }
-               
-               internal static IEnumerable BinDirectories
+#endregion             
+               internal static string BinDirectory
                {
                        get {
-                               AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
-                               string baseDir = setup.ApplicationBase;
-                               string bindir;
-
-                               if (Environment.GetEnvironmentVariable ("MONO_IOMAP") != null || IsRunningOnWindows) {
-                                       bindir = Path.Combine (baseDir, "bin");
-                                       if (Directory.Exists (bindir))
-                                               yield return bindir;
-                               } else {
+                               if (binDirectory == null) {
+                                       AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
+                                       string baseDir = setup.ApplicationBase;
+                                       string bindir;
+                                       
                                        foreach (string dir in BinDirs) {
                                                bindir = Path.Combine (baseDir, dir);
                                                if (!Directory.Exists (bindir))
                                                        continue;
-                                               yield return bindir;
+                                               binDirectory = bindir;
+                                               break;
                                        }
                                }
+
+                               return binDirectory;
                        }
                }
 
@@ -1413,16 +1766,17 @@ namespace System.Web {
                                ArrayList binDlls = null;
                                string[] dlls;
                                
-                               foreach (string bindir in BinDirectories) {
-                                       if (binDlls == null)
-                                               binDlls = new ArrayList ();
+                               string bindir = BinDirectory;
+                               if (bindir != null) {
+                                       binDlls = new ArrayList ();
                                        dlls = Directory.GetFiles (bindir, "*.dll");
                                        binDlls.AddRange (dlls);
                                }
 
                                if (binDlls == null)
                                        return new string[] {};
-                               return (string[])binDlls.ToArray (typeof (string));
+                               
+                               return (string[]) binDlls.ToArray (typeof (string));
                        }
                }
                                        
@@ -1445,7 +1799,6 @@ namespace System.Web {
                                        return type;
                        }
 
-#if NET_2_0
                        IList tla = System.Web.Compilation.BuildManager.TopLevelAssemblies;
                        if (tla != null && tla.Count > 0) {
                                foreach (Assembly asm in tla) {
@@ -1456,24 +1809,54 @@ namespace System.Web {
                                                return type;
                                }
                        }
-#endif
 
-                       type = LoadTypeFromBin (typeName);
+                       Exception loadException = null;
+                       try {
+                               type = null;
+                               type = LoadTypeFromBin (typeName);
+                       } catch (Exception ex) {
+                               loadException = ex;
+                       }
+                       
                        if (type != null)
                                return type;
 #endif
                        if (throwOnMissing)
-                               throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName));
+                               throw new TypeLoadException (String.Format ("Type '{0}' cannot be found", typeName), loadException);
                        
                        return null;
                }
 
+               internal static Type LoadType <TBaseType> (string typeName, bool throwOnMissing)
+               {
+                       Type ret = LoadType (typeName, throwOnMissing);
+
+                       if (typeof (TBaseType).IsAssignableFrom (ret))
+                               return ret;
+
+                       if (throwOnMissing)
+                               throw new TypeLoadException (String.Format ("Type '{0}' found but it doesn't derive from base type '{1}'.", typeName, typeof (TBaseType)));
+
+                       return null;
+               }
+               
                internal static Type LoadTypeFromBin (string typeName)
                {
                        Type type = null;
                        
                        foreach (string s in BinDirectoryAssemblies) {
-                               Assembly binA = Assembly.LoadFrom (s);
+                               Assembly binA = null;
+                               
+                               try {
+                                       binA = Assembly.LoadFrom (s);
+                               } catch (FileLoadException) {
+                                       // ignore
+                                       continue;
+                               } catch (BadImageFormatException) {
+                                       // ignore
+                                       continue;
+                               }
+                               
                                type = binA.GetType (typeName, false);
                                if (type == null)
                                        continue;