Sfoglia il codice sorgente

2002-12-18 Gonzalo Paniagua Javier <[email protected]>

	* System.Web/HttpApplicationFactory.cs: add the context as parameter
	when building the application Type.

	* System.Web/HttpCookie.cs: new internal constructor.
	* System.Web/HttpCookieCollection.cs: new internal method to make a
	cookie expire.

	* System.Web/HttpRequest.cs: MapPath fixes.
	* System.Web/HttpResponse.cs: implemented ApplyAppPathModifier.
	* System.Web/HttpRuntime.cs: fixed typo in AppDomainAppVirtualPath.
	* System.Web.Compilation/AspGenerator.cs: now it uses the current
	HttpContext when creating user controls. TemplateSourceDirectory is no
	longer a dummy value.

	* System.Web.Compilation/GlobalAsaxCompiler.cs:
	* System.Web.Compilation/PageCompiler.cs:
	* System.Web.Compilation/UserControlCompiler.cs: set the context which
	will be used to locate the files.

	* System.Web.UI/BaseParser.cs: use MapPath and context to locate files.
	* System.Web.UI/Control.cs: implemented MapPathSecure.
	* System.Web.UI/TemplateControl.cs: use UrlUtils to generate the path.
	* System.Web.UI/TemplateControlParser.cs: use the context and MapPath.
	* System.Web.UI/UserControl.cs: implemented MapPath.
	* System.Web.UI/UserControlParser.cs: added context parameter to
	constructor.
	* System.Web.Util/PathUtil.cs: removed.
	* System.Web.Util/UrlUtils.cs: fixed Combine to handle '~'.

svn path=/trunk/mcs/; revision=9737
Gonzalo Paniagua Javier 23 anni fa
parent
commit
8e91ed0203

+ 27 - 12
mcs/class/System.Web/System.Web.Compilation/AspGenerator.cs

@@ -325,6 +325,8 @@ class AspGenerator
 	bool isUserControl;
 	bool isApplication;
 
+	HttpContext context;
+
 	enum UserControlResult
 	{
 		OK = 0,
@@ -397,6 +399,11 @@ class AspGenerator
 		}
 	}
 	
+	internal HttpContext Context {
+		get { return context; }
+		set { context = value; }
+	}
+	
 	public void AddInterface (string iface)
 	{
 		if (interfaces == "") {
@@ -581,8 +588,7 @@ class AspGenerator
 				throw new ApplicationException ("Source file extension for controls " + 
 								"must be .ascx");
 
-			string srcLocation = PathUtil.Combine (null, src);
-			UserControlData data = GenerateUserControl (srcLocation);
+			UserControlData data = GenerateUserControl (src, Context);
 			switch (data.result) {
 			case UserControlResult.OK:
 				prolog.AppendFormat ("\tusing {0};\n", "ASP");
@@ -1728,6 +1734,21 @@ class AspGenerator
 		}
 	}
 
+	private string GetTemplateDirectory ()
+	{
+		string templatePath = Path.GetDirectoryName (fullPath);
+		string appPath = Path.GetDirectoryName (HttpRuntime.AppDomainAppPath);
+
+		if (templatePath == appPath)
+			return "/";
+
+		templatePath = templatePath.Substring (appPath.Length);
+		if (Path.DirectorySeparatorChar != '/')
+			templatePath = templatePath.Replace (Path.DirectorySeparatorChar, '/');
+			
+		return templatePath;
+	}
+
 	private void End ()
 	{
 		classDecl = "\tpublic class " + className + " : " + parent + interfaces + " {\n"; 
@@ -1765,12 +1786,11 @@ class AspGenerator
 				"\t\tprotected System.Web.HttpApplication ApplicationInstance\n\t\t{\n" +
 				"\t\t\tget { return (System.Web.HttpApplication) this.Context.ApplicationInstance; }\n" +
 				"\t\t}\n\n");
-			//FIXME: add TemplateSourceDirectory: don't know what for...yet!
-			//FIXME: it should be the path from the root where the file resides
+
 			constructor.AppendFormat (
 				"\t\tpublic override string TemplateSourceDirectory\n\t\t{{\n" +
 				"\t\t\tget {{ return \"{0}\"; }}\n" +
-				"\t\t}}\n\n", Path.GetDirectoryName (fullPath)); // FIXME: should be rooted on .appVPath
+				"\t\t}}\n\n", GetTemplateDirectory ());
 
 			epilog.Append ("\n\t\tprotected override void FrameworkInitialize ()\n\t\t{\n" +
 					"\t\t\tthis.__BuildControlTree (this);\n");
