Index: src/main/java/com/xpn/xwiki/api/XWiki.java
===================================================================
--- src/main/java/com/xpn/xwiki/api/XWiki.java	(revision 12955)
+++ src/main/java/com/xpn/xwiki/api/XWiki.java	(working copy)
@@ -2606,4 +2606,50 @@
     {
         return this.criteriaService;
     }
+
+    /**
+     * API to get the Servlet path for the wiki 'database'
+     * In mono wiki this is "bin/" or "xwiki/"
+     * In multi wiki this is "subwiki/wiki_wikiname/"
+     * In can be configured in xwiki.cfg with the config xwiki.servletpath and xwiki.defaultservletpath
+     * It also has to be changed ina web.xml
+     * @param database wiki for which to get the path
+     * @return The servlet path
+     */
+    public String getServletPath(String database) {
+        return xwiki.getServletPath(database, context);
+    }
+      /**
+     * API to get the webapp path for the wiki 'database'
+     * This usually is "xwiki/"
+     * In can be configured in xwiki.cfg with the config xwiki.webapppath
+     * It also has to be changed ina web.xml
+     * @param database wiki for which to get the path
+     * @return The servlet path
+     */
+    public String getWebAppPath(String database) {
+        return xwiki.getWebAppPath(database, context);
+    }
+
+     /**
+     * API to get the Servlet path for the curriki wiki
+     * In mono wiki this is "bin/" or "xwiki/"
+     * In multi wiki this is "subwiki/wiki_wikiname/"
+     * In can be configured in xwiki.cfg with the config xwiki.servletpath and xwiki.defaultservletpath
+     * It also has to be changed ina web.xml
+     * @return The servlet path
+     */
+    public String getServletPath() {
+        return xwiki.getServletPath(context.getDatabase(), context);
+    }
+      /**
+     * API to get the webapp path for the current wiki
+     * This usually is "xwiki/"
+     * In can be configured in xwiki.cfg with the config xwiki.webapppath
+     * It also has to be changed ina web.xml
+     * @return The servlet path
+     */
+    public String getWebAppPath() {
+        return xwiki.getWebAppPath(context.getDatabase(), context);
+    }
 }
