2010-05-05 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpApplication.cs
index 81dc754eb3504ba7e90cf114ea37fb2ee8756283..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,30 +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 vmw.@internal.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;
@@ -117,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
                //
@@ -131,16 +149,18 @@ 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;
                CultureInfo prev_app_culture;
                CultureInfo prev_appui_culture;
                IPrincipal prev_user;
-#if NET_2_0
+
+               static string binDirectory;
+               
 #if TARGET_J2EE
                const string initialization_exception_key = "System.Web.HttpApplication.initialization_exception";
                static Exception initialization_exception {
@@ -151,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
@@ -161,6 +181,16 @@ namespace System.Web {
                bool must_yield;
                bool in_begin;
 
+               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);
@@ -171,41 +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;
                                }
-
-#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
                        }
                }
 
+               internal bool InApplicationStart {
+                       get { return in_application_start; }
+                       set { in_application_start = value; }
+               }
+               
                internal string AssemblyLocation {
                        get {
                                if (assemblyLocation == null)
@@ -214,11 +230,9 @@ namespace System.Web {
                        }
                }
 
-#if NET_2_0
                internal static Exception InitializationException {
                        get { return initialization_exception; }
                }
-#endif
 
                [Browsable (false)]
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
@@ -250,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;
                        }
@@ -262,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;
                        }
@@ -276,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;
                        }
@@ -309,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)]
@@ -343,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);
@@ -442,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);
@@ -454,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);
@@ -467,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);
@@ -478,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);
@@ -490,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);
@@ -503,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);
@@ -577,9 +720,81 @@ namespace System.Web {
                        AsyncInvoker invoker = new AsyncInvoker (bh, eh, data);
                        UpdateRequestCache += new EventHandler (invoker.Invoke);
                }
-#endif
+
+               // Added in 2.0 SP1
+               // 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);
+               }
+               
+               public void AddOnLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
+               {
+                       AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
+                       LogRequest += new EventHandler (invoker.Invoke);
+               }
+
+               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);
+               }
+
+               public void AddOnMapRequestHandlerAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
+               {
+                       AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
+                       MapRequestHandler += new EventHandler (invoker.Invoke);
+               }
+
+               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);
+               }
+
+               public void AddOnPostLogRequestAsync (BeginEventHandler beginHandler, EndEventHandler endHandler, object state)
+               {
+                       AsyncInvoker invoker = new AsyncInvoker (beginHandler, endHandler, state);
+                       PostLogRequest += new EventHandler (invoker.Invoke);
+               }
                
                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
@@ -593,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
                //
@@ -627,49 +866,87 @@ 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);
-                                       } catch (ThreadAbortException){
-                                               // This happens on Redirect() or End()
-                                               Thread.ResetAbort ();
+                                               eh (this, EventArgs.Empty);
+                                               if (stop_processing)
+                                                       context.ClearError ();
+                                       } catch (ThreadAbortException taex){
+                                               context.ClearError ();
+                                               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()
+                                                       context.AddError (taex);
                                        } catch (Exception ee){
                                                context.AddError (ee);
                                        }
                                }
                        }
                        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
                }
                
                //
                // Ticks the clock: next step on the pipeline.
                //
-               void Tick ()
+               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."));
-                               else
-                                       PipelineDone ();
+                                       ProcessError (HttpException.NewWithCode ("The request timed out.", WebEventCodes.RequestTransactionAbort));
+                               else {
+                                       context.ClearError ();
+                                       if (FlagEnd.Value != obj && !HttpRuntime.DomainUnloading)
+                                               context.AddError (taex);
+                               }
+                               
+                               stop_processing = true;
+                               PipelineDone ();
                        } catch (Exception e) {
-                               Console.WriteLine ("Tick caught an exception that has not been propagated:\n" + e);
+                               ProcessError (e);
+                               stop_processing = true;
+                               PipelineDone ();
                        }
                }
 
@@ -700,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);
                        }