@@ -1832,17 +1852,12 @@ class AspGenerator
 		public string assemblyName;
 	}
 
-	private static UserControlData GenerateUserControl (string src)
+	private static UserControlData GenerateUserControl (string src, HttpContext context)
 	{
 		UserControlData data = new UserControlData ();
 		data.result = UserControlResult.OK;
 
-		if (!File.Exists (src)) {
-			data.result = UserControlResult.FileNotFound;
-			return data;
-		}
-
-		UserControlCompiler compiler = new UserControlCompiler (new UserControlParser (src));
+		UserControlCompiler compiler = new UserControlCompiler (new UserControlParser (src, context));
 		Type t = compiler.GetCompiledType ();
 		if (t == null) {
 			data.result = UserControlResult.CompilationFailed;

+ 10 - 0
mcs/class/System.Web/System.Web.Compilation/ChangeLog

@@ -1,3 +1,13 @@
+2002-12-18  Gonzalo Paniagua Javier <[email protected]>
+
+	* AspGenerator.cs: now it uses the current HttpContext when creating
+	user controls. TemplateSourceDirectory is no longer a dummy value.
+
+	* GlobalAsaxCompiler.cs:
+	* PageCompiler.cs:
+	* UserControlCompiler.cs: set the context which will be used to locate
+	the files.
+	
 2002-12-13  Gonzalo Paniagua Javier <[email protected]>
 
 	* AspGenerator.cs: added support for AutoEventWireup attribute in

+ 4 - 1
mcs/class/System.Web/System.Web.Compilation/GlobalAsaxCompiler.cs

@@ -19,6 +19,7 @@ namespace System.Web.Compilation
 	{
 		string filename;
 		string sourceFile;
+		HttpContext context;
 
 		private GlobalAsaxCompiler (string filename)
 		{
@@ -60,7 +61,7 @@ namespace System.Web.Compilation
 			}
 		}
 
-		public static Type CompileApplicationType (string filename)
+		public static Type CompileApplicationType (string filename, HttpContext context)
 		{
 			CompilationCacheItem item = CachingCompiler.GetCached (filename);
 			if (item != null && item.Result != null) {
@@ -71,6 +72,7 @@ namespace System.Web.Compilation
 			}
 
 			GlobalAsaxCompiler gac = new GlobalAsaxCompiler (filename);
+			gac.context = context;
 			return gac.GetCompiledType ();
 		}
 
@@ -80,6 +82,7 @@ namespace System.Web.Compilation
 			AspParser parser = new AspParser (filename, input);
 			parser.Parse ();
 			AspGenerator generator = new AspGenerator (filename, parser.Elements);
+			generator.Context = context;
 			generator.BaseType = typeof (HttpApplication).ToString ();
 			generator.ProcessElements ();
 			string generated = generator.GetCode ().ReadToEnd ();

+ 1 - 0
mcs/class/System.Web/System.Web.Compilation/PageCompiler.cs

@@ -85,6 +85,7 @@ namespace System.Web.Compilation
 			AspParser parser = new AspParser (inputFile, input);
 			parser.Parse ();
 			AspGenerator generator = new AspGenerator (inputFile, parser.Elements);
+			generator.Context = pageParser.Context;
 			generator.BaseType = pageParser.BaseType.ToString ();
 			generator.ProcessElements ();
 			pageParser.Text = generator.GetCode ().ReadToEnd ();

+ 1 - 0
mcs/class/System.Web/System.Web.Compilation/UserControlCompiler.cs

@@ -99,6 +99,7 @@ namespace System.Web.Compilation
 			AspParser parser = new AspParser (inputFile, input);
 			parser.Parse ();
 			AspGenerator generator = new AspGenerator (inputFile, parser.Elements);
+			generator.Context = userControlParser.Context;
 			generator.BaseType = userControlParser.BaseType.ToString ();
 			generator.ProcessElements ();
 			userControlParser.Text = generator.GetCode ().ReadToEnd ();

+ 14 - 3
mcs/class/System.Web/System.Web.UI/BaseParser.cs

@@ -7,8 +7,10 @@
 //
 // (C) 2002 Ximian, Inc. (http://www.ximian.com)
 //
+
 using System.IO;
 using System.Web;
+using System.Web.Util;
 
 namespace System.Web.UI
 {
@@ -26,7 +28,10 @@ namespace System.Web.UI
 
 		internal string MapPath (string path, bool allowCrossAppMapping)
 		{
-			return context.Request.MapPath (path, baseVDir, allowCrossAppMapping);
+			if (context == null)
+				throw new HttpException ("context is null!!");
+
+			return context.Request.MapPath (path, BaseVirtualDir, allowCrossAppMapping);
 		}
 
 		internal string PhysicalPath (string path)
@@ -34,7 +39,7 @@ namespace System.Web.UI
 			if (Path.DirectorySeparatorChar != '/')
 				path = path.Replace ('/', '\\');
 				
-			return Path.GetFullPath (Path.Combine (baseVDir, path));
+			return Path.GetFullPath (Path.Combine (BaseVirtualDir, path));
 		}
 
 		internal HttpContext Context
@@ -42,13 +47,16 @@ namespace System.Web.UI
 			get {
 				return context;
 			}
+			set {
+				context = value;
+			}
 		}
 
 		internal string BaseDir
 		{
 			get {
 				if (baseDir == null)
-					baseDir = MapPath (baseVDir, false);
+					baseDir = MapPath (BaseVirtualDir, false);
 
 				return baseDir;
 			}
@@ -57,6 +65,9 @@ namespace System.Web.UI
 		internal string BaseVirtualDir
 		{
 			get {
+				if (baseVDir == null)
+					baseVDir = UrlUtils.GetDirectory (context.Request.FilePath);
+
 				return baseVDir;
 			}
 		}

+ 9 - 0
mcs/class/System.Web/System.Web.UI/ChangeLog

@@ -1,3 +1,12 @@
+2002-12-18  Gonzalo Paniagua Javier <[email protected]>
+
+	* BaseParser.cs: use MapPath and context to locate files.
+	* Control.cs: implemented MapPathSecure.
+	* TemplateControl.cs: use UrlUtils to generate the path.
+	* TemplateControlParser.cs: use the context and MapPath.
+	* UserControl.cs: implemented MapPath.
+	* UserControlParser.cs: added context parameter to constructor.
+
 2002-12-17  Gonzalo Paniagua Javier <[email protected]>
 
 	* Control.cs: implemented MapPathSecure.

+ 2 - 1
mcs/class/System.Web/System.Web.UI/Control.cs

@@ -423,7 +423,8 @@ namespace System.Web.UI
 		[MonoTODO("Secure?")]
                 protected string MapPathSecure(string virtualPath)
                 {
-			return Context.Request.MapPath (virtualPath);
+			string combined = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
+			return Context.Request.MapPath (combined);
                 }
 
                 protected virtual bool OnBubbleEvent(object source, EventArgs args) //DIT

+ 2 - 6
mcs/class/System.Web/System.Web.UI/TemplateControl.cs

@@ -112,12 +112,8 @@ namespace System.Web.UI {
 			if (virtualPath == null)
 				throw new ArgumentNullException ("virtualPath");
 
-			if (virtualPath [0] == '/')
-				throw new ArgumentException ("Path cannot be rooted", "virtualPath");
-
-			virtualPath = PathUtil.Combine (TemplateSourceDirectory, virtualPath);
-
-			return UserControlCompiler.CompileUserControlType (new UserControlParser (virtualPath));
+			string vpath = UrlUtils.Combine (TemplateSourceDirectory, virtualPath);
+			return UserControlCompiler.CompileUserControlType (new UserControlParser (vpath, Context));
 		}
 
 		public Control LoadControl (string virtualPath)

+ 3 - 1
mcs/class/System.Web/System.Web.UI/TemplateControlParser.cs

@@ -10,6 +10,7 @@ using System;
 using System.Collections;
 using System.IO;
 using System.Web.Compilation;
+using System.Web.Util;
 
 namespace System.Web.UI
 {
@@ -17,7 +18,8 @@ namespace System.Web.UI
 	{
 		internal object GetCompiledInstance (string virtualPath, string inputFile, HttpContext context)
 		{
-			InputFile = inputFile;
+			Context = context;
+			InputFile = MapPath (virtualPath);
 			Type type = CompileIntoType ();
 			if (type == null)
 				return null;

+ 1 - 2
mcs/class/System.Web/System.Web.UI/UserControl.cs

@@ -135,10 +135,9 @@ namespace System.Web.UI
 			FrameworkInitialize ();
 		}
 
-		[MonoTODO]
 		public string MapPath (string virtualPath)
 		{
-			throw new NotImplementedException ();
+			return Request.MapPath (virtualPath, TemplateSourceDirectory, true);
 		}
 
 		protected override void LoadViewState (object savedState)

+ 4 - 3
mcs/class/System.Web/System.Web.UI/UserControlParser.cs

@@ -14,14 +14,15 @@ namespace System.Web.UI
 {
 	public sealed class UserControlParser : TemplateControlParser
 	{
-		internal UserControlParser (string inputFile)
+		internal UserControlParser (string inputFile, HttpContext context)
 		{
-			InputFile = inputFile;
+			Context = context;
+			InputFile = context.Request.MapPath (inputFile);
 		}
 		
 		public static Type GetCompiledType (string virtualPath, string inputFile, HttpContext context)
 		{
-			UserControlParser ucp = new UserControlParser (inputFile);
+			UserControlParser ucp = new UserControlParser (inputFile, context);
 			Type t = ucp.CompileIntoType ();
 			return t;
 		}

+ 5 - 0
mcs/class/System.Web/System.Web.Util/ChangeLog

@@ -1,3 +1,8 @@
+2002-12-18  Gonzalo Paniagua Javier <[email protected]>
+
+	* PathUtil.cs: removed.
+	* UrlUtils.cs: fixed Combine to handle '~'.
+
 2002-12-12  Gonzalo Paniagua Javier <[email protected]>
 
 	* PathUtil.cs: some path handling methods that are not available in

+ 0 - 88
mcs/class/System.Web/System.Web.Util/PathUtil.cs

@@ -1,88 +0,0 @@
-//
-// System.Web.Util.PathUtil
-//
-// Authors:
-//	Gonzalo Paniagua Javier ([email protected])
-//
-// (C) 2002 Ximian, Inc (http://www.ximian.com)
-//
-
-using System;
-using System.Collections;
-using System.IO;
-using System.Reflection;
-
-namespace System.Web.Util
-{
-	internal class PathUtil
-	{
-		static string appbase;
-		static char [] separators;
-
-		static PathUtil ()
-		{
-			// This hack is a workaround until AppDomainVirtualPath works... Gotta investigate it.
-			Assembly entry = Assembly.GetEntryAssembly ();
-			appbase = Path.GetDirectoryName (entry.Location);
-			//
-
-			if (Path.DirectorySeparatorChar != Path.AltDirectorySeparatorChar)
-				separators = new char [] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar};
-			else
-				separators = new char [] {Path.DirectorySeparatorChar};
-		}
-		
-		static string MakeAbsolute (string abspath)
-		{
-			string [] parts = abspath.Split (separators);
-			ArrayList valid = new ArrayList ();
-
-			int len = parts.Length;
-			bool hasDots = false;
-			for (int i = 0; i < len; i++) {
-				if (parts [i] == ".") {
-					hasDots = true;
-					continue;
-				}
-
-				if (parts [i] == "..") {
-					hasDots = true;
-					if (valid.Count > 0)
-						valid.RemoveAt (valid.Count - 1);
-					continue;
-				}
-
-				valid.Add (parts [i]);
-			}
-
-			if (!hasDots)
-				return abspath;
-
-			parts = (String []) valid.ToArray (typeof (string));
-			string result = String.Join (new String (Path.DirectorySeparatorChar, 1), parts);
-			if (!Path.IsPathRooted (result))
-				return Path.DirectorySeparatorChar + result;
-
-			return result;
-		}
-
-		static public string Combine (string basepath, string relative)
-		{
-			if (relative == null || relative.Length == 0)
-				throw new ArgumentException ("empty or null", "relative");
-
-			char first = relative [0];
-			if (first == '/' || first == '\\' || Path.IsPathRooted (relative))
-				throw new ArgumentException ("'relative' is rooted", "relative");
-
-			if (first == '~' && relative.Length > 1 && Array.IndexOf (separators, relative [1]) != -1)
-				return Path.Combine (appbase, relative.Substring (2));
-
-			if (basepath == null)
-				basepath = appbase;
-
-			return MakeAbsolute (Path.Combine (basepath, relative));
-		}
-	}
-}
-

+ 17 - 16
mcs/class/System.Web/System.Web.Util/UrlUtils.cs

@@ -96,34 +96,35 @@ namespace System.Web.Util
 		
 		public static void FailIfPhysicalPath(string path)
 		{
-			if(path!= null && path.Length > 0)
+			if(path!= null && path.Length > 1)
 			{
-				if(path[0]==':' || path.StartsWith(@"\\"))
+				if(path[1]==':' || path.StartsWith(@"\\"))
 					throw new HttpException(HttpRuntime.FormatResourceString("Physical_path_not_allowed", path));
 			}
 		}
 		
-		public static string Combine(string basePath, string relPath)
+		public static string Combine (string basePath, string relPath)
 		{
-			FailIfPhysicalPath(relPath);
-			if(IsRootUrl(relPath))
-			{
-				if(relPath != null && relPath.Length > 0)
-				{
-					return Reduce(relPath);
-				}
+			FailIfPhysicalPath (relPath);
+			if (IsRootUrl (relPath)) {
+				if (relPath != null && relPath.Length > 0)
+					return Reduce (relPath);
+
 				return String.Empty;
 			}
-			if(relPath.Length < 3 || relPath[0]!='~' || (relPath[0]!='/' && relPath[0]!='\\'))
-			{
-				if(basePath==null || basePath.Length==1 || basePath[0]=='/')
+
+			if (relPath.Length < 3 || relPath [0] != '~' || relPath [0] == '/' || relPath [0] == '\\') {
+				if (basePath == null || basePath.Length == 1 || basePath [0] == '/')
 					basePath = String.Empty;
-				return Reduce(basePath + "/" + relPath);
+
+				return Reduce (basePath + "/" + relPath);
 			}
+
 			string vPath = HttpRuntime.AppDomainAppVirtualPath;
-			if(vPath.Length <= 1)
+			if (vPath.Length <= 1)
 				vPath = String.Empty;
-			return Reduce(vPath + "/" + relPath.Substring(2));
+
+			return Reduce (vPath + "/" + relPath.Substring (2));
 		}
 		
 		public static bool IsValidProtocol(string protocol)

+ 12 - 0
mcs/class/System.Web/System.Web/ChangeLog

@@ -1,3 +1,15 @@
+2002-12-18  Gonzalo Paniagua Javier <[email protected]>
+
+	* HttpApplicationFactory.cs: add the context as parameter when building
+	the application Type.
+	
+	* HttpCookie.cs: new internal constructor.
+	* HttpCookieCollection.cs: new internal method to make a cookie expire.
+
+	* HttpRequest.cs: MapPath fixes.
+	* HttpResponse.cs: implemented ApplyAppPathModifier.
+	* HttpRuntime.cs: fixed typo in AppDomainAppVirtualPath.
+
 2002-12-17  Gonzalo Paniagua Javier <[email protected]>
 
 	* HttpContext.cs: hack to create a default user when there's no one.

+ 1 - 1
mcs/class/System.Web/System.Web/HttpApplicationFactory.cs

@@ -78,7 +78,7 @@ namespace System.Web {
 			if (File.Exists(_appFilename)) {
 				// Setup filemonitor for all filedepend also. CacheDependency?
 
-				_appType = GlobalAsaxCompiler.CompileApplicationType (_appFilename);
+				_appType = GlobalAsaxCompiler.CompileApplicationType (_appFilename, context);
 				if (_appType == null)
 					throw new ApplicationException ("Error compiling application file (global.asax).");
 			} else {

+ 9 - 0
mcs/class/System.Web/System.Web/HttpCookie.cs

@@ -41,6 +41,15 @@ namespace System.Web
 			_Path = "/";
 		}
 
+		internal HttpCookie (string name, string value, string path, DateTime expires)
+		{
+			_Name = name;
+			_Value = value;
+			_Path = path;
+			if (expires != DateTime.MinValue)
+				Expires = expires;
+		}
+		
 		internal HttpResponseHeader GetCookieHeader ()
 		{
 			StringBuilder oSetCookie = new StringBuilder ();

+ 8 - 0
mcs/class/System.Web/System.Web/HttpCookieCollection.cs

@@ -134,6 +134,14 @@ namespace System.Web
 			if (null != _Response)
 				_Response.ChangedCookieColl();
 		}
+
+		internal void MakeCookieExpire (string name, string path)
+		{
+			DateTime expirationTime = new DateTime (1999, 10, 12); // This is the date MS sends!
+			HttpCookie willExpire = new HttpCookie (name, String.Empty, path, expirationTime);
+			Remove (name);
+			Add (willExpire);
+		}
 	}
 }
 

+ 40 - 18
mcs/class/System.Web/System.Web/HttpRequest.cs

@@ -61,6 +61,7 @@ namespace System.Web {
 		private HttpBrowserCapabilities _browser;
 
 		private HttpCookieCollection cookies;
+		private bool rewritten;
 
 		public HttpRequest(string Filename, string Url, string Querystring) {
 			_iContentLength = -1;
@@ -697,11 +698,12 @@ namespace System.Web {
 
 		public string PhysicalPath {
 			get {
-				if (null != _WorkerRequest) {
-					_sPathTranslated = _WorkerRequest.GetFilePathTranslated();
-					if (null == _sPathTranslated) {
-						_sPathTranslated = _WorkerRequest.MapPath(FilePath);
-					}
+				if (_sPathTranslated == null && _WorkerRequest != null) {
+					if (rewritten)
+						_sPathTranslated = _WorkerRequest.GetFilePathTranslated ();
+
+					if (null == _sPathTranslated)
+						_sPathTranslated = _WorkerRequest.MapPath (FilePath);
 				}
 
 				return _sPathTranslated;
@@ -876,6 +878,21 @@ namespace System.Web {
 			}
 		}
 
+		internal string RootVirtualDir {
+			get {
+				if (_sRequestRootVirtualDir == null) {
+					_sRequestRootVirtualDir = FilePath;
+					int pos = _sRequestRootVirtualDir.LastIndexOf ('/');
+					if (pos == -1 || pos == 0)
+						_sRequestRootVirtualDir = "/";
+					else
+						_sRequestRootVirtualDir = _sRequestRootVirtualDir.Substring (0, pos);
+				}
+
+				return _sRequestRootVirtualDir;
+			}
+		}
+		
 		public byte [] BinaryRead(int count) {
 			int iSize = TotalBytes;
 			if (iSize == 0) {
@@ -927,29 +944,34 @@ namespace System.Web {
 			return arrRet;
 		}
 
-		public string MapPath(string VirtualPath)
+		public string MapPath (string VirtualPath)
 		{
-			if (_sRequestRootVirtualDir == null) {
-				_sRequestRootVirtualDir = FilePath;
-				int pos = _sRequestRootVirtualDir.LastIndexOf ('/');
-				if (pos == -1 || pos == 0)
-					_sRequestRootVirtualDir = "/";
-				else
-					_sRequestRootVirtualDir = _sRequestRootVirtualDir.Substring (0, pos);
-			}
-			return MapPath (VirtualPath, _sRequestRootVirtualDir, true);
+			return MapPath (VirtualPath, RootVirtualDir, true);
 		}
 
-		[MonoTODO]
-		public string MapPath(string virtualPath, string baseVirtualDir, bool allowCrossAppMapping)
+		[MonoTODO("allowCrossAppMapping?")]
+		public string MapPath (string virtualPath, string baseVirtualDir, bool allowCrossAppMapping)
 		{
 			if (_WorkerRequest == null)
 				throw new HttpException ("No HttpWorkerRequest!!!");
 
 			if (virtualPath == null || virtualPath.Length == 0)
 				virtualPath = ".";
+			else
+				virtualPath = virtualPath.Trim ();
+
+			if (System.IO.Path.DirectorySeparatorChar != '/')
+				virtualPath = virtualPath.Replace (System.IO.Path.DirectorySeparatorChar, '/');
+
+			if (UrlUtils.IsRooted (virtualPath)) {
+				virtualPath = UrlUtils.Reduce (virtualPath);
+			} else {
+				if (baseVirtualDir == null)
+					virtualPath = UrlUtils.Combine (RootVirtualDir, virtualPath);
+				else
+					virtualPath = UrlUtils.Combine (baseVirtualDir, virtualPath);
+			}
 
-			virtualPath = System.IO.Path.Combine (baseVirtualDir, virtualPath);
 			return _WorkerRequest.MapPath (virtualPath);
 		}
 

+ 13 - 3
mcs/class/System.Web/System.Web/HttpResponse.cs

@@ -176,8 +176,9 @@ namespace System.Web
 
 			if (_Cookies != null) {
 				int length = _Cookies.Count;
-				for (int i = 0; i < length; i++)
+				for (int i = 0; i < length; i++) {
 					oHeaders.Add (_Cookies.Get (i).GetCookieHeader ());
+				}
 			}
 
 			return oHeaders;
@@ -269,10 +270,18 @@ namespace System.Web
 			throw new NotImplementedException ();
 		}
 
-		[MonoTODO()]
 		public string ApplyAppPathModifier (string virtualPath)
 		{
-			throw new NotImplementedException ();
+			if (virtualPath == null)
+				return null;
+
+			if (UrlUtils.IsRelativeUrl (virtualPath)) {
+				virtualPath = UrlUtils.Combine (_Context.Request.RootVirtualDir, virtualPath);
+			} else if (UrlUtils.IsRooted (virtualPath)) {
+				virtualPath = UrlUtils.Reduce (virtualPath);
+			}
+
+			return virtualPath;
 		}
 
 		public bool Buffer
@@ -751,6 +760,7 @@ namespace System.Web
 
 			Clear ();
 
+			url = ApplyAppPathModifier (url);
 			StatusCode = 302;
 			AppendHeader (HttpWorkerRequest.HeaderLocation, url);
 

+ 1 - 1
mcs/class/System.Web/System.Web/HttpRuntime.cs

@@ -266,7 +266,7 @@ namespace System.Web {
 		public static string AppDomainAppVirtualPath {
 			get {
 				if (appDomainAppVirtualPath == null)
-					appDomainAppPath = (string) AppDomain.CurrentDomain.GetData (".appVPath");
+					appDomainAppVirtualPath = (string) AppDomain.CurrentDomain.GetData (".appVPath");
 
 				return appDomainAppVirtualPath;
 			}

+ 0 - 1
mcs/class/System.Web/list

@@ -324,7 +324,6 @@ System.Web.Util/FileChangesMonitor.cs
 System.Web.Util/FilePathParser.cs
 System.Web.Util/IISVersionInfo.cs
 System.Web.Util/NativeFileChangeEventHandler.cs
-System.Web.Util/PathUtil.cs
 System.Web.Util/UrlUtils.cs
 System.Web.Util/WebEncoding.cs
 System.Web.Util/WebEqualComparer.cs