Index: src/main/java/com/xpn/xwiki/XWiki.java
===================================================================
--- src/main/java/com/xpn/xwiki/XWiki.java	(revision 12955)
+++ src/main/java/com/xpn/xwiki/XWiki.java	(working copy)
@@ -385,47 +385,54 @@
         if (xwiki.isVirtualMode()) {
             XWikiRequest request = context.getRequest();
             String host = "";
+            String originalHost = "";
             try {
                 URL requestURL = context.getURL();
-                host = requestURL.getHost();
+                if (LOG.isDebugEnabled())
+                 LOG.debug("Request url is: " + requestURL.toString());
+                originalHost = host = requestURL.getHost();
             } catch (Exception e) {
             }
 
+            // we will use an element of the path to get the host
+            // This only happens if the url is in the form contains /xwiki/wiki_wikiname/
+            if ("1".equals(xwiki.Param("xwiki.virtual.usepath", "0"))) {
+                String uri = request.getRequestURI();
+                if (LOG.isDebugEnabled())
+                    LOG.debug("Request uri is: " + uri);
+                int vhi1 = uri.indexOf("/", 1);
+                int vhi2 = uri.indexOf("/", vhi1 + 1);
+                int vhi3 = uri.indexOf("/", vhi2 + 1);
+                String subwiki = uri.substring(vhi1+1, vhi2);
+                String virtualHost = uri.substring(vhi2+1, vhi3);
+                if (subwiki.equals("subwiki"))
+                    host = virtualHost.substring(5);
+            }
+
             if (host.equals("")) {
                 return xwiki;
             }
 
+            if (LOG.isDebugEnabled())
+                LOG.debug("Host is: " + host);
             String appname = xwiki.findWikiServer(host, context);
+            if (LOG.isDebugEnabled())
+                LOG.debug("appname is: " + appname);
 
             if (appname == null) {
-                String uri = request.getRequestURI();
-                int i1 = host.indexOf(".");
-                String servername = (i1 != -1) ? host.substring(0, i1) : host;
-
-                XWikiURLFactory urlf = context.getURLFactory();
-                if ((urlf != null) && (urlf instanceof XWikiServletURLFactory)
-                    && ("".equals(((XWikiServletURLFactory) urlf).getContextPath()))) {
-                    appname = context.getMainXWiki();
+                // As a convenience, allow sites starting with www, localhost or using an
+                // IP address not to have to create a XWikiServerXwiki page since we consider
+                // in that case that they're pointing to the main wiki.
+                if ((originalHost.startsWith("www."))
+                        || (originalHost.equals("localhost") || (context.getUtil().match(
+                        "m|[0-9]+\\.|[0-9]+\\.[0-9]+\\.[0-9]|", originalHost)))) {
+                    if (LOG.isDebugEnabled())
+                        LOG.debug("Fallback to default wiki");
+                    return xwiki;
                 } else {
-                    appname = uri.substring(1, uri.indexOf("/", 2));
+                    throw new XWikiException(XWikiException.MODULE_XWIKI, XWikiException.ERROR_XWIKI_DOES_NOT_EXIST,
+                            "The wiki " + host + " does not exist");
                 }
-
-                if ("0".equals(xwiki.Param("xwiki.virtual.autowww"))) {
-                    appname = servername;
-                } else {
-                    // As a convenience, allow sites starting with www, localhost or using an
-                    // IP address not to have to create a XWikiServerXwiki page since we consider
-                    // in that case that they're pointing to the main wiki.
-                    if ((servername.equals("www"))
-                        || (host.equals("localhost") || (context.getUtil().match(
-                            "m|[0-9]+\\.|[0-9]+\\.[0-9]+\\.[0-9]|", host)))) {
-                        if (appname.equals("xwiki")) {
-                            return xwiki;
-                        }
-                    } else {
-                        appname = servername;
-                    }
-                }
             }
 
             synchronized (appname) {
@@ -4087,7 +4094,7 @@
                 return -4;
             }
 
-            String wikiServerPage = "XWikiServer" + wikiName.substring(0, 1).toUpperCase() + wikiName.substring(1);
+            String wikiServerPage = getServerWikiPage(wikiName);
             // Verify is server page already exist
             XWikiDocument serverdoc = getDocument("XWiki", wikiServerPage, context);
             if (serverdoc.isNew()) {
@@ -4188,12 +4195,18 @@
     public URL getServerURL(String database, XWikiContext context) throws MalformedURLException
     {
         String serverurl = null;
+
+        // In virtual wiki path mode the server is the standard one
+        if ("1".equals(Param("xwiki.virtual.usepath", "0"))) {
+           return null;
+        }
+        
         if (database != null) {
             String db = context.getDatabase();
             try {
                 context.setDatabase(getDatabase());
                 XWikiDocument doc =
-                    getDocument("XWiki.XWikiServer" + database.substring(0, 1).toUpperCase() + database.substring(1),
+                    getDocument(getServerWikiPage(database),
                         context);
                 BaseObject serverobject = doc.getObject("XWiki.XWikiServerClass");
                 if (serverobject != null) {
@@ -4229,6 +4242,69 @@
         }
     }
 
+    public String getServletPath(String database, XWikiContext context)
+    {
+        // unless we are in virtual wiki path mode we should return null
+        if (!database.equals(getDatabase()) && "1".equals(Param("xwiki.virtual.usepath", "0"))) {
+            if (database != null) {
+                String db = context.getDatabase();
+                try {
+                    context.setDatabase(getDatabase());
+                    XWikiDocument doc =
+                            getDocument(getServerWikiPage(database),
+                                    context);
+                    BaseObject serverobject = doc.getObject("XWiki.XWikiServerClass");
+                    if (serverobject != null) {
+                        String server = serverobject.getStringValue("server");
+                        if ((server != null) && !server.equals("localhost")) {
+                            int i1 = server.indexOf(".");
+                            server = (i1==-1) ? server : server.substring(0, i1);
+                            return "subwiki/wiki_" + server + "/";
+                        }
+                    }
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                } finally {
+                    context.setDatabase(db);
+                }
+            }
+        }
+
+        String currentServletpath = context.getRequest().getServletPath();
+        String servletPath = Param("xwiki.servletpath", "");
+        if (servletPath.equals("")) {
+            if (currentServletpath.startsWith("/bin")) {
+                servletPath = "bin/";
+            } else if (context.getRequest().getServletPath().startsWith("/testbin")) {
+                servletPath = "testbin/";
+            } else {
+                servletPath = Param("xwiki.defaultservletpath", "bin/");
+            }
+        }
+
+        return servletPath;
+    }
+
+    public String getWebAppPath(String database, XWikiContext context) {
+        String path = context.getURL().getPath();
+        String contextPath = Param("xwiki.webapppath", "");
+        if (contextPath.equals("")) {
+            try {
+                contextPath = context.getRequest().getContextPath();
+                // TODO We're using URL parts in a wrong way, since contextPath and servletPath are
+                // returned with a leading /, while we need a trailing /. This code moves the / from
+                // the beginning to the end.
+                // If the app is deployed as the ROOT ap, then there's no need to move the /.
+                if (contextPath.length() > 0) {
+                    contextPath = contextPath.substring(1) + "/";
+                }
+            } catch (Exception e) {
+                contextPath = path.substring(0, path.indexOf('/', 1) + 1);
+            }
+        }
+        return contextPath;
+    }
+
     public String getURL(String fullname, String action, XWikiContext context) throws XWikiException
     {
         XWikiDocument doc = new XWikiDocument();
@@ -4381,18 +4457,26 @@
                 // pass to it using the following algorithm:
                 // path info = requestURI - (contextPath + servletPath)
                 String path;
-                if (!request.getRequestURI().startsWith(request.getContextPath() + request.getServletPath())) {
+                String webapppath = getWebAppPath(context.getDatabase(), context);
+                String servletpath = getServletPath(context.getDatabase(), context);
+
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Request URI: " + request.getRequestURI());
+                    LOG.debug("Webapp path: " + webapppath);
+                    LOG.debug("Servlet path: " + servletpath);
+                }
+
+                if (!request.getRequestURI().startsWith("/" + webapppath + servletpath)) {
                     LOG.warn("Request URI [" + request.getRequestURI() + "] should have matched " + "context path ["
-                        + request.getContextPath() + "] and servlet path [" + request.getServletPath() + "]");
+                        + webapppath + "] and servlet path [" + servletpath + "]");
                     // Even though this branch shouldn't get executed we never know what containers
                     // will return and thus in order to be safe we fall back to the previous
                     // behavior which was to use getPathInfo() for getting the path (with the
                     // potential issue with i18n encoding as stated above).
                     path = request.getPathInfo();
                 } else {
-                    path =
-                        request.getRequestURI().substring(
-                            request.getContextPath().length() + request.getServletPath().length());
+                    // we need to get rid of /xwiki/bin/ or /xwiki/subwiki/wiki_wikiname/ in case of a XEM in usepath mode
+                    path = request.getRequestURI().substring(webapppath.length() + servletpath.length());
                 }
 
                 // Fix error in some containers, which don't hide the jsessionid parameter from the
Index: src/main/java/com/xpn/xwiki/web/XWikiDebugGWTURLFactory.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/XWikiDebugGWTURLFactory.java	(revision 12955)
+++ src/main/java/com/xpn/xwiki/web/XWikiDebugGWTURLFactory.java	(working copy)
@@ -11,10 +11,8 @@
     public void init(XWikiContext context) {
         URL url = context.getURL();
 
-        contextPath = "/xwiki/";
-
-        servletPath = "bin/";
-
+        contextPath = "xwiki/";
+        
         try {
             serverURL = new URL(url.getProtocol(), url.getHost(), 1025, "/");
         } catch (MalformedURLException e) {
Index: src/main/java/com/xpn/xwiki/web/XWikiServletURLFactory.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/XWikiServletURLFactory.java	(revision 12955)
+++ src/main/java/com/xpn/xwiki/web/XWikiServletURLFactory.java	(working copy)
@@ -46,8 +46,6 @@
 
     protected String contextPath;
 
-    protected String servletPath;
-
     public XWikiServletURLFactory()
     {
     }
@@ -57,7 +55,6 @@
     {
         this.serverURL = serverURL;
         this.contextPath = servletPath;
-        this.servletPath = actionPath;
     }
 
     // Used by tests
@@ -73,37 +70,9 @@
             // Cannot initialize, probably running tests...
             return;
         }
-        String path = url.getPath();
-        String servletpath = context.getRequest().getServletPath();
 
-        contextPath =
-            (context.getWiki() == null) ? "" : context.getWiki().Param("xwiki.servletpath", "");
-        if (contextPath.equals("")) {
-            try {
-                contextPath = context.getRequest().getContextPath();
-                // TODO We're using URL parts in a wrong way, since contextPath and servletPath are
-                // returned with a leading /, while we need a trailing /. This code moves the / from
-                // the beginning to the end.
-                // If the app is deployed as the ROOT ap, then there's no need to move the /.
-                if (contextPath.length() > 0) {
-                    contextPath = contextPath.substring(1) + "/";
-                }
-            } catch (Exception e) {
-                contextPath = path.substring(0, path.indexOf('/', 1) + 1);
-            }
-        }
-
-        servletPath = context.getWiki().Param("xwiki.actionpath", "");
-        if (servletPath.equals("")) {
-            if (servletpath.startsWith("/bin")) {
-                servletPath = "bin/";
-            } else if (context.getRequest().getServletPath().startsWith("/testbin")) {
-                servletPath = "testbin/";
-            } else {
-                servletPath = context.getWiki().Param("xwiki.defaultactionpath", "bin/");
-            }
-        }
-
+        contextPath = context.getWiki().getWebAppPath(context.getDatabase(), context);
+        
         try {
             serverURL = new URL(url, "/");
         } catch (MalformedURLException e) {
@@ -122,18 +91,6 @@
         return contextPath;
     }
 
-    /**
-     * Returns the part of the URL identifying the servlet inside the web application, which is the
-     * Struts mapping name. In a normal install, that is <tt>bin/</tt>. Other usual values are
-     * <tt>xwiki/</tt> and <tt>testbin/</tt>.
-     * 
-     * @return The servlet path corresponding to the current request.
-     */
-    public String getServletPath()
-    {
-        return servletPath;
-    }
-
     private URL getServerURL(XWikiContext context) throws MalformedURLException
     {
         return getServerURL(context.getDatabase(), context);
@@ -194,7 +151,7 @@
         }
 
         StringBuffer newpath = new StringBuffer(contextPath);
-        newpath.append(servletPath);
+        addServletPath(newpath, xwikidb, context);
 
         addAction(newpath, action, context);
         addSpace(newpath, web, action, context);
@@ -219,6 +176,15 @@
         }
     }
 
+    private void addServletPath(StringBuffer newpath, String xwikidb, XWikiContext context)
+    {
+        if (xwikidb==null)
+            xwikidb = context.getDatabase();
+
+        String spath = context.getWiki().getServletPath(xwikidb, context);
+        newpath.append(spath);
+    }
+
     private void addAction(StringBuffer newpath, String action, XWikiContext context)
     {
         boolean showViewAction = context.getWiki().showViewAction(context);
@@ -294,7 +260,7 @@
         XWikiContext context)
     {
         StringBuffer newpath = new StringBuffer(contextPath);
-        newpath.append(servletPath);
+        addServletPath(newpath, xwikidb, context);
         addAction(newpath, "skin", context);
         addSpace(newpath, web, "skin", context);
         addName(newpath, name, "skin", context);
@@ -344,7 +310,7 @@
         }
 
         StringBuffer newpath = new StringBuffer(contextPath);
-        newpath.append(servletPath);
+        addServletPath(newpath, xwikidb, context);
         addAction(newpath, action, context);
         addSpace(newpath, web, action, context);
         addName(newpath, name, action, context);
@@ -374,7 +340,7 @@
     {
         String action = "downloadrev";
         StringBuffer newpath = new StringBuffer(contextPath);
-        newpath.append(servletPath);
+        addServletPath(newpath, xwikidb, context);
         addAction(newpath, action, context);
         addSpace(newpath, web, action, context);
         addName(newpath, name, action, context);
Index: src/main/java/com/xpn/xwiki/web/XWikiPortletURLFactory.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/XWikiPortletURLFactory.java	(revision 12955)
+++ src/main/java/com/xpn/xwiki/web/XWikiPortletURLFactory.java	(working copy)
@@ -42,7 +42,6 @@
         }
 
         contextPath = "xwiki/";
-        servletPath = "bin/";
     }
 
     public URL createAttachmentURL(String filename, String web, String name, String action, String xwikidb, XWikiContext context) {
Index: src/main/java/com/xpn/xwiki/web/XWikiRequestProcessor.java
===================================================================
--- src/main/java/com/xpn/xwiki/web/XWikiRequestProcessor.java	(revision 12955)
+++ src/main/java/com/xpn/xwiki/web/XWikiRequestProcessor.java	(working copy)
@@ -34,6 +34,11 @@
         HttpServletResponse httpServletResponse) throws IOException
     {
         String result = super.processPath(httpServletRequest, httpServletResponse);
+
+        if (result.startsWith("/wiki_")) {
+          result = result.substring(result.indexOf("/", 1));           
+        }
+
         if (StringUtils.countMatches(result, "/") <= 2) {
             if (result.startsWith("/xmlrpc/")) {
                 return "/xmlrpc/";