@@ -729,14 +1007,6 @@ namespace System.Web {
                                                in_begin = true;
                                                context.BeginTimeoutPossible ();
                                                current_ai.begin (this, EventArgs.Empty, async_callback_completed_cb, current_ai.data);
-                                       } catch (ThreadAbortException taex){
-                                               object obj = taex.ExceptionState;
-                                               Thread.ResetAbort ();
-                                               stop_processing = true;
-                                               if (obj is StepTimeout)
-                                                       ProcessError (new HttpException ("The request timed out."));
-                                       } catch (Exception e){
-                                               ProcessError (e);
                                        } finally {
                                                in_begin = false;
                                                context.EndTimeoutPossible ();
@@ -754,14 +1024,6 @@ namespace System.Web {
                                        try {
                                                context.BeginTimeoutPossible ();
                                                d (this, EventArgs.Empty);
-                                       } catch (ThreadAbortException taex){
-                                               object obj = taex.ExceptionState;
-                                               Thread.ResetAbort ();
-                                               stop_processing = true;
-                                               if (obj is StepTimeout)
-                                                       ProcessError (new HttpException ("The request timed out."));
-                                       } catch (Exception e){
-                                               ProcessError (e);
                                        } finally {
                                                context.EndTimeoutPossible ();
                                        }
@@ -795,17 +1057,6 @@ namespace System.Web {
                        if (error != null){
                                HttpResponse response = context.Response;
 
-#if TARGET_J2EE
-                               IPortletActionRequest actionRequest = context.ServletRequest as IPortletActionRequest;
-                               IPortletActionResponse actionResponse = context.ServletResponse as IPortletActionResponse;
-                               if (actionRequest != null && actionResponse != null && actionRequest.processActionOnly ()) {
-                                       string exception = "Exception of type " + context.Error.GetType () + 
-                                               " during processAction: " + context.Error.Message + Console.Out.NewLine + 
-                                               context.Error.StackTrace;
-                                       actionResponse.setRenderParameter ("vmw.action.exception", exception);
-                                       return;
-                               }
-#endif
                                if (!response.HeadersSent){
                                        response.ClearHeaders ();
                                        response.ClearContent ();
@@ -813,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;
@@ -823,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 ());
                                }
                        }
@@ -836,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 {
@@ -853,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;
@@ -866,105 +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;
-#endif
+                       StopTimer ();
 
+                       StartTimer ("MapRequestHandler");
+                       // As per http://msdn2.microsoft.com/en-us/library/bb470252(VS.90).aspx
+                       eventHandler = Events [MapRequestHandlerEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
+                                       yield return stop;
+                       StopTimer ();
+                       context.MapRequestHandlerDone = true;
+                       
+                       StartTimer ("GetHandler");
                        // Obtain the handler for the request.
                        IHttpHandler handler = null;
                        try {
-                               handler = GetHandler (context);
+                               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));
+                                       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)));
+                                       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){
@@ -977,20 +1353,25 @@ namespace System.Web {
                                        } else {
                                                must_yield = false;
                                                handler.ProcessRequest (context);
+#if TARGET_J2EE
+                                               IHttpExtendedHandler extHandler=handler as IHttpExtendedHandler;
+                                               doProcessHandler = extHandler != null && !extHandler.IsCompleted;
+#endif
                                        }
                                }
-                       } catch (ThreadAbortException taex){
-                               object obj = taex.ExceptionState;
-                               Thread.ResetAbort ();
-                               stop_processing = true;
-                               if (obj is StepTimeout)
-                                       ProcessError (new HttpException ("The request timed out."));
-                       } catch (Exception e){
-                               ProcessError (e);
+                               if (context.Error != null)
+                                       throw new TargetInvocationException(context.Error);
                        } finally {
                                in_begin = false;
                                context.EndTimeoutPossible ();
                        }
+                       StopTimer ();
+#if TARGET_J2EE
+                       if (doProcessHandler) {
+                               yield return false;
+                               goto processHandler;
+                       }
+#endif
                        if (must_yield)
                                yield return stop_processing;
                        else if (stop_processing)
@@ -998,51 +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;
-#endif
+                       StopTimer ();
+
+                       StartTimer ("LogRequest");
+                       eventHandler = Events [LogRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
+                                       yield return stop;
+                       StopTimer ();
+
+                       StartTimer ("PostLogRequest");
+                       eventHandler = Events [PostLogRequestEvent];
+                       if (eventHandler != null)
+                               foreach (bool stop in RunHooks (eventHandler))
+                                       yield return stop;
+                       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;
@@ -1057,29 +1467,32 @@ namespace System.Web {
                                ret = culture;
                        
                        return ret;
-#else
-                       return culture;
-#endif
                }
 
 
                void PreStart ()
                {
+                       GlobalizationSection cfg;
+                       cfg = (GlobalizationSection) WebConfigurationManager.GetSection ("system.web/globalization");
+                       app_culture = cfg.GetCulture ();
+                       autoCulture = cfg.IsAutoCulture;
+                       appui_culture = cfg.GetUICulture ();
+                       autoUICulture = cfg.IsAutoUICulture;
 #if !TARGET_J2EE
-                       HttpRuntime.TimeoutManager.Add (context);
+                       context.StartTimeoutTimer ();
 #endif
                        Thread th = Thread.CurrentThread;
                        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;
                        }
 
@@ -1090,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)
@@ -1109,8 +1521,10 @@ namespace System.Web {
 #if !TARGET_J2EE
                        if (context == null)
                                context = HttpContext.Current;
-                       HttpRuntime.TimeoutManager.Remove (context);
+                       context.StopTimeoutTimer ();
 #endif
+                       context.Request.ReleaseResources ();
+                       context.Response.ReleaseResources ();
                        context = null;
                        session = null;
                        HttpContext.Current = null;
@@ -1118,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;
                        }
