diff --git a/.idea/libraries/ant.xml b/.idea/libraries/ant.xml
deleted file mode 100644
index f614c1b1066..00000000000
--- a/.idea/libraries/ant.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/extensions.xml b/.idea/libraries/extensions.xml
index fbf504ce55a..b5beaf6428e 100644
--- a/.idea/libraries/extensions.xml
+++ b/.idea/libraries/extensions.xml
@@ -6,11 +6,13 @@
+
+
diff --git a/eXist-db.iml b/eXist-db.iml
index 4665b0bb15c..475b9a704e5 100644
--- a/eXist-db.iml
+++ b/eXist-db.iml
@@ -67,7 +67,6 @@
-
diff --git a/src/org/exist/http/urlrewrite/XQueryURLRewrite.java b/src/org/exist/http/urlrewrite/XQueryURLRewrite.java
index dffcbd06950..18311d9b1e7 100644
--- a/src/org/exist/http/urlrewrite/XQueryURLRewrite.java
+++ b/src/org/exist/http/urlrewrite/XQueryURLRewrite.java
@@ -723,8 +723,11 @@ SourceInfo findSourceFromDb(final DBBroker broker, final String basePath, final
DocumentImpl controllerDoc = null;
try {
final XmldbURI locationUri = XmldbURI.xmldbUriFor(basePath);
-
- controllerDoc = findDbControllerXql(broker, locationUri, components);
+ XmldbURI resourceUri = locationUri;
+ for(final String component : components) {
+ resourceUri = resourceUri.append(component);
+ }
+ controllerDoc = findDbControllerXql(broker, locationUri, resourceUri);
if (controllerDoc == null) {
LOG.warn("XQueryURLRewrite controller could not be found for path: " + path);
@@ -757,32 +760,35 @@ SourceInfo findSourceFromDb(final DBBroker broker, final String basePath, final
/**
* Finds a `controller.xql` file within a Collection hierarchy.
* Most specific collections are considered first.
- *
+ *
* For example, given the collectionUri `/db/apps`
- * and the pathPomponents `['myapp', 'data']`, the
+ * and the resourceUri /db/apps/myapp/data, the
* order or search will be:
- *
- * /db/apps/myapp/data/collection.xconf
- * /db/apps/myapp/collection.xconf
- * /db/apps/collection.xconf
+ *
+ * /db/apps/myapp/data/controller.xql
+ * /db/apps/myapp/controller.xql
+ * /db/apps/controller.xql
*
* @param broker The database broker
* @param collectionUri The root collection URI, below which we should not descend
- * @param pathComponents The path within the collectionUri to the most specific Collection
+ * @param resourceUri The path to the most specific document or collection for which we should find a controller
* @return The most relevant controller.xql document (with a READ_LOCK), or null if it could not be found.
*/
//@tailrec
private @Nullable
- DocumentImpl findDbControllerXql(final DBBroker broker, final XmldbURI collectionUri, final String[] pathComponents) {
+ DocumentImpl findDbControllerXql(final DBBroker broker, final XmldbURI collectionUri, final XmldbURI resourceUri) {
+ if (collectionUri.compareTo(resourceUri) > 0) {
+ return null;
+ }
+
Collection collection = null;
try {
- collection = broker.openCollection(collectionUri, LockMode.READ_LOCK);
- if (collection == null) {
- return null;
- }
-
- if (pathComponents.length == 0 || !collection.hasChildCollection(broker, XmldbURI.createInternal(pathComponents[0]))) {
- return collection.getDocumentWithLock(broker, XQUERY_CONTROLLER_URI, LockMode.READ_LOCK);
+ collection = broker.openCollection(resourceUri, LockMode.READ_LOCK);
+ if (collection != null) {
+ final DocumentImpl doc = collection.getDocumentWithLock(broker, XQUERY_CONTROLLER_URI, LockMode.READ_LOCK);
+ if (doc != null) {
+ return doc;
+ }
}
} catch (final PermissionDeniedException e) {
if (LOG.isDebugEnabled()) {
@@ -800,12 +806,12 @@ DocumentImpl findDbControllerXql(final DBBroker broker, final XmldbURI collectio
}
}
- final XmldbURI subCollectionUri = collectionUri.append(pathComponents[0]);
- final String[] subPathComponents = new String[pathComponents.length - 1];
- if (subPathComponents.length > 0) {
- System.arraycopy(pathComponents, 1, subPathComponents, 0, subPathComponents.length);
+ if(resourceUri.numSegments() == 2) {
+ return null;
}
- return findDbControllerXql(broker, subCollectionUri, subPathComponents);
+ final XmldbURI subResourceUri = resourceUri.removeLastSegment();
+
+ return findDbControllerXql(broker, collectionUri, subResourceUri);
}
private SourceInfo findSourceFromFs(final String basePath, final String[] components) {
diff --git a/src/org/exist/jetty/JettyStart.java b/src/org/exist/jetty/JettyStart.java
index e29a4861f6b..e6c24551e1f 100644
--- a/src/org/exist/jetty/JettyStart.java
+++ b/src/org/exist/jetty/JettyStart.java
@@ -101,6 +101,10 @@ public JettyStart() {
}
public synchronized void run() {
+ run(true);
+ }
+
+ public synchronized void run(final boolean standalone) {
final String jettyProperty = Optional.ofNullable(System.getProperty(JETTY_HOME_PROP))
.orElseGet(() -> {
final Optional home = ConfigurationHelper.getExistHome();
@@ -110,8 +114,13 @@ public synchronized void run() {
return jettyPath;
});
- final Path standaloneFile = Paths.get(jettyProperty).resolve("etc").resolve(Main.STANDALONE_ENABLED_JETTY_CONFIGS);
- run(new String[] { standaloneFile.toAbsolutePath().toString() }, null);
+ final Path jettyConfig;
+ if (standalone) {
+ jettyConfig = Paths.get(jettyProperty).resolve("etc").resolve(Main.STANDALONE_ENABLED_JETTY_CONFIGS);
+ } else {
+ jettyConfig = Paths.get(jettyProperty).resolve("etc").resolve(Main.STANDARD_ENABLED_JETTY_CONFIGS);
+ }
+ run(new String[] { jettyConfig.toAbsolutePath().toString() }, null);
}
public synchronized void run(final String[] args, final Observer observer) {
diff --git a/test/src/org/exist/http/urlrewrite/URLRewritingTest.java b/test/src/org/exist/http/urlrewrite/URLRewritingTest.java
new file mode 100644
index 00000000000..4b61eaad65f
--- /dev/null
+++ b/test/src/org/exist/http/urlrewrite/URLRewritingTest.java
@@ -0,0 +1,114 @@
+/*
+ * eXist Open Source Native XML Database
+ * Copyright (C) 2001-2018 The eXist Project
+ * http://exist-db.org
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.exist.http.urlrewrite;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.fluent.Executor;
+import org.apache.http.client.fluent.Request;
+import org.apache.http.entity.ContentType;
+import org.exist.TestUtils;
+import org.exist.test.ExistWebServer;
+import org.exist.util.io.FastByteArrayOutputStream;
+import org.exist.xmldb.XmldbURI;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.exist.http.urlrewrite.XQueryURLRewrite.XQUERY_CONTROLLER_FILENAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class URLRewritingTest {
+
+ private static final XmldbURI TEST_COLLECTION_NAME = XmldbURI.create("controller-test");
+ private static final XmldbURI TEST_COLLECTION = XmldbURI.create("/db/apps").append(TEST_COLLECTION_NAME);
+
+ private static final String TEST_CONTROLLER = "xquery version \"3.1\";\n{fn:current-dateTime()}";
+ private static Executor executor = null;
+
+ @ClassRule
+ public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true, false);
+
+ @Test
+ public void findsParentController() throws IOException {
+ final XmldbURI nestedCollectionName = XmldbURI.create("nested");
+ final XmldbURI docName = XmldbURI.create("test.xml");
+ final String testDocument = "world";
+
+ final String storeDocUri = getRestUri() + TEST_COLLECTION.append(nestedCollectionName).append(docName);
+ HttpResponse response = executor.execute(Request
+ .Put(storeDocUri)
+ .bodyString(testDocument, ContentType.APPLICATION_XML)
+ ).returnResponse();
+ assertEquals(HttpStatus.SC_CREATED, response.getStatusLine().getStatusCode());
+
+ final String retrieveDocUri = getAppsUri() + "/" + TEST_COLLECTION_NAME.append(nestedCollectionName).append(docName);
+ response = executor.execute(Request
+ .Get(retrieveDocUri)
+ ).returnResponse();
+ assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+ final String responseBody;
+ try (final FastByteArrayOutputStream baos = new FastByteArrayOutputStream((int)response.getEntity().getContentLength())) {
+ response.getEntity().writeTo(baos);
+ responseBody = baos.toString(UTF_8);
+ }
+ assertTrue(responseBody.matches(".+"));
+ }
+
+ @BeforeClass
+ public static void setup() throws IOException {
+ executor = Executor.newInstance()
+ .auth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)
+ .authPreemptive("localhost");
+
+ final HttpResponse response = executor.execute(Request
+ .Put(getRestUri() + TEST_COLLECTION + "/" + XQUERY_CONTROLLER_FILENAME)
+ .bodyString(TEST_CONTROLLER, ContentType.create("application/xquery"))
+ ).returnResponse();
+ assertEquals(HttpStatus.SC_CREATED, response.getStatusLine().getStatusCode());
+ }
+
+ @AfterClass
+ public static void cleanup() throws IOException {
+
+ final HttpResponse response = executor.execute(Request
+ .Delete(getRestUri() + TEST_COLLECTION)
+ ).returnResponse();
+ assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+ }
+
+ private static String getServerUri() {
+ return "http://localhost:" + existWebServer.getPort() + "/exist";
+ }
+
+ private static String getRestUri() {
+ return getServerUri() + "/rest";
+ }
+
+ private static String getAppsUri() {
+ return getServerUri() + "/apps";
+ }
+}
diff --git a/test/src/org/exist/test/ExistWebServer.java b/test/src/org/exist/test/ExistWebServer.java
index 1c37febfbb5..2aed2273921 100644
--- a/test/src/org/exist/test/ExistWebServer.java
+++ b/test/src/org/exist/test/ExistWebServer.java
@@ -39,6 +39,7 @@ public class ExistWebServer extends ExternalResource {
private final boolean disableAutoDeploy;
private final boolean useTemporaryStorage;
private Optional temporaryStorage = Optional.empty();
+ private final boolean jettyStandaloneMode;
public ExistWebServer() {
this(false);
@@ -57,10 +58,15 @@ public ExistWebServer(final boolean useRandomPort, final boolean cleanupDbOnShut
}
public ExistWebServer(final boolean useRandomPort, final boolean cleanupDbOnShutdown, final boolean disableAutoDeploy, final boolean useTemporaryStorage) {
+ this(useRandomPort, cleanupDbOnShutdown, disableAutoDeploy, useTemporaryStorage, true);
+ }
+
+ public ExistWebServer(final boolean useRandomPort, final boolean cleanupDbOnShutdown, final boolean disableAutoDeploy, final boolean useTemporaryStorage, final boolean jettyStandaloneMode) {
this.useRandomPort = useRandomPort;
this.cleanupDbOnShutdown = cleanupDbOnShutdown;
this.disableAutoDeploy = disableAutoDeploy;
this.useTemporaryStorage = useTemporaryStorage;
+ this.jettyStandaloneMode = jettyStandaloneMode;
}
public final int getPort() {
@@ -94,7 +100,7 @@ protected void before() throws Throwable {
System.setProperty(PROP_JETTY_SSL_PORT, Integer.toString(nextFreePort(MIN_RANDOM_PORT, MAX_RANDOM_PORT)));
server = new JettyStart();
- server.run();
+ server.run(jettyStandaloneMode);
}
} else {
server = new JettyStart();