diff --git a/src/Mono.WebServer.Apache/main.cs b/src/Mono.WebServer.Apache/main.cs index f7ebfeec..e33b0524 100644 --- a/src/Mono.WebServer.Apache/main.cs +++ b/src/Mono.WebServer.Apache/main.cs @@ -366,7 +366,7 @@ public int RealMain (string [] args, bool root, IApplicationHost ext_apphost, bo return (res) ? 0 : 1; } - ApplicationServer server = new ApplicationServer (webSource); + ApplicationServer server = new ApplicationServer (webSource, rootDir); server.Verbose = verbose; server.SingleApplication = !root; diff --git a/src/Mono.WebServer.FastCgi/main.cs b/src/Mono.WebServer.FastCgi/main.cs index 1bd3c538..3dd683c3 100644 --- a/src/Mono.WebServer.FastCgi/main.cs +++ b/src/Mono.WebServer.FastCgi/main.cs @@ -288,7 +288,7 @@ public static int Main (string [] args) root_dir = Environment.CurrentDirectory; bool auto_map = false; //(bool) configmanager ["automappaths"]; WebSource webSource = new WebSource (); - appserver = new ApplicationServer (webSource); + appserver = new ApplicationServer (webSource, root_dir); appserver.Verbose = (bool) configmanager ["verbose"]; string applications = (string) diff --git a/src/Mono.WebServer.XSP/main.cs b/src/Mono.WebServer.XSP/main.cs index 718c24ae..54796814 100644 --- a/src/Mono.WebServer.XSP/main.cs +++ b/src/Mono.WebServer.XSP/main.cs @@ -426,7 +426,7 @@ public int RealMain (string [] args, bool root, IApplicationHost ext_apphost, bo webSource = new XSPWebSource (ipaddr, port, !root); } - ApplicationServer server = new ApplicationServer (webSource); + ApplicationServer server = new ApplicationServer (webSource, settings.RootDir); server.Verbose = settings.Verbose; server.SingleApplication = !root; diff --git a/src/Mono.WebServer/ApplicationServer.cs b/src/Mono.WebServer/ApplicationServer.cs index 18c4714b..e689c173 100644 --- a/src/Mono.WebServer/ApplicationServer.cs +++ b/src/Mono.WebServer/ApplicationServer.cs @@ -90,6 +90,7 @@ public class ApplicationServer : MarshalByRefObject Socket listen_socket; bool single_app; Exception initialException; + string physicalRoot; Thread runner; @@ -127,10 +128,20 @@ public class ApplicationServer : MarshalByRefObject return iep.Port; } } + + public string PhysicalRoot { + get { return physicalRoot; } + } - public ApplicationServer (WebSource source) + public ApplicationServer (WebSource source, string physicalRoot) { - webSource = source; + if (source == null) + throw new ArgumentNullException ("source"); + if (physicalRoot == null || physicalRoot.Length == 0) + throw new ArgumentNullException ("physicalRoot"); + + this.webSource = source; + this.physicalRoot = physicalRoot; } public bool Verbose { diff --git a/src/Mono.WebServer/MonoWorkerRequest.cs b/src/Mono.WebServer/MonoWorkerRequest.cs index b52c62c9..8dc8a81d 100644 --- a/src/Mono.WebServer/MonoWorkerRequest.cs +++ b/src/Mono.WebServer/MonoWorkerRequest.cs @@ -175,8 +175,12 @@ public MapPathEventArgs (string path) /// public abstract class MonoWorkerRequest : SimpleWorkerRequest { + static readonly char[] mapPathTrimStartChars = { '/' }; + static bool runningOnWindows; static bool checkFileAccess = true; + static bool needToReplacePathSeparator; + static char pathSeparatorChar; /// /// Contains the application host used by the current @@ -218,6 +222,8 @@ public abstract class MonoWorkerRequest : SimpleWorkerRequest /// as read from the application host. /// string hostPath; + + string hostPhysicalRoot; /// /// Contains the @@ -274,6 +280,11 @@ static MonoWorkerRequest () #endif ); + if (Path.DirectorySeparatorChar != '/') { + needToReplacePathSeparator = true; + pathSeparatorChar = Path.DirectorySeparatorChar; + } + try { #if NET_2_0 string v = ConfigurationManager.AppSettings ["MonoServerCheckHiddenFiles"]; @@ -381,6 +392,15 @@ public MonoWorkerRequest (IApplicationHost appHost) } } + string HostPhysicalRoot { + get { + if (hostPhysicalRoot == null) + hostPhysicalRoot = appHostBase.Server.PhysicalRoot; + + return hostPhysicalRoot; + } + } + /// /// Gets the content encoding used by the current instance. /// @@ -595,30 +615,67 @@ string DoMapPathEvent (string path) /// register a with . /// + // + // The logic here is as follows: + // + // If path is equal to the host's virtual path (including trailing slash), + // return the host virtual path. + // + // If path is absolute (starts with '/') then check if it's under our host vpath. If + // it is, base the mapping under the virtual application's physical path. If it + // isn't use the physical root of the application server to return the mapped + // path. If you have just one application configured, then the values computed in + // both of the above cases will be the same. If you have several applications + // configured for this xsp/mod-mono-server instance, then virtual paths outside our + // application virtual path will return physical paths relative to the server's + // physical root, not application's. This is consistent with the way IIS worker + // request works. See bug #575600 + // public override string MapPath (string path) { string eventResult = DoMapPathEvent (path); if (eventResult != null) return eventResult; - if (path == null || path.Length == 0 || path == HostVPath) - return HostPath.Replace ('/', Path.DirectorySeparatorChar); + string hostVPath = HostVPath; + int hostVPathLen = HostVPath.Length; + int pathLen = path != null ? path.Length : 0; + bool inThisApp; +#if NET_2_0 + inThisApp = path.StartsWith (hostVPath, StringComparison.Ordinal); +#else + inThisApp = path.StartsWith (hostVPath); +#endif + if (pathLen == 0 || (inThisApp && (pathLen == hostVPathLen || (pathLen == hostVPathLen + 1 && path [pathLen - 1] == '/')))) { + if (needToReplacePathSeparator) + return HostPath.Replace ('/', pathSeparatorChar); + return HostPath; + } - if (path [0] == '~' && path.Length > 2 && path [1] == '/') - path = path.Substring (1); + string basePath = null; + switch (path [0]) { + case '~': + if (path.Length >= 2 && path [1] == '/') + path = path.Substring (1); + break; + + case '/': + if (!inThisApp) + basePath = HostPhysicalRoot; + break; + } - int len = HostVPath.Length; - if (path.StartsWith (HostVPath) && (path.Length == len || path [len] == '/')) - path = path.Substring (len + 1); + if (basePath == null) + basePath = HostPath; - while (path.Length > 0 && path [0] == '/') { - path = path.Substring (1); - } + if (inThisApp && (path.Length == hostVPathLen || path [hostVPathLen] == '/')) + path = path.Substring (hostVPathLen + 1); - if (Path.DirectorySeparatorChar != '/') - path = path.Replace ('/', Path.DirectorySeparatorChar); + path = path.TrimStart (mapPathTrimStartChars); + if (needToReplacePathSeparator) + path = path.Replace ('/', pathSeparatorChar); - return Path.Combine (HostPath, path); + return Path.Combine (basePath, path); } ///