@@ -1134,29 +1553,70 @@ namespace System.Web {
                        pipeline = Pipeline ();
                        Tick ();
                }
-       
+
+               const string HANDLER_CACHE = "@@HttpHandlerCache@@";
+
+               internal static Hashtable GetHandlerCache ()
+               {
+                       Cache cache = HttpRuntime.InternalCache;
+                       Hashtable ret = cache [HANDLER_CACHE] as Hashtable;
+
+                       if (ret == null) {
+                               ret = new Hashtable ();
+                               cache.Insert (HANDLER_CACHE, ret);
+                       }
+
+                       return ret;
+               }
+               
+               internal static void ClearHandlerCache ()
+               {
+                       Hashtable cache = GetHandlerCache ();
+                       cache.Clear ();
+               }
+               
+               object LocateHandler (HttpRequest req, string verb, string url)
+               {
+                       Hashtable cache = GetHandlerCache ();
+                       string id = String.Concat (verb, url);
+                       object ret = cache [id];
+
+                       if (ret != null)
+                               return 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)
+               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;
-                       string url = request.FilePath;
                        
                        IHttpHandler handler = null;
-#if NET_2_0
-                       HttpHandlersSection     httpHandlersSection = (HttpHandlersSection) WebConfigurationManager.GetSection ("system.web/httpHandlers");
-                       object o = httpHandlersSection.LocateHandler (verb, url);
-#else
-                       HandlerFactoryConfiguration factory_config = (HandlerFactoryConfiguration) HttpContext.GetAppConfig ("system.web/httpHandlers");
-                       object o = factory_config.LocateHandler (verb, url);
-#endif
-
-                       factory = o as IHttpHandlerFactory;
+                       object o = LocateHandler (request, verb, url);
                        
+                       factory = o as IHttpHandlerFactory;
                        if (factory == null) {
                                handler = (IHttpHandler) o;
                        } else {
-                               handler = factory.GetHandler (context, verb, url, request.PhysicalPath);
+                               handler = factory.GetHandler (context, verb, url, request.MapPath (url));
                        }
 
                        return handler;
@@ -1194,18 +1654,10 @@ namespace System.Web {
                        
                        begin_iar = new AsyncRequestState (done, cb, extraData);
 
-#if TARGET_J2EE
-                       IPortletRenderRequest renderRequest = context.ServletRequest as IPortletRenderRequest;
-                       if (renderRequest != null) {
-                               string actionException = context.ServletRequest.getParameter ("vmw.action.exception");
-                               if (actionException != null && actionException.Length > 0) {
-                                       FinalErrorWrite (context.Response, actionException.Replace("\n", "<br>"));
-                                       begin_iar.Complete ();
-                                       return begin_iar;
-                               }
-                       }
-#endif
-
+                       CultureInfo[] cultures = new CultureInfo [2];
+                       cultures [0] = Thread.CurrentThread.CurrentCulture;
+                       cultures [1] = Thread.CurrentThread.CurrentUICulture;
+                       
 #if TARGET_JVM
                        if (true)
 #else
@@ -1213,13 +1665,17 @@ namespace System.Web {
 #endif
                                Start (null);
                        else
-                               ThreadPool.QueueUserWorkItem (new WaitCallback (Start), null);
+                               ThreadPool.QueueUserWorkItem (new WaitCallback (Start), cultures);
                        
                        return begin_iar;
                }
 
                void IHttpAsyncHandler.EndProcessRequest (IAsyncResult result)
                {
+#if TARGET_J2EE
+                       if (result == null)
+                               result = begin_iar;
+#endif
                        if (!result.IsCompleted)
                                result.AsyncWaitHandle.WaitOne ();
                        begin_iar = null;
@@ -1256,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);
@@ -1272,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)
@@ -1290,52 +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 IEnumerable PrivateBinPath
-               {
-                       get {
-                               AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
-                               string baseDir = setup.ApplicationBase;
-                               
-                               string pbp = setup.PrivateBinPath;
-                               if (pbp == null || pbp.Length == 0)
-                                       yield break;
-                               foreach (string d in pbp.Split (Path.PathSeparator))
-                                       yield return Path.Combine (baseDir, d);
-                       }
-               }
-
-               internal static bool IsRunningOnWindows {
-                        get {
-                               PlatformID pid = Environment.OSVersion.Platform;        
-                               return ((int) pid != 128 && (int) pid != 4);
-                       }
-                }
-               
-               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;
                        }
                }
 
@@ -1345,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));
                        }
                }
                                        
@@ -1369,6 +1791,7 @@ namespace System.Web {
                        if (type != null)
                                return type;
 
+#if !TARGET_JVM
                        Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
                        foreach (Assembly ass in assemblies) {
                                type = ass.GetType (typeName, false);
@@ -1376,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) {
@@ -1387,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;
@@ -1504,4 +1956,3 @@ namespace System.Web {
        }
 #endregion
 }
-