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);
}
///