2010-04-21 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web / HttpContext.cs
index 916aa0fb280daaf759a69d68a3e60881ab942863..d183afa0f4d31b816f5d2605417568a5e7fa9617 100644 (file)
@@ -1,13 +1,14 @@
 //
-// System.Web.HttpContext
+// System.Web.HttpContext.cs 
 //
-// Authors:
-//     Patrik Torstensson (Patrik.Torstensson@labs2.com)
-//     Gonzalo Paniagua Javier (gonzalo@ximian.com)
-//
-// (c) 2003, 2004 Novell, Inc. (http://www.novell.com)
+// Author:
+//     Miguel de Icaza (miguel@novell.com)
+//     Gonzalo Paniagua Javier (gonzalo@novell.com)
+//      Marek Habersack <mhabersack@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
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.Collections;
 using System.Configuration;
+using System.Globalization;
+using System.Runtime.Remoting.Messaging;
+using System.Security.Permissions;
 using System.Security.Principal;
+using System.Threading;
 using System.Web.Caching;
 using System.Web.Configuration;
-using System.Web.Util;
 using System.Web.SessionState;
-using System.Threading;
-using System.Runtime.Remoting.Messaging;
+using System.Web.UI;
+using System.Web.Util;
+using System.Reflection;
+using System.Collections.Generic;
+using System.IO;
+using System.Resources;
+using System.Web.Compilation;
+using System.Web.Profile;
+using CustomErrorMode = System.Web.Configuration.CustomErrorsMode;
 
 namespace System.Web
 {
-       public sealed class HttpContext : IServiceProvider
+       // CAS - no InheritanceDemand here as the class is sealed
+       [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+       public sealed partial class HttpContext : IServiceProvider
        {
-               private ArrayList _arrExceptions;
-
-               private HttpResponse    _oResponse;
-               private HttpRequest _oRequest;
-               private HttpServerUtility _Server;
-               private HttpApplication _oApplication;
-               private HttpSessionState _oSession;
-               private HttpWorkerRequest _oWorkerRequest;
-               private TraceContext _oTrace;
-               private IHttpHandler _Handler;
-               private IHttpAsyncHandler _AsyncHandler;
-
-               private bool _skipauth;
-               private Hashtable               _oItems;
-               private DateTime                _oTimestamp;
-               int timeoutPossible;
-               long timeoutBegin;
-               object configTimeout;
-               string errorPage;
+               internal HttpWorkerRequest WorkerRequest;
+               HttpApplication app_instance;
+               HttpRequest request;
+               HttpResponse response;
+               HttpSessionState session_state;
+               HttpServerUtility server;
+               TraceContext trace_context;
+               IHttpHandler handler;
+               string error_page;
+               bool skip_authorization = false;
                IPrincipal user;
+               object errors;
+               Hashtable items;
+               object config_timeout;
+               int timeout_possible;
+               DateTime time_stamp = DateTime.UtcNow;
+               Timer timer;
+               Thread thread;
+               bool _isProcessingInclude;
                
-#if NET_2_0
-               private System.Web.UI.Page lastPage;
-#endif
+               [ThreadStatic]
+               static ResourceProviderFactory provider_factory;
 
-               public HttpContext (HttpRequest Request, HttpResponse Response)
-               {
-                       Context = this;
+               [ThreadStatic]
+               static DefaultResourceProviderFactory default_provider_factory;
+               
+               [ThreadStatic]
+               static Dictionary <string, IResourceProvider> resource_providers;
+               
+#if TARGET_JVM
+               const string app_global_res_key = "HttpContext.app_global_res_key";
+               internal static Assembly AppGlobalResourcesAssembly {
+                       get { return (Assembly) AppDomain.CurrentDomain.GetData (app_global_res_key); }
+                       set { AppDomain.CurrentDomain.SetData (app_global_res_key, value); }
+               }
+#else
+               internal static Assembly AppGlobalResourcesAssembly;
+#endif
+               ProfileBase profile = null;
+               LinkedList<IHttpHandler> handlers;
 
-                       _arrExceptions = null;
-                       _oItems = null;
-                       _oTimestamp = DateTime.Now;
-                       _oRequest = Request;
-                       _oResponse = Response;
-                       _oTrace = new TraceContext (this);
+               static DefaultResourceProviderFactory DefaultProviderFactory {
+                       get {
+                               if (default_provider_factory == null)
+                                       default_provider_factory = new DefaultResourceProviderFactory ();
+                               return default_provider_factory;
+                       }
                }
-
-               public HttpContext (HttpWorkerRequest WorkerRequest)
+               
+               public HttpContext (HttpWorkerRequest wr)
                {
-                       Context = this;
-
-                       _arrExceptions = null;
-                       _oItems = null;
-                       _oTimestamp = DateTime.Now;
-                       _oRequest = new HttpRequest (WorkerRequest, this);
-                       _oResponse = new HttpResponse (WorkerRequest, this);
-                       _oWorkerRequest = WorkerRequest;
-                       _oTrace = new TraceContext (this);
+                       WorkerRequest = wr;
+                       request = new HttpRequest (WorkerRequest, this);
+                       response = new HttpResponse (WorkerRequest, this);
+#if NET_4_0
+                       SessionStateBehavior = SessionStateBehavior.Default;
+#endif
                }
 
-               internal HttpWorkerRequest WorkerRequest
+               public HttpContext (HttpRequest request, HttpResponse response)
                {
-                       get {
-                               return _oWorkerRequest;
-                       }
+                       this.request = request;
+                       this.response = response;
+#if NET_4_0
+                       SessionStateBehavior = SessionStateBehavior.Default;
+#endif
                }
 
-               internal static HttpContext Context
-               {
-                       get {
-                               return (HttpContext) CallContext.GetData ("Context");
-                       }
-
-                       set {
-                               CallContext.SetData ("Context", value);
-                       }
+               internal bool IsProcessingInclude {
+                       get { return _isProcessingInclude; }
+                       set { _isProcessingInclude = value; }
                }
 
-               public Exception [] AllErrors
-               {
+               public Exception [] AllErrors {
                        get {
-                               if (_arrExceptions == null || _arrExceptions.Count == 0)
+                               if (errors == null)
                                        return null;
 
-                               return (Exception []) _arrExceptions.ToArray (typeof (Exception));
+                               if (errors is Exception){
+                                       Exception [] all = new Exception [1];
+                                       all [0] = (Exception) errors;
+                                       return all;
+                               } 
+                               return (Exception []) (((ArrayList) errors).ToArray (typeof (Exception)));
                        }
                }
 
-               public HttpApplicationState Application
-               {
+               public HttpApplicationState Application {
                        get {
                                return HttpApplicationFactory.ApplicationState;
                        }
                }
 
-               public HttpApplication ApplicationInstance
-               {
+               public HttpApplication ApplicationInstance {
                        get {
-                               return _oApplication;
+                               return app_instance;
                        }
+
                        set {
-                               _oApplication = value;
+                               app_instance = value;
                        }
+                             
                }
 
-               public Cache Cache
-               {
+               public Cache Cache {
                        get {
                                return HttpRuntime.Cache;
                        }
                }
 
-               public static HttpContext Current {
-                       get { return Context; }
-#if NET_1_1
-                       set { Context = value; }
-#endif
-               }
-
-               public Exception Error
-               {
+               internal Cache InternalCache {
                        get {
-                               if (_arrExceptions == null || _arrExceptions.Count == 0)
-                                       return null;
-
-                               return (Exception) _arrExceptions [0];
+                               return HttpRuntime.InternalCache;
                        }
                }
-
-               public IHttpHandler Handler
-               {
-                       get {    
-                               return _Handler;
+               
+               //
+               // The "Current" property is set just after we have constructed it with 
+               // the 'HttpContext (HttpWorkerRequest)' constructor.
+               //
+#if !TARGET_JVM // No remoting CallContext support in Grasshopper
+               public static HttpContext Current {
+                       get {
+                               return (HttpContext) CallContext.GetData ("c");
                        }
 
                        set {
-                               _Handler = value;
+                               CallContext.SetData ("c", value);
                        }
                }
+#endif
 
-               internal IHttpAsyncHandler AsyncHandler
-               {
-                       get {    
-                               return _AsyncHandler;
+               public Exception Error {
+                       get {
+                               if (errors == null || (errors is Exception))
+                                       return (Exception) errors;
+                               return (Exception) (((ArrayList) errors) [0]);
+                       }
+               }
+
+               public IHttpHandler Handler {
+                       get {
+                               return handler;
                        }
 
                        set {
-                               _AsyncHandler = value;
+                               handler = value;
                        }
                }
 
                public bool IsCustomErrorEnabled {
                        get {
-                               CustomErrorsConfig cfg;
                                try {
-                                       cfg = (CustomErrorsConfig) GetConfig ("system.web/customErrors");
-                               } catch (Exception) {
-                                       return false;
+                                       return IsCustomErrorEnabledUnsafe;
                                }
-                               
-                               if (cfg == null)
+                               catch {
                                        return false;
+                               }
+                       }
+               }
 
-                               CustomErrorMode mode = cfg.Mode;
-                               if (mode == CustomErrorMode.On)
+               internal bool IsCustomErrorEnabledUnsafe {
+                       get {
+                               CustomErrorsSection cfg = (CustomErrorsSection) WebConfigurationManager.GetSection ("system.web/customErrors");
+                               if (cfg.Mode == CustomErrorMode.On)
                                        return true;
 
-                               return (mode == CustomErrorMode.RemoteOnly &&
-                                       _oRequest.ServerVariables ["LOCAL_ADDR"] == _oRequest.UserHostAddress);
+                               return (cfg.Mode == CustomErrorMode.RemoteOnly) && !Request.IsLocal;
                        }
                }
-
-               public bool IsDebuggingEnabled
-               {
+#if !TARGET_JVM
+               public bool IsDebuggingEnabled {
+                       get { return RuntimeHelpers.DebuggingEnabled; }
+               }
+#endif
+               public IDictionary Items {
                        get {
-                               return CompilationConfiguration.GetInstance (this).Debug;
+                               if (items == null)
+                                       items = new Hashtable ();
+                               return items;
                        }
                }
 
-               public IDictionary Items
-               {
+               public HttpRequest Request {
                        get {
-                               if (_oItems == null)
-                                       _oItems = new Hashtable ();
+                               return request;
+                       }
+               }
 
-                               return _oItems;
+               public HttpResponse Response {
+                       get {
+                               return response;
                        }
                }
 
-               public HttpRequest Request
-               {
+               public HttpServerUtility Server {
                        get {
-                               return _oRequest;
+                               if (server == null)
+                                       server = new HttpServerUtility (this);
+                               return server;
                        }
                }
 
-               public HttpResponse Response
-               {
+               public HttpSessionState Session {
                        get {
-                               return _oResponse;
+                               return session_state;
                        }
                }
 
-               public HttpServerUtility Server
-               {
+               public bool SkipAuthorization {
                        get {
-                               if (null == _Server)
-                                       _Server = new HttpServerUtility (this);
+                               return skip_authorization;
+                       }
 
-                               return _Server; 
+                       [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
+                       set {
+                               skip_authorization = value;
                        }
                }
 
-               public HttpSessionState Session
-               {
+               public DateTime Timestamp {
                        get {
-                               return (HttpSessionState) _oSession;
+                               return time_stamp.ToLocalTime ();
+                       }
+               }
+               
+               public TraceContext Trace {
+                       get {
+                               if (trace_context == null)
+                                       trace_context = new TraceContext (this);
+                               return trace_context;
                        }
                }
 
-               public bool SkipAuthorization
-               {
+               public IPrincipal User {
                        get {
-                               return _skipauth;
+                               return user;
                        }
 
+                       [SecurityPermission (SecurityAction.Demand, ControlPrincipal = true)]
                        set {
-                               _skipauth = value;
+                               user = value;
                        }
                }
 
-               public DateTime Timestamp
+               internal bool MapRequestHandlerDone {
+                       get;
+                       set;
+               }
+               
+               // The two properties below are defined only when the IIS7 integrated mode is used.
+               // They are useless under Mono
+               public RequestNotification CurrentNotification {
+                       get { throw new PlatformNotSupportedException ("This property is not supported on Mono.");  }
+               }
+
+               public bool IsPostNotification {
+                       get { throw new PlatformNotSupportedException ("This property is not supported on Mono."); }
+               }
+               
+               internal void PushHandler (IHttpHandler handler)
                {
+                       if (handler == null)
+                               return;
+                       if (handlers == null)
+                               handlers = new LinkedList <IHttpHandler> ();
+                       handlers.AddLast (handler);
+               }
+
+               internal void PopHandler ()
+               {
+                       if (handlers == null || handlers.Count == 0)
+                               return;
+                       handlers.RemoveLast ();
+               }
+               
+               IHttpHandler GetCurrentHandler ()
+               {
+                       if (handlers == null || handlers.Count == 0)
+                               return null;
+                       
+                       return handlers.Last.Value;
+               }
+
+               IHttpHandler GetPreviousHandler ()
+               {
+                       if (handlers == null || handlers.Count <= 1)
+                               return null;
+                       LinkedListNode <IHttpHandler> previous = handlers.Last.Previous;
+                       if (previous != null)
+                               return previous.Value;
+                       return null;
+               }
+               
+               public IHttpHandler CurrentHandler {
+                       get { return GetCurrentHandler (); }
+               }
+
+               public IHttpHandler PreviousHandler {
+                       get { return GetPreviousHandler (); }
+               }
+
+               internal bool ProfileInitialized {
+                       get { return profile != null; }
+               }
+
+               public ProfileBase Profile {
                        get {
-                               return _oTimestamp;
+                               if (profile == null) {
+                                       if (Request.IsAuthenticated)
+                                               profile = ProfileBase.Create (User.Identity.Name);
+                                       else
+                                               profile = ProfileBase.Create (Request.AnonymousID, false);
+                               }
+                               return profile;
+                       }
+
+                       internal set {
+                               profile = value;
                        }
                }
 
-               public TraceContext Trace
+               public void AddError (Exception errorInfo)
                {
-                       get {
-                               return _oTrace;
+                       if (errors == null){
+                               errors = errorInfo;
+                               return;
                        }
+                       ArrayList l;
+                       if (errors is Exception){
+                               l = new ArrayList ();
+                               l.Add (errors);
+                               errors = l;
+                       } else 
+                               l = (ArrayList) errors;
+                       l.Add (errorInfo);
                }
 
-               public IPrincipal User {
-                       get { return user; }
-                       set { user = value; }
+               internal void ClearError (Exception e)
+               {
+                       if (errors == e)
+                               errors = null;
                }
 
-               internal bool TimeoutPossible {
-                       get { return (Interlocked.CompareExchange (ref timeoutPossible, 1, 1) == 1); }
+               internal bool HasError (Exception e)
+               {
+                       if (errors == e)
+                               return true;
+
+                       return (errors is ArrayList) ?
+                               ((ArrayList) errors).Contains (e) : false;
                }
-               
-               internal void BeginTimeoutPossible ()
+
+               public void ClearError ()
                {
-                       timeoutPossible = 1;
-                       timeoutBegin = DateTime.UtcNow.Ticks;
+                       errors = null;
                }
 
-               internal void EndTimeoutPossible ()
+               [Obsolete ("use WebConfigurationManager.GetWebApplicationSection")]
+               public static object GetAppConfig (string name)
                {
-                       Interlocked.CompareExchange (ref timeoutPossible, 0, 1);
+                       object o = ConfigurationSettings.GetConfig (name);
+
+                       return o;
                }
-               
-               internal void TryWaitForTimeout () 
+
+               [Obsolete ("see GetSection")]
+               public object GetConfig (string name)
                {
-                       while (Interlocked.CompareExchange (ref timeoutPossible, 1, 1) == 1) {
-                               Thread.Sleep (500);
-                       }
+                       return GetSection (name);
                }
 
-               internal bool CheckIfTimeout (DateTime dt)
+               public static object GetGlobalResourceObject (string classKey, string resourceKey)
                {
-                       TimeSpan ts = new TimeSpan (dt.Ticks - timeoutBegin);
-                       return (ts > ConfigTimeout);
+                       return GetGlobalResourceObject (classKey, resourceKey, Thread.CurrentThread.CurrentUICulture);
                }
 
-               internal TimeSpan ConfigTimeout {
-                       get {
-                               if (configTimeout == null) {
-                                       HttpRuntimeConfig config = (HttpRuntimeConfig)
-                                                               GetConfig ("system.web/httpRuntime");
-                                       configTimeout = new TimeSpan (0, 0, config.ExecutionTimeout);
-                               }
+               static bool EnsureProviderFactory ()
+               {
+                       if (resource_providers == null)
+                               resource_providers = new Dictionary <string, IResourceProvider> ();
 
-                               return (TimeSpan) configTimeout;
-                       }
-                       set {
-                               configTimeout = value;
+                       if (provider_factory != null)
+                               return true;
+                       
+                       GlobalizationSection gs = WebConfigurationManager.GetSection ("system.web/globalization") as GlobalizationSection;
+
+                       if (gs == null)
+                               return false;
+
+                       String rsfTypeName = gs.ResourceProviderFactoryType;
+                       bool usingDefault = false;
+                       if (String.IsNullOrEmpty (rsfTypeName)) {
+                               usingDefault = true;
+                               rsfTypeName = typeof (DefaultResourceProviderFactory).AssemblyQualifiedName;
                        }
+                       
+                       Type rsfType = HttpApplication.LoadType (rsfTypeName, true);
+                       ResourceProviderFactory rpf = Activator.CreateInstance (rsfType) as ResourceProviderFactory;
+                       
+                       if (rpf == null && usingDefault)
+                               return false;
+
+                       provider_factory = rpf;
+                       if (usingDefault)
+                               default_provider_factory = rpf as DefaultResourceProviderFactory;
+                       
+                       return true;
                }
                
-               internal string ErrorPage {
-                       get { return errorPage; }
-                       set { errorPage = value; }
+               internal static IResourceProvider GetResourceProvider (string virtualPath, bool isLocal)
+               {
+                       if (!EnsureProviderFactory ())
+                               return null;
+
+                       // TODO: check if it makes sense to cache the providers and, if yes, maybe
+                       // we should expire the entries (or just store them in InternalCache?)
+                       IResourceProvider rp = null;
+                       if (!resource_providers.TryGetValue (virtualPath, out rp)) {
+                               if (isLocal)
+                                       rp = provider_factory.CreateLocalResourceProvider (virtualPath);
+                               else
+                                       rp = provider_factory.CreateGlobalResourceProvider (virtualPath);
+                               
+                               if (rp == null) {
+                                       if (isLocal)
+                                               rp = DefaultProviderFactory.CreateLocalResourceProvider (virtualPath);
+                                       else
+                                               rp = DefaultProviderFactory.CreateGlobalResourceProvider (virtualPath);
+
+                                       if (rp == null)
+                                               return null;
+                               }
+                               
+                               resource_providers.Add (virtualPath, rp);
+                       }
+
+                       return rp;
                }
-               
-               internal void SetSession (HttpSessionState session)
+
+               static object GetGlobalObjectFromFactory (string classKey, string resourceKey, CultureInfo culture)
                {
-                       _oSession = session;
+                       // FIXME: Retention of data
+                       IResourceProvider rp = GetResourceProvider (classKey, false);
+                       if (rp == null)
+                               return null;
+                       
+                       return rp.GetObject (resourceKey, culture);
                }
                
-               public void AddError (Exception errorInfo)
+               public static object GetGlobalResourceObject (string classKey, string resourceKey, CultureInfo culture)
                {
-                       if (_arrExceptions == null)
-                               _arrExceptions = new ArrayList ();
-
-                       _arrExceptions.Add (errorInfo);
+                       return GetGlobalObjectFromFactory ("Resources." + classKey, resourceKey, culture);
                }
 
-               public void ClearError ()
+               public static object GetLocalResourceObject (string virtualPath, string resourceKey)
                {
-                       _arrExceptions = null;
+                       return GetLocalResourceObject (virtualPath, resourceKey, Thread.CurrentThread.CurrentUICulture);
                }
 
-               public object GetConfig (string name)
+               static object GetLocalObjectFromFactory (string virtualPath, string resourceKey, CultureInfo culture)
                {
-                       return WebConfigurationSettings.GetConfig (name, this);
+                       IResourceProvider rp = GetResourceProvider (virtualPath, true);
+                       if (rp == null)
+                               return null;
+                       
+                       return rp.GetObject (resourceKey, culture);
                }
+               
+               public static object GetLocalResourceObject (string virtualPath, string resourceKey, CultureInfo culture)
+               {
+                       if (!VirtualPathUtility.IsAbsolute (virtualPath))
+                               throw new ArgumentException ("The specified virtualPath was not rooted.");
 
-               public static object GetAppConfig (string name)
+                       return GetLocalObjectFromFactory (virtualPath, resourceKey, culture);
+               }
+
+               public object GetSection (string name)
                {
-                       return WebConfigurationSettings.GetConfig (name);
+                       return WebConfigurationManager.GetSection (name);
                }
 
                object IServiceProvider.GetService (Type service)
                {
-                       if (service == typeof (HttpWorkerRequest)) 
-                               return _oWorkerRequest;
+                       if (service == typeof (HttpWorkerRequest))
+                               return WorkerRequest;
+
+                       //
+                       // We return everything out of properties in case
+                       // they are dynamically computed in some form in the future.
+                       //
+                       if (service == typeof (HttpApplication))
+                               return ApplicationInstance;
 
                        if (service == typeof (HttpRequest))
                                return Request;
@@ -371,61 +556,195 @@ namespace System.Web
                        if (service == typeof (HttpResponse))
                                return Response;
 
-                       if (service == typeof (HttpApplication))
-                               return ApplicationInstance;
+                       if (service == typeof (HttpSessionState))
+                               return Session;
 
                        if (service == typeof (HttpApplicationState))
                                return Application;
 
-                       if (service == typeof (HttpSessionState))
-                               return Session;
+                       if (service == typeof (IPrincipal))
+                               return User;
+
+                       if (service == typeof (Cache))
+                               return Cache;
+
+                       if (service == typeof (HttpContext))
+                               return Current;
+
+                       if (service == typeof (IHttpHandler))
+                               return Handler;
 
                        if (service == typeof (HttpServerUtility))
                                return Server;
-
+                       
+                       if (service == typeof (TraceContext))
+                               return Trace;
+                       
                        return null;
                }
 
+               public void RemapHandler (IHttpHandler handler)
+               {
+                       if (MapRequestHandlerDone)
+                               throw new InvalidOperationException ("The RemapHandler method was called after the MapRequestHandler event occurred.");
+                       Handler = handler;
+               }
+               
                public void RewritePath (string path)
                {
-                       //LAMESPEC: they say that they throw a ArgumentNullException, however,
-                       // i get a NullReferenceException...
-                       if (path == null)
-                               throw new ArgumentNullException ("path");
+                       RewritePath (path, true);
+               }
 
-                       string query;
+               public void RewritePath (string filePath, string pathInfo, string queryString)
+               {
+                       RewritePath (filePath, pathInfo, queryString, false);
+               }
+
+               public void RewritePath (string path, bool rebaseClientPath)
+               {
                        int qmark = path.IndexOf ('?');
-                       if (qmark == -1 || qmark + 1 >= path.Length) {
-                               query = null;
-                       } else {
-                               query = path.Substring (qmark + 1);
-                               path = path.Substring (0, qmark);
-                       }
+                       if (qmark != -1)
+                               RewritePath (path.Substring (0, qmark), String.Empty, path.Substring (qmark + 1), rebaseClientPath);
+                       else
+                               RewritePath (path, null, null, rebaseClientPath);
+               }
+
+               public void RewritePath (string filePath, string pathInfo, string queryString, bool setClientFilePath)
+               {
+                       if (filePath == null)
+                               throw new ArgumentNullException ("filePath");
+                       if (!VirtualPathUtility.IsValidVirtualPath (filePath))
+                               throw new HttpException ("'" + HttpUtility.HtmlEncode (filePath) + "' is not a valid virtual path.");
 
-                       path = UrlUtils.Combine (Request.BaseVirtualDir, path);
-                       if (!path.StartsWith (HttpRuntime.AppDomainAppVirtualPath))
-                               throw new HttpException (404, "The virtual path '" + path +
-                                                        "' maps to another application.");
+                       bool pathRelative = VirtualPathUtility.IsAppRelative (filePath);
+                       bool pathAbsolute = pathRelative ? false : VirtualPathUtility.IsAbsolute (filePath);
+                       HttpRequest req = Request;
+                       if (req == null)
+                               return;
+                       
+                       if (pathRelative || pathAbsolute) {
+                               if (pathRelative)
+                                       filePath = VirtualPathUtility.ToAbsolute (filePath);
+                       } else
+                               filePath = VirtualPathUtility.AppendTrailingSlash (req.BaseVirtualDir) + filePath;
+                       
+                       if (!StrUtils.StartsWith (filePath, HttpRuntime.AppDomainAppVirtualPath))
+                               throw new HttpException (404, "The virtual path '" + HttpUtility.HtmlEncode (filePath) + "' maps to another application.", filePath);
 
-                       Request.SetCurrentExePath (path);
-                       Request.QueryStringRaw = query;
+                       req.SetCurrentExePath (filePath);
+                       req.SetFilePath (filePath);
+
+                       if (setClientFilePath)
+                               req.ClientFilePath = filePath;
+                       
+                       // A null pathInfo or queryString is ignored and previous values remain untouched
+                       if (pathInfo != null)
+                               req.SetPathInfo (pathInfo);
+
+                       if (queryString != null)
+                               req.QueryStringRaw = queryString;
                }
 
-#if NET_1_1
-               public void RewritePath (string filePath, string pathInfo, string queryString)
+#if NET_4_0
+               public void SetSessionStateBehavior (SessionStateBehavior sessionStateBehavior)
                {
-                       RewritePath (filePath + "?" + queryString);
-                       Request.SetPathInfo (pathInfo);
+                       SessionStateBehavior = sessionStateBehavior;
                }
 #endif
+               
+#region internals
+               internal void SetSession (HttpSessionState state)
+               {
+                       session_state = state;
+               }
+
+               // URL of a page used for error redirection.
+               internal string ErrorPage {
+                       get {
+                               return error_page;
+                       }
 
-#if NET_2_0
-               internal System.Web.UI.Page LastPage {
-                       get { return lastPage; }
-                       set { lastPage = value; }
+                       set {
+                               error_page = value;
+                       }
                }
+
+               internal TimeSpan ConfigTimeout {
+                       get {
+                               if (config_timeout == null) {
+                                       HttpRuntimeSection section = (HttpRuntimeSection)WebConfigurationManager.GetSection ("system.web/httpRuntime");
+                                       config_timeout = section.ExecutionTimeout;
+                               }
+
+                               return (TimeSpan) config_timeout;
+                       }
+
+                       set {
+                               config_timeout = value;
+#if !TARGET_J2EE
+                               if (timer != null) {
+                                       TimeSpan remaining = value - (DateTime.UtcNow - time_stamp);
+                                       long remaining_ms = Math.Max ((long)remaining.TotalMilliseconds, 0);
+
+                                       // See http://msdn2.microsoft.com/en-us/library/7hs7492w.aspx
+                                       if (remaining_ms > 4294967294)
+                                               remaining_ms = 4294967294;
+                                       
+                                       timer.Change (remaining_ms, (long)Timeout.Infinite);
+                               }
 #endif
+                       }
+               }
+
+#if NET_4_0
+               internal SessionStateBehavior SessionStateBehavior {
+                       get;
+                       private set;
+               }
+#endif
+               
+#if !TARGET_J2EE
+               void TimeoutReached(object state) {
+                       HttpRuntime.QueuePendingRequest (false);
+                       if (Interlocked.CompareExchange (ref timeout_possible, 0, 0) == 0) {
+                               timer.Change(2000, 0);
+                               return;                 
+                       }
+                       StopTimeoutTimer();
+                       
+                       thread.Abort (new StepTimeout ());
+               }
+               
+               internal void StartTimeoutTimer() {
+                       thread = Thread.CurrentThread;
+                       timer = new Timer (TimeoutReached, null, (int)ConfigTimeout.TotalMilliseconds, Timeout.Infinite);
+               }
+               
+               internal void StopTimeoutTimer() {
+                       if(timer != null) {
+                               timer.Dispose ();
+                               timer = null;
+                       }
+               }
 
+               internal bool TimeoutPossible {
+                       get { return (Interlocked.CompareExchange (ref timeout_possible, 1, 1) == 1); }
+               }
+
+               internal void BeginTimeoutPossible ()
+               {
+                       timeout_possible = 1;
+               }
+
+               internal void EndTimeoutPossible ()
+               {
+                       Interlocked.CompareExchange (ref timeout_possible, 0, 1);
+               }
+#endif
+#endregion
+       }
+       
+       class StepTimeout
+       {
        }
 }
-