diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 22c86b8c21d..a048222f89b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -105,12 +105,6 @@ updates: update-types: - patch - minor - milton-webdav: - patterns: - - "org.exist-db.thirdparty.com.ettrema:*" - update-types: - - patch - - minor maven-plugins-apache: patterns: - "org.apache.maven.plugins:*" diff --git a/BUILD.md b/BUILD.md index 77f7e9ff6a6..bfce2c4d370 100644 --- a/BUILD.md +++ b/BUILD.md @@ -28,15 +28,58 @@ Useful build switches: Maven resolves dependencies from these repositories (defined in `exist-parent/pom.xml`): - **Releases:** Maven Central (direct) → exist-db proxy → exist-db → evolved-binary (all public) -- **Snapshots:** GitHub Packages (exist, exist-xqts-runner) → exist-db-snapshots → evolved-binary-snapshots - -### GitHub Packages (authentication for SNAPSHOT builds) +- **GitHub Packages (releases):** `jackrabbit-webdav-jakarta` — transformed Jackrabbit WebDAV JAR used by `exist-webdav` ([PR #6364](https://github.com/eXist-db/exist/pull/6364)) +- **Snapshots:** GitHub Packages (`exist`, `exist-xqts-runner`) → exist-db-snapshots → evolved-binary-snapshots + +### GitHub Packages (authentication) + +Some artifacts are hosted on GitHub Packages under the `eXist-db` org. GitHub requires authentication; without it Maven reports **401 Unauthorized**. + +| Server id in `settings.xml` | Repository | Used for | +|-----------------------------|------------|----------| +| `github` | `eXist-db/exist` | eXist SNAPSHOT builds published to GitHub Packages | +| `github-xqts-runner` | `eXist-db/exist-xqts-runner` | `exist-xqts` conformance runner (SNAPSHOT) | +| `github-jackrabbit-webdav-jakarta` | `eXist-db/jackrabbit-webdav-jakarta` | `jackrabbit-webdav` compile dependency in `exist-webdav` | + +Maven matches credentials by **repository id**: the `` in each `` block in `exist-parent/pom.xml` must match a `` in `~/.m2/settings.xml`. A PAT configured only as `github` is **not** applied to the other two repos. + +**Option 1 – Skip modules that need GitHub Packages** (no auth needed): + +- XQTS: `mvn -DskipTests package -pl '!exist-xqts'` +- WebDAV tests: `mvn -DskipTests package -pl '!exist-webdav'` (or skip tests only: `-Dtest=!* -pl exist-webdav` is not ideal; prefer `-pl '!exist-webdav'` for compile-only) + +**Option 2 – Configure GitHub auth** (full build including `exist-webdav` and `exist-xqts`): add a GitHub PAT with **`read:packages`** (and org access to `eXist-db` packages) to `~/.m2/settings.xml`. Use the same token for all three server entries; only the `` differs. See `.github/actions/maven-github-settings/action.yml` for the canonical format: + +```xml + + + github + YOUR_GITHUB_USERNAME + YOUR_GITHUB_PAT + + + github-xqts-runner + YOUR_GITHUB_USERNAME + YOUR_GITHUB_PAT + + + github-jackrabbit-webdav-jakarta + YOUR_GITHUB_USERNAME + YOUR_GITHUB_PAT + + +``` -When building from `develop` (or any SNAPSHOT version), Maven resolves `exist-xqts-runner` from `https://maven.pkg.github.com/eXist-db/exist-xqts-runner`. GitHub Packages requires authentication; without it you get **401 Unauthorized**. +If a previous resolve failed with 401, Maven may cache the failure as `*.lastUpdated` under `~/.m2/repository/`. After fixing `settings.xml`, delete that artifact directory or add `-U` on the next build. -**Option 1 – Exclude XQTS** (no auth needed): use `mvn -DskipTests package -pl '!exist-xqts'` to skip the XQTS module. +Example: verify Jackrabbit resolves after configuring auth: -**Option 2 – Configure GitHub auth** (if you need XQTS or a full build): add a GitHub PAT to `~/.m2/settings.xml` as server `github-xqts-runner` (and optionally `github` for eXist snapshots). See `.github/actions/maven-github-settings/action.yml` for the expected `` format. +```bash +rm -rf ~/.m2/repository/org/exist-db/thirdparty/org/apache/jackrabbit/jackrabbit-webdav/2.22.3-jakarta-ee10 +mvn dependency:get \ + -Dartifact=org.exist-db.thirdparty.org.apache.jackrabbit:jackrabbit-webdav:2.22.3-jakarta-ee10 \ + -U -Ddependency-check.skip=true +``` Further build options can be found at: [eXist-db Build Documentation](http://www.exist-db.org/exist/apps/doc/exist-building.xml "How to build eXist") and on the workflow files of this repo. @@ -47,6 +90,7 @@ From the repo root: - **All tests:** `mvn -V -B verify -Ddependency-check.skip -Dlicense.skip` - **exist-core only:** add `--projects exist-core --also-make` to the above - **Single test class:** `mvn -Dtest=fully.qualified.TestClass test --projects exist-core --also-make` +- **WebDAV round-trip tests:** `mvn test -pl extensions/webdav --also-make -Dtest=org.exist.webdav.WebDavRoundTripTest -Dsurefire.failIfNoSpecifiedTests=false` (requires `github-jackrabbit-webdav-jakarta` auth; litmus compliance runs in Docker CI) **NOTE:** In the above example, we switched the current (checked-out) branch from `develop` to `master`. We use the [GitFlow for eXist-db](#contributing-to-exist) process: diff --git a/exist-core/pom.xml b/exist-core/pom.xml index ea95cece914..edff104cf1c 100644 --- a/exist-core/pom.xml +++ b/exist-core/pom.xml @@ -576,8 +576,8 @@ test - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 test @@ -642,18 +642,13 @@ test - org.apache.httpcomponents - httpcore + org.apache.httpcomponents.core5 + httpcore5 test - org.apache.httpcomponents - httpmime - test - - - org.apache.httpcomponents - fluent-hc + org.apache.httpcomponents.client5 + httpclient5-fluent test @@ -1163,6 +1158,18 @@ The BaseX Team. The original license statement is also included below.]]> + + org.apache.maven.plugins + maven-jar-plugin + + + + test-jar + + + + + org.apache.maven.plugins maven-surefire-plugin diff --git a/exist-core/src/test/java/org/exist/dom/persistent/CDataIntergationTest.java b/exist-core/src/test/java/org/exist/dom/persistent/CDataIntergationTest.java index ceae9bae169..78f58c35e5b 100644 --- a/exist-core/src/test/java/org/exist/dom/persistent/CDataIntergationTest.java +++ b/exist-core/src/test/java/org/exist/dom/persistent/CDataIntergationTest.java @@ -22,13 +22,11 @@ package org.exist.dom.persistent; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.fluent.Executor; -import org.apache.http.client.fluent.Request; +import org.apache.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; import org.exist.TestUtils; +import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; -import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.exist.xmldb.DatabaseImpl; import org.exist.xmldb.XmldbURI; import org.junit.ClassRule; @@ -44,14 +42,15 @@ import java.io.IOException; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.http.HttpStatus.SC_CREATED; +import static org.apache.hc.core5.http.HttpStatus.SC_CREATED; +import static org.apache.hc.core5.http.HttpStatus.SC_OK; import static org.junit.Assert.*; /** * Tests for retrieving a document containing CDATA via * various APIs. */ -public class CDataIntergationTest { +public class CDataIntergationTest extends AbstractHttpTest { @ClassRule public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); @@ -67,29 +66,21 @@ public void cdataRestApi() throws IOException { final String uri = "http://localhost:" + existWebServer.getPort() + "/exist/rest/db"; final String docUri = uri + "/rest-cdata-test.xml"; - final Executor executor = Executor - .newInstance() - .auth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD) - .authPreemptive(new HttpHost("localhost", existWebServer.getPort())); + final Executor executor = AbstractHttpTest.createAuthenticatedExecutor( + existWebServer, TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD); // store document - final HttpResponse storeResponse = executor.execute( + assertEquals(SC_CREATED, executeForStatus(executor, Request - .Put(docUri) + .put(docUri) .addHeader("Content-Type", "application/xml") .bodyByteArray(cdata_xml.getBytes(UTF_8)) - ).returnResponse(); - assertEquals(SC_CREATED, storeResponse.getStatusLine().getStatusCode()); + )); // retrieve document - final HttpResponse retrieveResponse = executor.execute( - Request - .Get(docUri) - ).returnResponse(); - try (final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) { - retrieveResponse.getEntity().writeTo(baos); - assertEquals(cdata_xml, baos.toString(UTF_8)); - } + final HttpResponseResult retrieved = executeForStatusAndBody(executor, Request.get(docUri)); + assertEquals(SC_OK, retrieved.statusCode()); + assertEquals(cdata_xml, retrieved.body()); } @Test diff --git a/exist-core/src/test/java/org/exist/http/AbstractHttpTest.java b/exist-core/src/test/java/org/exist/http/AbstractHttpTest.java index f54157e241e..2cc28070d9b 100644 --- a/exist-core/src/test/java/org/exist/http/AbstractHttpTest.java +++ b/exist-core/src/test/java/org/exist/http/AbstractHttpTest.java @@ -23,23 +23,34 @@ package org.exist.http; import com.evolvedbinary.j8fu.function.FunctionE; -import org.apache.http.HttpHost; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.CookieSpecs; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.fluent.Executor; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpHeaders; +import org.apache.hc.core5.http.HttpHost; +import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.exist.TestUtils; import org.exist.test.ExistWebServer; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +import static org.junit.Assert.assertEquals; /** * @author Adam Retter */ public abstract class AbstractHttpTest { + /** + * HTTP status and body from a single fluent request execution. + */ + public record HttpResponseResult(int statusCode, String body) { + } + /** * Get the Server URI. * @@ -73,6 +84,67 @@ protected static String getAppsUri(final ExistWebServer existWebServer) { return getServerUri(existWebServer) + "/apps"; } + /** + * Create an {@link HttpHost} for the given eXist-db Web Server. + * + * @param existWebServer the eXist-db Web Server. + * + * @return the HTTP host. + */ + public static HttpHost getHttpHost(final ExistWebServer existWebServer) { + return new HttpHost("http", "localhost", existWebServer.getPort()); + } + + private static String basicAuthorizationHeader(final String user, final String password) { + return "Basic " + Base64.getEncoder().encodeToString( + (user + ":" + password).getBytes(StandardCharsets.UTF_8)); + } + + /** + * Create an HTTP client that sends preemptive HTTP Basic authentication. + * + *

HC5's fluent {@link Executor} auth helpers do not always attach credentials to requests + * under the {@code /exist/...} context path; the request interceptor ensures the + * {@code Authorization} header is present on the first request.

+ * + * @param existWebServer the eXist-db Web Server. + * @param user the user name. + * @param password the password. + * + * @return a closable HTTP client. + */ + public static CloseableHttpClient createAuthenticatedClient( + final ExistWebServer existWebServer, + final String user, + final String password) { + final String authorizationHeader = basicAuthorizationHeader(user, password); + + return HttpClients.custom() + .addRequestInterceptorFirst((request, entity, context) -> { + if (!request.containsHeader(HttpHeaders.AUTHORIZATION)) { + request.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader); + } + }) + .disableAutomaticRetries() + .build(); + } + + /** + * Create an HTTP executor that sends preemptive HTTP Basic authentication. + * + * @param existWebServer the eXist-db Web Server. + * @param user the user name. + * @param password the password. + * + * @return an executor backed by {@link #createAuthenticatedClient(ExistWebServer, String, String)}. + */ + public static Executor createAuthenticatedExecutor( + final ExistWebServer existWebServer, + final String user, + final String password) { + return Executor.newInstance(createAuthenticatedClient(existWebServer, user, password)); + } + /** * Execute a function with a HTTP Client. * @@ -83,13 +155,9 @@ protected static String getAppsUri(final ExistWebServer existWebServer) { * * @throws IOException if an I/O error occurs */ - protected static T withHttpClient(final FunctionE fn) throws IOException { - try (final CloseableHttpClient client = HttpClientBuilder - .create() + protected static T withHttpClient(final FunctionE fn) throws IOException { + try (final CloseableHttpClient client = HttpClients.custom() .disableAutomaticRetries() - .setDefaultRequestConfig(RequestConfig.custom() - .setCookieSpec(CookieSpecs.STANDARD) - .build()) .build()) { return fn.apply(client); } @@ -107,12 +175,68 @@ protected static T withHttpClient(final FunctionE T withHttpExecutor(final ExistWebServer existWebServer, final FunctionE fn) throws IOException { - return withHttpClient(client -> { - final Executor executor = Executor - .newInstance(client) - .auth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD) - .authPreemptive(new HttpHost("localhost", existWebServer.getPort())); - return fn.apply(executor); - }); + try (final CloseableHttpClient client = createAuthenticatedClient( + existWebServer, TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)) { + return fn.apply(Executor.newInstance(client)); + } + } + + /** + * Execute a request and return its status code, closing the response. + */ + protected static int executeForStatus(final Executor executor, final Request request) throws IOException { + try (ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(request).returnResponse()) { + return response.getCode(); + } + } + + /** + * Execute a request and return its status code, closing the response. + */ + protected static int executeForStatus(final Request request) throws IOException { + try (ClassicHttpResponse response = (ClassicHttpResponse) request.execute().returnResponse()) { + return response.getCode(); + } + } + + /** + * Execute a request and return status code and body, closing the response. + */ + public static HttpResponseResult executeForStatusAndBody(final Executor executor, final Request request) + throws IOException { + try (ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(request).returnResponse()) { + return new HttpResponseResult(response.getCode(), readResponseBody(response)); + } + } + + /** + * Execute a request and return status code and body, closing the response. + */ + public static HttpResponseResult executeForStatusAndBody(final Request request) throws IOException { + try (ClassicHttpResponse response = (ClassicHttpResponse) request.execute().returnResponse()) { + return new HttpResponseResult(response.getCode(), readResponseBody(response)); + } + } + + protected static String readResponseBody(final ClassicHttpResponse response) throws IOException { + if (response.getEntity() == null) { + return ""; + } + try (UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) { + response.getEntity().writeTo(baos); + return baos.toString(StandardCharsets.UTF_8); + } + } + + /** + * Execute a fluent request and assert status and body, closing the response. + */ + public static void assertRequestResponse( + final Request request, + final int expectedStatus, + final String expectedBody) throws IOException { + final HttpResponseResult result = executeForStatusAndBody(request); + assertEquals(expectedStatus, result.statusCode()); + assertEquals(expectedBody, result.body()); } } diff --git a/exist-core/src/test/java/org/exist/http/AuthenticatedHttpClientTest.java b/exist-core/src/test/java/org/exist/http/AuthenticatedHttpClientTest.java new file mode 100644 index 00000000000..7db90e284ce --- /dev/null +++ b/exist-core/src/test/java/org/exist/http/AuthenticatedHttpClientTest.java @@ -0,0 +1,61 @@ +/* + * eXist-db Open Source Native XML Database + * Copyright (C) 2001 The eXist-db Authors + * + * info@exist-db.org + * http://www.exist-db.org + * + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.exist.http; + +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpStatus; +import org.exist.TestUtils; +import org.exist.test.ExistWebServer; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +/** + * Regression test for HTTP Basic authentication with Apache HttpClient 5. + * + *

HC5's fluent {@link org.apache.hc.client5.http.fluent.Executor} {@code authPreemptive} and + * {@code auth} helpers do not reliably attach credentials to requests routed through Jetty's + * {@code /exist/...} context path. {@link AbstractHttpTest} therefore installs a preemptive + * {@code Authorization} request interceptor on the underlying client; this test guards that + * {@link AbstractHttpTest#createAuthenticatedExecutor} still succeeds for authenticated REST access.

+ */ +public class AuthenticatedHttpClientTest extends AbstractHttpTest { + + @ClassRule + public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true, false); + + @Test + public void authenticatedRestRequestSucceeds() throws IOException { + final String url = getRestUri(existWebServer) + "/db/"; + try (ClassicHttpResponse response = (ClassicHttpResponse) createAuthenticatedExecutor( + existWebServer, TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD) + .execute(Request.get(url)) + .returnResponse()) { + assertEquals(HttpStatus.SC_OK, response.getCode()); + } + } +} diff --git a/exist-core/src/test/java/org/exist/http/PortalRedirectTest.java b/exist-core/src/test/java/org/exist/http/PortalRedirectTest.java index a54963dcde9..e48d3c26d34 100644 --- a/exist-core/src/test/java/org/exist/http/PortalRedirectTest.java +++ b/exist-core/src/test/java/org/exist/http/PortalRedirectTest.java @@ -21,10 +21,11 @@ */ package org.exist.http; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; -import org.apache.http.util.EntityUtils; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.io.entity.EntityUtils; +import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; import org.junit.ClassRule; import org.junit.Test; @@ -45,13 +46,13 @@ public class PortalRedirectTest extends AbstractHttpTest { @Test public void portalRootServesLandingPageWithExistRedirect() throws IOException { - final Request request = Request.Get(portalUri(existWebServer)); - final HttpResponse response = withHttpExecutor(existWebServer, - executor -> executor.execute(request).returnResponse()); + final Request request = Request.get(portalUri(existWebServer)); + final ClassicHttpResponse response = withHttpExecutor(existWebServer, + executor -> (ClassicHttpResponse) executor.execute(request).returnResponse()); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + assertEquals(HttpStatus.SC_OK, response.getCode()); - final String body = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); + final String body = readResponseBody(response); assertTrue("Expected portal title", body.contains("Open Source Native XML Database")); assertTrue("Expected JS redirect to /exist", body.contains("window.location.replace(\"/exist\")")); assertTrue("Expected noscript fallback link to /exist", body.contains("href=\"/exist\"")); diff --git a/exist-core/src/test/java/org/exist/http/RESTTest.java b/exist-core/src/test/java/org/exist/http/RESTTest.java index 53f950e175d..187b1e8895d 100644 --- a/exist-core/src/test/java/org/exist/http/RESTTest.java +++ b/exist-core/src/test/java/org/exist/http/RESTTest.java @@ -25,7 +25,7 @@ import org.exist.xmldb.XmldbURI; import org.junit.ClassRule; -public abstract class RESTTest { +public abstract class RESTTest extends AbstractHttpTest { @ClassRule public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); diff --git a/exist-core/src/test/java/org/exist/http/urlrewrite/ControllerTest.java b/exist-core/src/test/java/org/exist/http/urlrewrite/ControllerTest.java index 6a3945323c1..7538e3e586d 100644 --- a/exist-core/src/test/java/org/exist/http/urlrewrite/ControllerTest.java +++ b/exist-core/src/test/java/org/exist/http/urlrewrite/ControllerTest.java @@ -23,11 +23,9 @@ package org.exist.http.urlrewrite; import com.evolvedbinary.j8fu.tuple.Tuple2; -import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; import org.junit.ClassRule; @@ -95,24 +93,18 @@ public void prefersNonLegacyController() throws IOException { private void store(final String testCollectionName, final String documentMediaType, final String documentName, final String documentContent) throws IOException { final Request request = Request - .Put(getRestUri(existWebServer) + "/db/apps/" + testCollectionName + "/" + documentName) + .put(getRestUri(existWebServer) + "/db/apps/" + testCollectionName + "/" + documentName) .bodyString(documentContent, ContentType.create(documentMediaType)); - int statusCode = withHttpExecutor(existWebServer, executor -> - executor.execute(request).returnResponse().getStatusLine().getStatusCode() - ); + int statusCode = withHttpExecutor(existWebServer, executor -> executeForStatus(executor, request)); assertEquals(HttpStatus.SC_CREATED, statusCode); } private Tuple2 get(final String testCollectionName, final String documentName) throws IOException { final Request request = Request - .Get(getAppsUri(existWebServer) + "/" + testCollectionName + "/" + documentName); + .get(getAppsUri(existWebServer) + "/" + testCollectionName + "/" + documentName); final Tuple2 responseCodeAndBody = withHttpExecutor(existWebServer, executor -> { - final HttpResponse response = executor.execute(request).returnResponse(); - final int sc = response.getStatusLine().getStatusCode(); - try (final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) { - response.getEntity().writeTo(baos); - return Tuple(sc, baos.toString(UTF_8)); - } + final HttpResponseResult r = executeForStatusAndBody(executor, request); + return Tuple(r.statusCode(), r.body()); }); return responseCodeAndBody; } diff --git a/exist-core/src/test/java/org/exist/http/urlrewrite/URLRewritingTest.java b/exist-core/src/test/java/org/exist/http/urlrewrite/URLRewritingTest.java index d52ec673547..1637f682de2 100644 --- a/exist-core/src/test/java/org/exist/http/urlrewrite/URLRewritingTest.java +++ b/exist-core/src/test/java/org/exist/http/urlrewrite/URLRewritingTest.java @@ -23,13 +23,11 @@ package org.exist.http.urlrewrite; import com.evolvedbinary.j8fu.tuple.Tuple2; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; -import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.exist.xmldb.XmldbURI; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -39,7 +37,6 @@ import java.io.IOException; import static com.evolvedbinary.j8fu.tuple.Tuple.Tuple; -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; @@ -65,22 +62,17 @@ public void findsParentController() throws IOException { final String storeDocUri = getRestUri(existWebServer) + TEST_COLLECTION.append(nestedCollectionName).append(docName); final Request storeRequest = Request - .Put(storeDocUri) + .put(storeDocUri) .bodyString(testDocument, ContentType.APPLICATION_XML); - final int storeResponseStatusCode = withHttpExecutor(existWebServer, executor -> executor.execute(storeRequest).returnResponse().getStatusLine().getStatusCode()); + final int storeResponseStatusCode = withHttpExecutor(existWebServer, executor -> executeForStatus(executor, storeRequest)); assertEquals(HttpStatus.SC_CREATED, storeResponseStatusCode); final String retrieveDocUri = getAppsUri(existWebServer) + "/" + TEST_COLLECTION_NAME.append(nestedCollectionName).append(docName); final Request retrieveRequest = Request - .Get(retrieveDocUri); - final Tuple2 retrieveResponseStatusCodeAndBody = withHttpExecutor(existWebServer, executor -> { - final HttpResponse response = executor.execute(retrieveRequest).returnResponse(); - final String responseBody; - try (final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream((int)response.getEntity().getContentLength())) { - response.getEntity().writeTo(baos); - responseBody = baos.toString(UTF_8); - } - return Tuple(response.getStatusLine().getStatusCode(), responseBody); + .get(retrieveDocUri); + final Tuple2 retrieveResponseStatusCodeAndBody = withHttpExecutor(existWebServer, executor -> { + final HttpResponseResult r = executeForStatusAndBody(executor, retrieveRequest); + return Tuple(r.statusCode(), r.body()); }); assertEquals(HttpStatus.SC_OK, retrieveResponseStatusCodeAndBody._1.intValue()); assertTrue(retrieveResponseStatusCodeAndBody._2.matches(".+")); @@ -89,12 +81,10 @@ public void findsParentController() throws IOException { @BeforeClass public static void setup() throws IOException { final Request request = Request - .Put(getRestUri(existWebServer) + TEST_COLLECTION + "/" + XQUERY_CONTROLLER_FILENAME) + .put(getRestUri(existWebServer) + TEST_COLLECTION + "/" + XQUERY_CONTROLLER_FILENAME) .bodyString(TEST_CONTROLLER, ContentType.create("application/xquery")); - final int statusCode = withHttpExecutor(existWebServer, executor -> - executor.execute(request).returnResponse().getStatusLine().getStatusCode() - ); + final int statusCode = withHttpExecutor(existWebServer, executor -> executeForStatus(executor, request)); assertEquals(HttpStatus.SC_CREATED, statusCode); } @@ -102,11 +92,9 @@ public static void setup() throws IOException { @AfterClass public static void cleanup() throws IOException { final Request request = Request - .Delete(getRestUri(existWebServer) + TEST_COLLECTION); + .delete(getRestUri(existWebServer) + TEST_COLLECTION); - final int statusCode = withHttpExecutor(existWebServer, executor -> - executor.execute(request).returnResponse().getStatusLine().getStatusCode() - ); + final int statusCode = withHttpExecutor(existWebServer, executor -> executeForStatus(executor, request)); assertEquals(HttpStatus.SC_OK, statusCode); } diff --git a/exist-core/src/test/java/org/exist/management/JmxRemoteTest.java b/exist-core/src/test/java/org/exist/management/JmxRemoteTest.java index 75ed07a1bd2..94335a23899 100644 --- a/exist-core/src/test/java/org/exist/management/JmxRemoteTest.java +++ b/exist-core/src/test/java/org/exist/management/JmxRemoteTest.java @@ -24,15 +24,13 @@ import com.evolvedbinary.j8fu.function.FunctionE; import com.evolvedbinary.j8fu.tuple.Tuple2; import org.apache.commons.lang3.SystemUtils; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.HttpClient; -import org.apache.http.client.fluent.Executor; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.message.BasicHeader; +import org.apache.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.BasicHeader; +import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; import org.junit.ClassRule; import org.junit.Test; @@ -48,7 +46,7 @@ import static org.junit.Assert.assertEquals; import static org.xmlunit.matchers.HasXPathMatcher.hasXPath; -public class JmxRemoteTest { +public class JmxRemoteTest extends AbstractHttpTest { @ClassRule public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true, false); @@ -60,7 +58,7 @@ private static String getServerUri() { @Test public void checkContent() throws IOException { // Get content - final Request request = Request.Get(getServerUri()); + final Request request = Request.get(getServerUri()); final String jmxXml = withHttpExecutor(executor -> executor.execute(request).returnContent().asString()); // Prepare XPath validation @@ -102,30 +100,19 @@ public void checkContent() throws IOException { @Test public void checkBasicRequest() throws IOException { - final Request request = Request.Get(getServerUri()) + final Request request = Request.get(getServerUri()) .addHeader(new BasicHeader("Accept", ContentType.APPLICATION_XML.toString())); final Tuple2 codeAndMediaType = withHttpExecutor(executor -> { - final HttpResponse response = executor.execute(request).returnResponse(); - return Tuple(response.getStatusLine().getStatusCode(), response.getEntity().getContentType().getValue()); + try (final ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(request).returnResponse()) { + return Tuple(response.getCode(), response.getEntity().getContentType()); + } }); assertEquals(Tuple(HttpStatus.SC_OK, "application/xml"), codeAndMediaType); } - private static T withHttpClient(final FunctionE fn) throws IOException { - try (final CloseableHttpClient client = HttpClientBuilder - .create() - .disableAutomaticRetries() - .build()) { - return fn.apply(client); - } - } - private static T withHttpExecutor(final FunctionE fn) throws IOException { - return withHttpClient(client -> { - final Executor executor = Executor.newInstance(client); - return fn.apply(executor); - }); + return withHttpClient(client -> fn.apply(Executor.newInstance(client))); } } diff --git a/exist-core/src/test/java/org/exist/security/RestApiSecurityTest.java b/exist-core/src/test/java/org/exist/security/RestApiSecurityTest.java index 13efb866538..7a36b76a1f1 100644 --- a/exist-core/src/test/java/org/exist/security/RestApiSecurityTest.java +++ b/exist-core/src/test/java/org/exist/security/RestApiSecurityTest.java @@ -25,12 +25,12 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -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.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; +import org.exist.http.AbstractHttpTest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpStatus; import org.exist.test.ExistWebServer; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.junit.ClassRule; @@ -61,10 +61,10 @@ protected void removeCol(final String collectionName, final String uid, final St final Executor exec = getExecutor(uid, pwd); try { - final HttpResponse resp = exec.execute(Request.Delete(collectionUri)).returnResponse(); - - if(resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new ApiException("Could not remove collection: " + collectionUri + ". " + getResponseBody(resp.getEntity())); + try (final ClassicHttpResponse resp = (ClassicHttpResponse) exec.execute(Request.delete(collectionUri)).returnResponse()) { + if(resp.getCode() != HttpStatus.SC_OK) { + throw new ApiException("Could not remove collection: " + collectionUri + ". " + getResponseBody(resp.getEntity())); + } } } catch(final IOException ioe) { throw new ApiException(ioe); @@ -103,12 +103,12 @@ protected void addCollectionUserAce(final String collectionUri, final String use protected String getXmlResourceContent(final String resourceUri, final String uid, final String pwd) throws ApiException { final Executor exec = getExecutor(uid, pwd); try { - final HttpResponse resp = exec.execute(Request.Get(getServerUri() + resourceUri)).returnResponse(); - - if(resp.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new ApiException("Could not get XML resource from uri: " + resourceUri + ". " + getResponseBody(resp.getEntity())); - } else { - return getResponseBody(resp.getEntity()); + try (final ClassicHttpResponse resp = (ClassicHttpResponse) exec.execute(Request.get(getServerUri() + resourceUri)).returnResponse()) { + if(resp.getCode() != HttpStatus.SC_OK) { + throw new ApiException("Could not get XML resource from uri: " + resourceUri + ". " + getResponseBody(resp.getEntity())); + } else { + return getResponseBody(resp.getEntity()); + } } } catch(final IOException ioe) { throw new ApiException(ioe); @@ -139,14 +139,15 @@ protected void createGroup(final String group_gid, final String uid, final Strin protected void createXmlResource(final String resourceUri, final String content, final String uid, final String pwd) throws ApiException { final Executor exec = getExecutor(uid, pwd); try { - final HttpResponse resp = exec.execute( - Request.Put(getServerUri() + resourceUri) + try (final ClassicHttpResponse resp = (ClassicHttpResponse) exec.execute( + Request.put(getServerUri() + resourceUri) .addHeader("Content-Type", "application/xml") .bodyByteArray(content.getBytes()) - ).returnResponse(); - - if(resp.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { - throw new ApiException("Could not store XML resource to uri: " + resourceUri + ". " + getResponseBody(resp.getEntity())); + ).returnResponse()) { + + if(resp.getCode() != HttpStatus.SC_CREATED) { + throw new ApiException("Could not store XML resource to uri: " + resourceUri + ". " + getResponseBody(resp.getEntity())); + } } } catch(final IOException ioe) { throw new ApiException(ioe); @@ -157,14 +158,15 @@ protected void createXmlResource(final String resourceUri, final String content, protected void createBinResource(final String resourceUri, final byte[] content, final String uid, final String pwd) throws ApiException { final Executor exec = getExecutor(uid, pwd); try { - final HttpResponse resp = exec.execute( - Request.Put(getServerUri() + resourceUri) + try (final ClassicHttpResponse resp = (ClassicHttpResponse) exec.execute( + Request.put(getServerUri() + resourceUri) .addHeader("Content-Type", "application/octet-stream") .bodyByteArray(content) - ).returnResponse(); - - if(resp.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) { - throw new ApiException("Could not store Binary resource to uri: " + resourceUri + ". " + getResponseBody(resp.getEntity())); + ).returnResponse()) { + + if(resp.getCode() != HttpStatus.SC_CREATED) { + throw new ApiException("Could not store Binary resource to uri: " + resourceUri + ". " + getResponseBody(resp.getEntity())); + } } } catch(final IOException ioe) { throw new ApiException(ioe); @@ -175,12 +177,12 @@ private void executeQuery(final String xquery, final String uid, final String pw final Executor exec = getExecutor(uid, pwd); try { final String queryUri = createQueryUri(xquery); - - final HttpResponse resp = exec.execute(Request.Get(queryUri)).returnResponse(); - final int status = resp.getStatusLine().getStatusCode(); - if(status != HttpStatus.SC_OK) { - throw new ApiException("HTTP " + status + " could not execute query uri: " + queryUri + ". " + getResponseBody(resp.getEntity())); + try (final ClassicHttpResponse resp = (ClassicHttpResponse) exec.execute(Request.get(queryUri)).returnResponse()) { + final int status = resp.getCode(); + if(status != HttpStatus.SC_OK) { + throw new ApiException("HTTP " + status + " could not execute query uri: " + queryUri + ". " + getResponseBody(resp.getEntity())); + } } } catch(final IOException ioe) { throw new ApiException(ioe); @@ -188,7 +190,7 @@ private void executeQuery(final String xquery, final String uid, final String pw } private Executor getExecutor(final String uid, String pwd) { - return Executor.newInstance().authPreemptive(new HttpHost("localhost", existWebServer.getPort())).auth(uid, pwd); + return AbstractHttpTest.createAuthenticatedExecutor(existWebServer, uid, pwd); } private String createQueryUri(final String xquery) throws UnsupportedEncodingException { diff --git a/exist-core/src/test/java/org/exist/xmlrpc/MoveResourceTest.java b/exist-core/src/test/java/org/exist/xmlrpc/MoveResourceTest.java index 5d0dce40dad..18fa422ce5a 100644 --- a/exist-core/src/test/java/org/exist/xmlrpc/MoveResourceTest.java +++ b/exist-core/src/test/java/org/exist/xmlrpc/MoveResourceTest.java @@ -21,13 +21,13 @@ */ package org.exist.xmlrpc; -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.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpStatus; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; @@ -48,6 +48,7 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; +import org.junit.AfterClass; import org.junit.ClassRule; import org.junit.Test; @@ -74,6 +75,11 @@ public class MoveResourceTest { @ClassRule public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); + @AfterClass + public static void closeHttpConnectionManager() { + CheckThread.closeConnectionManager(); + } + private static String getXmlRpcUri() { return "http://localhost:" + existWebServer.getPort() + "/xmlrpc"; } @@ -200,6 +206,15 @@ private String readSample() throws IOException { private static class CheckThread implements Callable { private static final PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(); + + static void closeConnectionManager() { + try { + poolingHttpClientConnectionManager.close(); + } catch (final Exception ignored) { + // idempotent + } + } + private final int iterations; public CheckThread(final int iterations) { @@ -212,26 +227,26 @@ public Boolean call() throws IOException, InterruptedException { .custom() .setConnectionManager(poolingHttpClientConnectionManager) .build(); - final org.apache.http.client.fluent.Executor executor = Executor.newInstance(client); + final Executor executor = Executor.newInstance(client); final String reqUrl = getRestUri() + "/db?_query=" + URLEncoder.encode("collection('/db')//SPEECH[SPEAKER = 'JULIET']", "UTF-8"); - final Request request = Request.Get(reqUrl); + final Request request = Request.get(reqUrl); for (int i = 0; i < iterations; i++) { - HttpResponse response = null; int lastStatus = -1; for (int r = 0; r <= REST_RETRY_MAX; r++) { - response = executor.execute(request).returnResponse(); - lastStatus = response.getStatusLine().getStatusCode(); - if (lastStatus == HttpStatus.SC_OK) { - break; - } - if (lastStatus < 500 || r == REST_RETRY_MAX) { - fail("REST query failed" + (r > 0 ? " after " + r + " retries" : "") + ": " + response.getStatusLine()); + try (ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(request).returnResponse()) { + lastStatus = response.getCode(); + if (lastStatus == HttpStatus.SC_OK) { + break; + } + if (lastStatus < 500 || r == REST_RETRY_MAX) { + fail("REST query failed" + (r > 0 ? " after " + r + " retries" : "") + ": HTTP " + lastStatus); + } } Thread.sleep(REST_RETRY_DELAY_MS); } - assertEquals(response.getStatusLine().toString(), HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + assertEquals("HTTP " + lastStatus, HttpStatus.SC_OK, lastStatus); Thread.sleep(DELAY); } diff --git a/exist-core/src/test/java/org/exist/xquery/RestBinariesTest.java b/exist-core/src/test/java/org/exist/xquery/RestBinariesTest.java index 77b0b8fec33..cb75cda80a3 100644 --- a/exist-core/src/test/java/org/exist/xquery/RestBinariesTest.java +++ b/exist-core/src/test/java/org/exist/xquery/RestBinariesTest.java @@ -24,12 +24,13 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.fluent.Executor; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; +import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream; +import org.apache.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; +import org.exist.http.AbstractHttpTest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpHost; import org.exist.http.jaxb.Query; import org.exist.http.jaxb.Result; import org.exist.test.ExistWebServer; @@ -47,8 +48,8 @@ import java.io.IOException; import java.io.InputStream; -import static org.apache.http.HttpStatus.SC_CREATED; -import static org.apache.http.HttpStatus.SC_OK; +import static org.apache.hc.core5.http.HttpStatus.SC_CREATED; +import static org.apache.hc.core5.http.HttpStatus.SC_OK; import static org.exist.TestUtils.ADMIN_DB_PWD; import static org.exist.TestUtils.ADMIN_DB_USER; import static org.junit.Assert.assertArrayEquals; @@ -65,9 +66,7 @@ public class RestBinariesTest extends AbstractBinariesTest executeXQuery(final String xquery) throws Exception { - final HttpResponse response = postXquery(xquery); - final HttpEntity entity = response.getEntity(); - try(final InputStream is = entity.getContent()) { + final byte[] xmlBytes = postXqueryBody(xquery); + try (final InputStream is = new UnsynchronizedByteArrayInputStream(xmlBytes)) { final JAXBContext jaxbContext = JAXBContext.newInstance("org.exist.http.jaxb"); final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); - final Result result = (Result)unmarshaller.unmarshal(is); + final Result result = (Result) unmarshaller.unmarshal(is); return consumer -> consumer.accept(result); } } - private HttpResponse postXquery(final String xquery) throws JAXBException, IOException { + private byte[] postXqueryBody(final String xquery) throws JAXBException, IOException { final Query query = new Query(); query.setText(xquery); final JAXBContext jaxbContext = JAXBContext.newInstance("org.exist.http.jaxb"); final Marshaller marshaller = jaxbContext.createMarshaller(); - final HttpResponse response; - try(final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) { + try (final UnsynchronizedByteArrayOutputStream baos = new UnsynchronizedByteArrayOutputStream()) { marshaller.marshal(query, baos); - response = executor.execute(Request.Post(getRestUrl() + "/db/") + try (final ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(Request.post(getRestUrl() + "/db/") .bodyByteArray(baos.toByteArray(), ContentType.APPLICATION_XML) - ).returnResponse(); - } - - if(response.getStatusLine().getStatusCode() != SC_OK) { - throw new IOException("Unable to query, HTTP response code: " + response.getStatusLine().getStatusCode()); + ).returnResponse()) { + + if (response.getCode() != SC_OK) { + throw new IOException("Unable to query, HTTP response code: " + response.getCode()); + } + if (response.getEntity() == null) { + return new byte[0]; + } + try (final InputStream is = response.getEntity().getContent()) { + return is.readAllBytes(); + } + } } - - return response; } @Override diff --git a/exist-core/src/test/java/org/exist/xquery/functions/request/GetDataTest.java b/exist-core/src/test/java/org/exist/xquery/functions/request/GetDataTest.java index 8bb7f535d37..b45033dd1cf 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/request/GetDataTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/request/GetDataTest.java @@ -23,11 +23,11 @@ import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.HttpVersion; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.HttpVersion; import org.exist.xmldb.UserManagementService; import java.io.IOException; import java.io.InputStream; @@ -82,7 +82,7 @@ public static void afterClass() throws XMLDBException { @Test public void retrieveEmpty() throws IOException { - Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .addHeader("Content-Type", "application/octet-stream"); testRequest(post, wrapInElement("").getBytes()); @@ -93,12 +93,11 @@ public void retrieveEmpty() throws IOException { public void retrieveBinaryHttp09() throws IOException { final String testData = "12345"; - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_0_9) .bodyByteArray(testData.getBytes(UTF_8), ContentType.APPLICATION_OCTET_STREAM); - final HttpResponse response = post.execute().returnResponse(); - assertEquals(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED, response.getStatusLine().getStatusCode()); + assertEquals(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED, executeForStatus(post)); } @Ignore("Jetty 12 drops the connection on HTTP/1.0 without a response, causing NoHttpResponseException in Apache HttpClient") @@ -106,7 +105,7 @@ public void retrieveBinaryHttp09() throws IOException { public void retrieveBinaryHttp10() throws IOException { final String testData = "12345"; - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_1_0) .bodyByteArray(testData.getBytes(UTF_8), ContentType.APPLICATION_OCTET_STREAM); @@ -117,7 +116,7 @@ public void retrieveBinaryHttp10() throws IOException { public void retrieveBinaryHttp11() throws IOException { final String testData = "12345"; - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_1_1) .bodyByteArray(testData.getBytes(UTF_8), ContentType.APPLICATION_OCTET_STREAM); @@ -129,7 +128,7 @@ public void retrieveBinaryHttp11ChunkedTransferEncoding() throws IOException { final String testData = "12345"; try (final InputStream is = new UnsynchronizedByteArrayInputStream(testData.getBytes(UTF_8))) { - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_1_1) .bodyStream(is, ContentType.APPLICATION_OCTET_STREAM); @@ -142,12 +141,11 @@ public void retrieveBinaryHttp11ChunkedTransferEncoding() throws IOException { public void retrieveXmlHttp09() throws IOException { final String testData = "hello"; - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_0_9) .bodyByteArray(testData.getBytes(UTF_8), ContentType.TEXT_XML); - final HttpResponse response = post.execute().returnResponse(); - assertEquals(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED, response.getStatusLine().getStatusCode()); + assertEquals(HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED, executeForStatus(post)); } @Ignore("Jetty 12 drops the connection on HTTP/1.0 without a response, causing NoHttpResponseException in Apache HttpClient") @@ -155,7 +153,7 @@ public void retrieveXmlHttp09() throws IOException { public void retrieveXmlHttp10() throws IOException { final String testData = "hello"; - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_1_0) .bodyByteArray(testData.getBytes(UTF_8), ContentType.TEXT_XML); @@ -166,7 +164,7 @@ public void retrieveXmlHttp10() throws IOException { public void retrieveXmlHttp11() throws IOException { final String testData = "hello"; - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_1_1) .bodyByteArray(testData.getBytes(UTF_8), ContentType.TEXT_XML); @@ -178,7 +176,7 @@ public void retrieveXmlHttp11ChunkedTransferEncoding() throws IOException { final String testData = "hello"; try (final InputStream is = new UnsynchronizedByteArrayInputStream(testData.getBytes(UTF_8))) { - final Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .version(HttpVersion.HTTP_1_1) .bodyStream(is, ContentType.TEXT_XML); @@ -190,7 +188,7 @@ public void retrieveXmlHttp11ChunkedTransferEncoding() throws IOException { public void retrieveMalformedXmlFallbackToString() throws IOException { final String testData = ""; - Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .bodyByteArray(testData.getBytes(UTF_8), ContentType.TEXT_XML); testRequest(post, wrapInElement(testData.replace("<", "<").replace(">", ">")).getBytes()); @@ -200,7 +198,7 @@ public void retrieveMalformedXmlFallbackToString() throws IOException { public void retrieveString() throws IOException { final String testData = "12345"; - Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .bodyByteArray(testData.getBytes(UTF_8)); testRequest(post, wrapInElement(testData).getBytes()); @@ -211,9 +209,9 @@ private void testRequest(Request method, final byte expectedResponse[]) throws I } private void testRequest(Request method, byte expectedResponse[], boolean stripWhitespaceAndFormatting) throws IOException { - final HttpResponse response = method.execute().returnResponse(); + try (final ClassicHttpResponse response = (ClassicHttpResponse) method.execute().returnResponse()) { - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + assertEquals(HttpStatus.SC_OK, response.getCode()); try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { response.getEntity().writeTo(os); @@ -225,5 +223,6 @@ private void testRequest(Request method, byte expectedResponse[], boolean stripW } assertArrayEquals(expectedResponse, actualResponse); } + } } } diff --git a/exist-core/src/test/java/org/exist/xquery/functions/request/GetHeaderTest.java b/exist-core/src/test/java/org/exist/xquery/functions/request/GetHeaderTest.java index ef4a110d6e2..d61cee6058d 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/request/GetHeaderTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/request/GetHeaderTest.java @@ -21,18 +21,16 @@ */ package org.exist.xquery.functions.request; -import static java.nio.charset.StandardCharsets.UTF_8; import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; import static org.junit.Assert.assertEquals; import java.io.IOException; import java.net.URLEncoder; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.HttpStatus; +import org.exist.http.AbstractHttpTest.HttpResponseResult; import org.exist.http.RESTTest; -import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.junit.Test; import org.xml.sax.SAXException; @@ -65,7 +63,7 @@ public void testHeaderValue() throws IOException, SAXException { } private void testGetHeader(String headerValue) throws IOException, SAXException { - Request request = Request.Get(getCollectionRootUri() + "?_query=" + URLEncoder.encode(xquery, "UTF-8") + "&_indent=no&_wrap=no"); + Request request = Request.get(getCollectionRootUri() + "?_query=" + URLEncoder.encode(xquery, "UTF-8") + "&_indent=no&_wrap=no"); final StringBuilder xmlExpectedResponse = new StringBuilder(""); if (headerValue != null) { @@ -74,14 +72,10 @@ private void testGetHeader(String headerValue) throws IOException, SAXException } xmlExpectedResponse.append(""); - final HttpResponse response = request.execute().returnResponse(); + final HttpResponseResult response = executeForStatusAndBody(request); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + assertEquals(HttpStatus.SC_OK, response.statusCode()); - try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { - response.getEntity().writeTo(os); - assertXMLEqual(xmlExpectedResponse - .toString(), new String(os.toByteArray(), UTF_8)); - } + assertXMLEqual(xmlExpectedResponse.toString(), response.body()); } } \ No newline at end of file diff --git a/exist-core/src/test/java/org/exist/xquery/functions/request/GetParameterTest.java b/exist-core/src/test/java/org/exist/xquery/functions/request/GetParameterTest.java index 08552c789e3..4c45ffd4032 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/request/GetParameterTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/request/GetParameterTest.java @@ -28,13 +28,13 @@ import java.util.ArrayList; import java.util.List; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.message.BasicNameValuePair; +import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.message.BasicNameValuePair; import org.exist.http.RESTTest; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.exist.xmldb.EXistResource; @@ -316,14 +316,14 @@ private void testGet(@Nullable final NameValues[] queryStringParams) throws IOEx } } - Request get = Request.Get(getCollectionRootUri() + "/" + XQUERY_FILENAME + (queryStringParams == null || queryStringParams.length == 0 ? "" : "?" + buf)); + Request get = Request.get(getCollectionRootUri() + "/" + XQUERY_FILENAME + (queryStringParams == null || queryStringParams.length == 0 ? "" : "?" + buf)); testRequest(get, buf.toString().replaceAll("&", "")); } private void testPost(@Nullable final NameValues[] formParams) throws IOException { final StringBuilder buf = new StringBuilder(); - Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME); + Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME); if (formParams != null) { final List bodyPairs = new ArrayList<>(); @@ -353,7 +353,7 @@ private void testPost(final NameValues[] queryStringParams, final NameValues[] f first = false; } - Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME + (queryStringParams.length == 0 ? "" : "?" + queryStringBuf)); + Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME + (queryStringParams.length == 0 ? "" : "?" + queryStringBuf)); final List bodyPairs = new ArrayList<>(); for (final NameValues formParam : formParams) { @@ -385,7 +385,7 @@ private void testMultipartPost(final Param[] multipartParams) throws IOException } } - Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME) + Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME) .body(multipart.build()); testRequest(post, buf.toString()); @@ -419,19 +419,20 @@ private void testMultipartPost(final NameValues[] queryStringParams, final Param } } - Request post = Request.Post(getCollectionRootUri() + "/" + XQUERY_FILENAME + (queryStringParams.length == 0 ? "" : "?" + queryStringBuf)) + Request post = Request.post(getCollectionRootUri() + "/" + XQUERY_FILENAME + (queryStringParams.length == 0 ? "" : "?" + queryStringBuf)) .body(multipart.build()); testRequest(post, queryStringBuf.toString().replaceAll("&", "") + bodyBuf); } private void testRequest(final Request request, final String expected) throws IOException { - final HttpResponse response = request.execute().returnResponse(); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + try (final ClassicHttpResponse response = (ClassicHttpResponse) request.execute().returnResponse()) { + assertEquals(HttpStatus.SC_OK, response.getCode()); - try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { - response.getEntity().writeTo(os); - assertEquals(expected, new String(os.toByteArray(), UTF_8)); + try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { + response.getEntity().writeTo(os); + assertEquals(expected, new String(os.toByteArray(), UTF_8)); + } } } diff --git a/exist-core/src/test/java/org/exist/xquery/functions/request/PatchTest.java b/exist-core/src/test/java/org/exist/xquery/functions/request/PatchTest.java index 386e40e619b..188ca95192f 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/request/PatchTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/request/PatchTest.java @@ -21,10 +21,10 @@ */ package org.exist.xquery.functions.request; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.exist.xmldb.UserManagementService; @@ -92,7 +92,7 @@ public static void afterClass() throws XMLDBException { public void patchBinary() throws IOException { final byte[] testData = "12345".getBytes(UTF_8); - final Request patch = Request.Patch(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request patch = Request.patch(getCollectionRootUri() + "/" + XQUERY_FILENAME) .bodyByteArray(testData, ContentType.APPLICATION_OCTET_STREAM); assertResponse(patch, encodeBase64String(testData)); @@ -102,7 +102,7 @@ public void patchBinary() throws IOException { public void patchXml() throws IOException { final String testData = "hello"; - final Request patch = Request.Patch(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request patch = Request.patch(getCollectionRootUri() + "/" + XQUERY_FILENAME) .bodyByteArray(testData.getBytes(UTF_8), ContentType.TEXT_XML); assertResponse(patch, testData); @@ -112,7 +112,7 @@ public void patchXml() throws IOException { public void patchString() throws IOException { final String testData = "12345"; - final Request patch = Request.Patch(getCollectionRootUri() + "/" + XQUERY_FILENAME) + final Request patch = Request.patch(getCollectionRootUri() + "/" + XQUERY_FILENAME) .bodyByteArray(testData.getBytes(UTF_8)); assertResponse(patch, testData); @@ -122,7 +122,7 @@ public void patchString() throws IOException { public void patchCollectionNotAllowed() throws IOException { final String testData = "hello"; - final Request patch = Request.Patch(getCollectionRootUri()) + final Request patch = Request.patch(getCollectionRootUri()) .bodyByteArray(testData.getBytes(UTF_8), ContentType.TEXT_XML); assertMethodNotAllowed(patch); @@ -132,33 +132,35 @@ public void patchCollectionNotAllowed() throws IOException { public void patchXmlResourceNotAllowed() throws IOException { final String testData = "hello"; - final Request patch = Request.Patch(getCollectionRootUri() + "/" + XML_FILENAME) + final Request patch = Request.patch(getCollectionRootUri() + "/" + XML_FILENAME) .bodyByteArray(testData.getBytes(UTF_8), ContentType.TEXT_XML); assertMethodNotAllowed(patch); } private void assertResponse(final Request method, String expectedData) throws IOException { - final HttpResponse response = method.execute().returnResponse(); final Matcher valueMatcher = hasSimilarXml( "PATCH" + expectedData + ""); - assertHTTPStatusCode(HttpStatus.SC_OK, response); + try (final ClassicHttpResponse response = (ClassicHttpResponse) method.execute().returnResponse()) { + assertHTTPStatusCode(HttpStatus.SC_OK, response); - try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { - response.getEntity().writeTo(os); + try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { + response.getEntity().writeTo(os); - final String actualResponse = new String(os.toByteArray()); - assertThat(actualResponse, valueMatcher); + final String actualResponse = new String(os.toByteArray()); + assertThat(actualResponse, valueMatcher); + } } } - private void assertHTTPStatusCode (final int code, final HttpResponse response) { - assertEquals(code, response.getStatusLine().getStatusCode()); + private void assertHTTPStatusCode (final int code, final ClassicHttpResponse response) { + assertEquals(code, response.getCode()); } private void assertMethodNotAllowed (final Request req) throws IOException { - final HttpResponse response = req.execute().returnResponse(); - assertHTTPStatusCode(HttpStatus.SC_METHOD_NOT_ALLOWED, response); + try (final ClassicHttpResponse response = (ClassicHttpResponse) req.execute().returnResponse()) { + assertHTTPStatusCode(HttpStatus.SC_METHOD_NOT_ALLOWED, response); + } } } diff --git a/exist-core/src/test/java/org/exist/xquery/functions/response/StreamBinaryTest.java b/exist-core/src/test/java/org/exist/xquery/functions/response/StreamBinaryTest.java index 26067159b53..3f9645f28c9 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/response/StreamBinaryTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/response/StreamBinaryTest.java @@ -29,9 +29,9 @@ import org.apache.commons.codec.binary.Base64; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpStatus; import org.exist.http.RESTTest; import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; import org.junit.Test; @@ -50,15 +50,16 @@ public void testStreamBinary() throws IOException { final String testValue = "hello world"; final String xquery = "response:stream-binary(xs:base64Binary('" + Base64.encodeBase64String(testValue.getBytes()) + "'), 'application/octet-stream', 'test.bin')"; - final Request get = Request.Get(getCollectionRootUri() + "?_query=" + URLEncoder.encode(xquery, "UTF-8") + "&_indent=no"); + final Request get = Request.get(getCollectionRootUri() + "?_query=" + URLEncoder.encode(xquery, "UTF-8") + "&_indent=no"); - final HttpResponse response = get.execute().returnResponse(); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + try (ClassicHttpResponse response = (ClassicHttpResponse) get.execute().returnResponse()) { + assertEquals(HttpStatus.SC_OK, response.getCode()); - try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { - response.getEntity().writeTo(os); + try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { + response.getEntity().writeTo(os); - assertArrayEquals(testValue.getBytes(), os.toByteArray()); + assertArrayEquals(testValue.getBytes(), os.toByteArray()); + } } } } \ No newline at end of file diff --git a/exist-core/src/test/java/org/exist/xquery/functions/session/AttributeTest.java b/exist-core/src/test/java/org/exist/xquery/functions/session/AttributeTest.java index 4765f168034..d9ada8a09f1 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/session/AttributeTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/session/AttributeTest.java @@ -32,11 +32,8 @@ */ package org.exist.xquery.functions.session; -import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.HttpStatus; import org.exist.util.UUIDGenerator; import org.junit.Test; @@ -45,7 +42,7 @@ import java.net.URLEncoder; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertEquals; +import static org.exist.http.AbstractHttpTest.assertRequestResponse; public class AttributeTest extends AbstractSessionTest { @@ -53,188 +50,99 @@ public class AttributeTest extends AbstractSessionTest { public void getSetAttributeExplicitSessionCreation() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // get the value of the attribute named "attr1", and check its value is the empty sequence final Request requestGetAttr = xqueryRequest("session:get-attribute('attr1')"); - final HttpResponse getResponse1 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, ""); // set the value of the attribute named "attr1" to a random UUID final String attr1Value = UUIDGenerator.getUUIDversion4(); final Request requestSetAttr1 = xqueryRequest("session:set-attribute('attr1', '" + attr1Value + "')"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(setResponse1.getEntity())); + assertRequestResponse(requestSetAttr1, HttpStatus.SC_OK, ""); // get the value of the attribute named "attr1", and check its value is the UUID - final HttpResponse getResponse2 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse2.getStatusLine().getStatusCode()); - assertEquals(attr1Value, readEntityAsString(getResponse2.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, attr1Value); } @Test public void getSetAttributeImplicitSessionCreation() throws IOException { // get the value of the attribute named "attr1", and check its value is the empty sequence final Request requestGetAttr = xqueryRequest("session:get-attribute('attr1')"); - final HttpResponse getResponse1 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, ""); // set the value of the attribute named "attr1" to a random UUID final String attr1Value = UUIDGenerator.getUUIDversion4(); final Request requestSetAttr1 = xqueryRequest("session:set-attribute('attr1', '" + attr1Value + "')"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(setResponse1.getEntity())); + assertRequestResponse(requestSetAttr1, HttpStatus.SC_OK, ""); // get the value of the attribute named "attr1", and check its value is the UUID - final HttpResponse getResponse2 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse2.getStatusLine().getStatusCode()); - assertEquals(attr1Value, readEntityAsString(getResponse2.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, attr1Value); } @Test public void getAttributeOnInvalidatedSessionSeparateHttpCalls() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session final Request requestInvalidateSession = xqueryRequest("session:invalidate()"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(invalidateSessionResponse.getEntity())); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, ""); // get the value of the attribute named "attr1", and check its value is the empty sequence final Request requestGetAttr1 = xqueryRequest("session:get-attribute('attr1')"); - final HttpResponse getResponse1 = requestGetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr1, HttpStatus.SC_OK, ""); } @Test public void getAttributeOnInvalidatedSessionSameHttpCall() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session and call get-attribute final Request requestInvalidateSession = xqueryRequest("session:invalidate(), session:get-attribute('attr1')"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(invalidateSessionResponse.getEntity())); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, ""); } @Test public void setAttributeOnInvalidatedSessionSeparateHttpCalls() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session final Request requestInvalidateSession = xqueryRequest("session:invalidate()"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(invalidateSessionResponse.getEntity())); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, ""); // set the value of the attribute named "attr1" to a random UUID final String attr1Value = UUIDGenerator.getUUIDversion4(); final Request requestSetAttr1 = xqueryRequest("session:set-attribute('attr1', '" + attr1Value + "')"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - final String responseBody = readEntityAsString(setResponse1.getEntity()); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); - assertEquals("", responseBody); + assertRequestResponse(requestSetAttr1, HttpStatus.SC_OK, ""); // get the value of the attribute named "attr1", and check its value is the UUID final Request requestGetAttr = xqueryRequest("session:get-attribute('attr1')"); - final HttpResponse getResponse2 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse2.getStatusLine().getStatusCode()); - assertEquals(attr1Value, readEntityAsString(getResponse2.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, attr1Value); } @Test public void setAttributeOnInvalidatedSessionSameHttpCall() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session and call set-attribute final String attr1Value = UUIDGenerator.getUUIDversion4(); final Request requestInvalidateSession = xqueryRequest("session:invalidate(), session:set-attribute('attr1', '" + attr1Value + "')"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - final String responseBody = readEntityAsString(invalidateSessionResponse.getEntity()); - assertEquals(HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", responseBody); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, ""); // get the value of the attribute named "attr1", and check its value is the UUID final Request requestGetAttr = xqueryRequest("session:get-attribute('attr1')"); - final HttpResponse getResponse2 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse2.getStatusLine().getStatusCode()); - assertEquals(attr1Value, readEntityAsString(getResponse2.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, attr1Value); } public Request xqueryRequest(final String xquery) throws UnsupportedEncodingException { - return Request.Get(getCollectionRootUri() + "/?_query=" + URLEncoder.encode(xquery, UTF_8.name()) + "&_wrap=no"); - } - - private static String readEntityAsString(final HttpEntity entity) throws IOException { - return new String(readEntity(entity), UTF_8); - } - - private static byte[] readEntity(final HttpEntity entity) throws IOException { - try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { - entity.writeTo(os); - return os.toByteArray(); - } + return Request.get(getCollectionRootUri() + "/?_query=" + URLEncoder.encode(xquery, UTF_8.name()) + "&_wrap=no"); } } diff --git a/exist-core/src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java b/exist-core/src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java index 74c0f86c1c5..9ba2488898c 100644 --- a/exist-core/src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java +++ b/exist-core/src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java @@ -32,12 +32,10 @@ */ package org.exist.xquery.functions.xmldb; -import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.HttpStatus; import org.exist.TestUtils; +import org.exist.http.AbstractHttpTest.HttpResponseResult; import org.exist.security.internal.aider.GroupAider; import org.exist.security.internal.aider.UserAider; import org.exist.xmldb.UserManagementService; @@ -56,6 +54,8 @@ import java.net.URLEncoder; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.exist.http.AbstractHttpTest.assertRequestResponse; +import static org.exist.http.AbstractHttpTest.executeForStatusAndBody; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -81,26 +81,16 @@ public void beforeClass() throws XMLDBException { public void loginExplicitSessionCreation() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // login to the database final Request requestGetAttr = xqueryRequest("xmldb:login('/db', '" + USER1_UID + "', '" + USER1_PWD + "')"); - final HttpResponse getResponse1 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("true", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, "true"); // get the identity of the current user final Request requestSetAttr1 = xqueryRequest("sm:id()"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); + final HttpResponseResult result = executeForStatusAndBody(requestSetAttr1); + assertEquals(HttpStatus.SC_OK, result.statusCode()); final Source expected = Input.fromString( """ @@ -112,7 +102,7 @@ public void loginExplicitSessionCreation() throws IOException { """).build(); - final Source actual = Input.fromString(readEntityAsString(setResponse1.getEntity())).build(); + final Source actual = Input.fromString(result.body()).build(); final Diff diff = DiffBuilder.compare(expected) .withTest(actual) .checkForSimilar() @@ -124,18 +114,12 @@ public void loginExplicitSessionCreation() throws IOException { public void loginImplicitSessionCreateSessionFalse() throws IOException { // login to the database final Request requestGetAttr = xqueryRequest("xmldb:login('/db', '" + USER1_UID + "', '" + USER1_PWD + "', false())"); - final HttpResponse getResponse1 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("true", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, "true"); // get the identity of the current user final Request requestSetAttr1 = xqueryRequest("sm:id()"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); + final HttpResponseResult result = executeForStatusAndBody(requestSetAttr1); + assertEquals(HttpStatus.SC_OK, result.statusCode()); final Source expected = Input.fromString( """ @@ -147,7 +131,7 @@ public void loginImplicitSessionCreateSessionFalse() throws IOException { """).build(); - final Source actual = Input.fromString(readEntityAsString(setResponse1.getEntity())).build(); + final Source actual = Input.fromString(result.body()).build(); final Diff diff = DiffBuilder.compare(expected) .withTest(actual) .checkForSimilar() @@ -159,18 +143,12 @@ public void loginImplicitSessionCreateSessionFalse() throws IOException { public void loginImplicitSessionCreateSessionTrue() throws IOException { // login to the database final Request requestGetAttr = xqueryRequest("xmldb:login('/db', '" + USER1_UID + "', '" + USER1_PWD + "', true())"); - final HttpResponse getResponse1 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("true", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, "true"); // get the identity of the current user final Request requestSetAttr1 = xqueryRequest("sm:id()"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); + final HttpResponseResult result = executeForStatusAndBody(requestSetAttr1); + assertEquals(HttpStatus.SC_OK, result.statusCode()); final Source expected = Input.fromString( """ @@ -182,7 +160,7 @@ public void loginImplicitSessionCreateSessionTrue() throws IOException { """).build(); - final Source actual = Input.fromString(readEntityAsString(setResponse1.getEntity())).build(); + final Source actual = Input.fromString(result.body()).build(); final Diff diff = DiffBuilder.compare(expected) .withTest(actual) .checkForSimilar() @@ -194,34 +172,20 @@ public void loginImplicitSessionCreateSessionTrue() throws IOException { public void loginOnInvalidatedSessionCreateSessionFalseSeparateHttpCalls() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session final Request requestInvalidateSession = xqueryRequest("session:invalidate()"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(invalidateSessionResponse.getEntity())); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, ""); // login to the database final Request requestGetAttr = xqueryRequest("xmldb:login('/db', '" + USER1_UID + "', '" + USER1_PWD + "', false())"); - final HttpResponse getResponse1 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("true", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, "true"); // get the identity of the current user final Request requestSetAttr1 = xqueryRequest("sm:id()"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); + final HttpResponseResult result = executeForStatusAndBody(requestSetAttr1); + assertEquals(HttpStatus.SC_OK, result.statusCode()); final Source expected = Input.fromString( """ @@ -233,7 +197,7 @@ public void loginOnInvalidatedSessionCreateSessionFalseSeparateHttpCalls() throw """).build(); - final Source actual = Input.fromString(readEntityAsString(setResponse1.getEntity())).build(); + final Source actual = Input.fromString(result.body()).build(); final Diff diff = DiffBuilder.compare(expected) .withTest(actual) .checkForSimilar() @@ -245,34 +209,20 @@ public void loginOnInvalidatedSessionCreateSessionFalseSeparateHttpCalls() throw public void loginOnInvalidatedSessionCreateSessionTrueSeparateHttpCalls() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session final Request requestInvalidateSession = xqueryRequest("session:invalidate()"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(invalidateSessionResponse.getEntity())); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, ""); // login to the database final Request requestGetAttr = xqueryRequest("xmldb:login('/db', '" + USER1_UID + "', '" + USER1_PWD + "', true())"); - final HttpResponse getResponse1 = requestGetAttr - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, getResponse1.getStatusLine().getStatusCode()); - assertEquals("true", readEntityAsString(getResponse1.getEntity())); + assertRequestResponse(requestGetAttr, HttpStatus.SC_OK, "true"); // get the identity of the current user final Request requestSetAttr1 = xqueryRequest("sm:id()"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); + final HttpResponseResult result = executeForStatusAndBody(requestSetAttr1); + assertEquals(HttpStatus.SC_OK, result.statusCode()); final Source expected = Input.fromString( """ @@ -284,7 +234,7 @@ public void loginOnInvalidatedSessionCreateSessionTrueSeparateHttpCalls() throws """).build(); - final Source actual = Input.fromString(readEntityAsString(setResponse1.getEntity())).build(); + final Source actual = Input.fromString(result.body()).build(); final Diff diff = DiffBuilder.compare(expected) .withTest(actual) .checkForSimilar() @@ -296,27 +246,16 @@ public void loginOnInvalidatedSessionCreateSessionTrueSeparateHttpCalls() throws public void loginOnInvalidatedSessionCreateSessionFalseSameHttpCall() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session and login to the database final Request requestInvalidateSession = xqueryRequest("session:invalidate(), xmldb:login('/db', '" + USER1_UID + "', '" + USER1_PWD + "', false())"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - final String responseBody = readEntityAsString(invalidateSessionResponse.getEntity()); - assertEquals(responseBody, HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("true", responseBody); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, "true"); // get the identity of the current user final Request requestSetAttr1 = xqueryRequest("sm:id()"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); + final HttpResponseResult result = executeForStatusAndBody(requestSetAttr1); + assertEquals(HttpStatus.SC_OK, result.statusCode()); final Source expected = Input.fromString( """ @@ -328,7 +267,7 @@ public void loginOnInvalidatedSessionCreateSessionFalseSameHttpCall() throws IOE """).build(); - final Source actual = Input.fromString(readEntityAsString(setResponse1.getEntity())).build(); + final Source actual = Input.fromString(result.body()).build(); final Diff diff = DiffBuilder.compare(expected) .withTest(actual) .checkForSimilar() @@ -340,27 +279,16 @@ public void loginOnInvalidatedSessionCreateSessionFalseSameHttpCall() throws IOE public void loginOnInvalidatedSessionCreateSessionTrueSameHttpCall() throws IOException { // explicitly create a new session final Request requestCreateSession = xqueryRequest("session:create()"); - final HttpResponse createSessionResponse = requestCreateSession - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, createSessionResponse.getStatusLine().getStatusCode()); - assertEquals("", readEntityAsString(createSessionResponse.getEntity())); + assertRequestResponse(requestCreateSession, HttpStatus.SC_OK, ""); // invalidate the session and login to the database final Request requestInvalidateSession = xqueryRequest("session:invalidate(), xmldb:login('/db', '" + USER1_UID + "', '" + USER1_PWD + "', true())"); - final HttpResponse invalidateSessionResponse = requestInvalidateSession - .execute() - .returnResponse(); - final String responseBody = readEntityAsString(invalidateSessionResponse.getEntity()); - assertEquals(responseBody, HttpStatus.SC_OK, invalidateSessionResponse.getStatusLine().getStatusCode()); - assertEquals("true", responseBody); + assertRequestResponse(requestInvalidateSession, HttpStatus.SC_OK, "true"); // get the identity of the current user final Request requestSetAttr1 = xqueryRequest("sm:id()"); - final HttpResponse setResponse1 = requestSetAttr1 - .execute() - .returnResponse(); - assertEquals(HttpStatus.SC_OK, setResponse1.getStatusLine().getStatusCode()); + final HttpResponseResult result = executeForStatusAndBody(requestSetAttr1); + assertEquals(HttpStatus.SC_OK, result.statusCode()); final Source expected = Input.fromString( """ @@ -372,7 +300,7 @@ public void loginOnInvalidatedSessionCreateSessionTrueSameHttpCall() throws IOEx """).build(); - final Source actual = Input.fromString(readEntityAsString(setResponse1.getEntity())).build(); + final Source actual = Input.fromString(result.body()).build(); final Diff diff = DiffBuilder.compare(expected) .withTest(actual) .checkForSimilar() @@ -381,17 +309,6 @@ public void loginOnInvalidatedSessionCreateSessionTrueSameHttpCall() throws IOEx } public Request xqueryRequest(final String xquery) throws UnsupportedEncodingException { - return Request.Get(getCollectionRootUri() + "/?_query=" + URLEncoder.encode(xquery, UTF_8.name()) + "&_wrap=no"); - } - - private static String readEntityAsString(final HttpEntity entity) throws IOException { - return new String(readEntity(entity), UTF_8); - } - - private static byte[] readEntity(final HttpEntity entity) throws IOException { - try (final UnsynchronizedByteArrayOutputStream os = new UnsynchronizedByteArrayOutputStream()) { - entity.writeTo(os); - return os.toByteArray(); - } + return Request.get(getCollectionRootUri() + "/?_query=" + URLEncoder.encode(xquery, UTF_8.name()) + "&_wrap=no"); } } diff --git a/exist-installer/pom.xml b/exist-installer/pom.xml index b8f30786529..dd04856bd49 100644 --- a/exist-installer/pom.xml +++ b/exist-installer/pom.xml @@ -117,7 +117,7 @@ ${izpack.resources.target}/install.xml ${project.basedir}/../exist-distribution/target/exist-distribution-dir - apache.httpcomponents.core.version,apache.httpcomponents.version,apache.xmlrpc.version,appassembler.version,aspectj.version,git.commit.id,git.commit.id.abbrev,git.closest.tag.name,git.closest.tag.commit.count,git.commit.time,git.commit.id.describe,contact.email,exquery.distribution.version,icu.version,jetty.version,izpack.installation.info.appversion,izpack.installation.info.author.email,izpack.installation.info.author.name,izpack.installation.info.url,izpack.resources.src,izpack.resources.target,izpack.version,jansi.version,jaxb.api.version,jaxb.impl.version,log4j.version,lucene.version,milton.version,project.build.sourceEncoding,project.copyright.name,saxon.version,xmlresolver.version,maven.compiler.release + apache.httpcomponents.core.version,apache.httpcomponents.version,apache.xmlrpc.version,appassembler.version,aspectj.version,git.commit.id,git.commit.id.abbrev,git.closest.tag.name,git.closest.tag.commit.count,git.commit.time,git.commit.id.describe,contact.email,exquery.distribution.version,icu.version,jetty.version,izpack.installation.info.appversion,izpack.installation.info.author.email,izpack.installation.info.author.name,izpack.installation.info.url,izpack.resources.src,izpack.resources.target,izpack.version,jansi.version,jaxb.api.version,jaxb.impl.version,log4j.version,lucene.version,project.build.sourceEncoding,project.copyright.name,saxon.version,xmlresolver.version,maven.compiler.release true true diff --git a/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/web.xml b/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/web.xml index dd33e81a13b..6f66ad5d0fd 100644 --- a/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/web.xml +++ b/exist-jetty-config/src/main/resources/standalone-webapp/WEB-INF/web.xml @@ -81,40 +81,10 @@ - + - milton - org.exist.webdav.MiltonWebDAVServlet - - - - resource.factory.class - org.exist.webdav.ExistResourceFactory - - - - - - - + webdav + org.exist.webdav.ExistWebdavServlet @@ -178,6 +148,12 @@ controller-config.xml. However, please note that some features of the website will only work if XQueryURLRewrite controls the /rest servlet (EXistServlet). --> + + + webdav + /webdav/* + + XQueryURLRewrite /* diff --git a/exist-parent/pom.xml b/exist-parent/pom.xml index c6b6146ef41..ece0e6f0918 100644 --- a/exist-parent/pom.xml +++ b/exist-parent/pom.xml @@ -118,6 +118,8 @@ 1.10.17 4.5.14 4.4.16 + 5.6.1 + 5.4 5.0.0 2.1.0 1.9.25.1 @@ -131,8 +133,6 @@ 12.1.9 2.26.0 10.4.0 - 1.8.1.3 - 1.8.1.3-jakarta-ee10 2.1.3 12.5 6.0.23 @@ -334,6 +334,21 @@ fluent-hc ${apache.httpcomponents.version} + + org.apache.httpcomponents.core5 + httpcore5 + ${apache.httpcomponents.core5.version} + + + org.apache.httpcomponents.client5 + httpclient5 + ${apache.httpcomponents.client5.version} + + + org.apache.httpcomponents.client5 + httpclient5-fluent + ${apache.httpcomponents.client5.version} + @@ -502,24 +517,6 @@ ${exquery.distribution.version} - - org.exist-db.thirdparty.com.ettrema - milton-api - ${milton.version} - - - - org.exist-db.thirdparty.com.ettrema - milton-client - ${milton.version} - - - - com.evolvedbinary.thirdparty.com.ettrema - milton-servlet - ${milton.servlet.version} - - org.exist-db.thirdparty.org.apache.jackrabbit diff --git a/extensions/debuggee/pom.xml b/extensions/debuggee/pom.xml index c622046bc13..44c130be7d5 100644 --- a/extensions/debuggee/pom.xml +++ b/extensions/debuggee/pom.xml @@ -59,8 +59,9 @@ - org.apache.httpcomponents - fluent-hc + org.apache.httpcomponents.client5 + httpclient5-fluent + 5.6.1 diff --git a/extensions/debuggee/src/main/java/org/exist/debugger/HttpSession.java b/extensions/debuggee/src/main/java/org/exist/debugger/HttpSession.java index f7618446bea..2df75ecda2b 100644 --- a/extensions/debuggee/src/main/java/org/exist/debugger/HttpSession.java +++ b/extensions/debuggee/src/main/java/org/exist/debugger/HttpSession.java @@ -21,8 +21,9 @@ */ package org.exist.debugger; -import org.apache.http.client.fluent.Form; -import org.apache.http.client.fluent.Request; +import org.apache.hc.client5.http.fluent.Form; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; /** * @author Dmitriy Shabanov @@ -45,12 +46,11 @@ public void run() { try { System.out.println("sending http request with debugging flag"); - final int code = Request.Post(url) + final int code = ((ClassicHttpResponse) Request.post(url) .bodyForm(Form.form().add("XDEBUG_SESSION", "default").build()) .execute() - .returnResponse() - .getStatusLine() - .getStatusCode(); + .returnResponse()) + .getCode(); debugger.terminate(url, code); diff --git a/extensions/expath/pom.xml b/extensions/expath/pom.xml index b189b3307a0..1f9cc4289f1 100644 --- a/extensions/expath/pom.xml +++ b/extensions/expath/pom.xml @@ -57,11 +57,22 @@ commons-io + org.apache.httpcomponents httpcore + + org.apache.httpcomponents.core5 + httpcore5 + + org.apache.logging.log4j log4j-api diff --git a/extensions/expath/src/main/java/org/expath/exist/SendRequestFunction.java b/extensions/expath/src/main/java/org/expath/exist/SendRequestFunction.java index edaaa1eb32c..726242b9f3c 100644 --- a/extensions/expath/src/main/java/org/expath/exist/SendRequestFunction.java +++ b/extensions/expath/src/main/java/org/expath/exist/SendRequestFunction.java @@ -23,7 +23,7 @@ import java.net.URI; import java.net.URISyntaxException; -import org.apache.http.HttpStatus; +import org.apache.hc.core5.http.HttpStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.dom.QName; diff --git a/extensions/expath/src/main/java/org/expath/httpclient/model/exist/EXistTreeBuilder.java b/extensions/expath/src/main/java/org/expath/httpclient/model/exist/EXistTreeBuilder.java index 85da486d913..ba28cf71c81 100644 --- a/extensions/expath/src/main/java/org/expath/httpclient/model/exist/EXistTreeBuilder.java +++ b/extensions/expath/src/main/java/org/expath/httpclient/model/exist/EXistTreeBuilder.java @@ -21,6 +21,7 @@ */ package org.expath.httpclient.model.exist; +// http-client-java 1.4.2 API; remove when PR #5346 (http-client-java 1.5.2) lands import org.apache.http.Header; import org.exist.dom.QName; import org.exist.dom.memtree.DocumentImpl; diff --git a/extensions/exquery/restxq/pom.xml b/extensions/exquery/restxq/pom.xml index ccc37f26ed3..a683ed4a6be 100644 --- a/extensions/exquery/restxq/pom.xml +++ b/extensions/exquery/restxq/pom.xml @@ -157,6 +157,14 @@ + + ${project.groupId} + exist-core + ${project.version} + test-jar + test + + junit junit @@ -173,13 +181,13 @@ test - org.apache.httpcomponents - httpcore + org.apache.httpcomponents.core5 + httpcore5 test - org.apache.httpcomponents - fluent-hc + org.apache.httpcomponents.client5 + httpclient5-fluent test diff --git a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractClassIntegrationTest.java b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractClassIntegrationTest.java index ce815094f63..434310a744b 100644 --- a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractClassIntegrationTest.java +++ b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractClassIntegrationTest.java @@ -26,9 +26,9 @@ */ package org.exist.extensions.exquery.restxq.impl; -import org.apache.http.HttpHost; -import org.apache.http.client.fluent.Executor; +import org.apache.hc.client5.http.fluent.Executor; import org.exist.TestUtils; +import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -44,9 +44,7 @@ public abstract class AbstractClassIntegrationTest extends AbstractIntegrationTe @BeforeClass public static void setupExecutor() { - executor = Executor.newInstance() - .auth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD) - .authPreemptive(new HttpHost("localhost", existWebServer.getPort())); + executor = AbstractHttpTest.createAuthenticatedExecutor(existWebServer, TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD); } protected static String getServerUri() { diff --git a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractInstanceIntegrationTest.java b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractInstanceIntegrationTest.java index 9249c0dbe81..873b41e9949 100644 --- a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractInstanceIntegrationTest.java +++ b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractInstanceIntegrationTest.java @@ -26,9 +26,9 @@ */ package org.exist.extensions.exquery.restxq.impl; -import org.apache.http.HttpHost; -import org.apache.http.client.fluent.Executor; +import org.apache.hc.client5.http.fluent.Executor; import org.exist.TestUtils; +import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; import org.junit.Before; import org.junit.Rule; @@ -45,9 +45,7 @@ public abstract class AbstractInstanceIntegrationTest extends AbstractIntegratio @Before public void setupExecutor() { - executor = Executor.newInstance() - .auth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD) - .authPreemptive(new HttpHost("localhost", existWebServer.getPort())); + executor = AbstractHttpTest.createAuthenticatedExecutor(existWebServer, TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD); } protected String getServerUri() { diff --git a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractIntegrationTest.java b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractIntegrationTest.java index d2bcaf358e6..dc04a0def6c 100644 --- a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractIntegrationTest.java +++ b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/AbstractIntegrationTest.java @@ -26,13 +26,14 @@ */ package org.exist.extensions.exquery.restxq.impl; -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.apache.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpStatus; import org.exist.collections.CollectionConfiguration; import org.exist.dom.memtree.SAXAdapter; +import org.exist.http.AbstractHttpTest; import org.exist.test.ExistWebServer; import org.exist.util.ExistSAXParserFactory; import org.exquery.restxq.Namespace; @@ -68,6 +69,10 @@ public abstract class AbstractIntegrationTest { private static ContentType XQUERY_CONTENT_TYPE = ContentType.create("application/xquery", UTF_8); + /** + * Standalone test webapp is mounted at {@code /} (see {@code exist.jetty.standalone.webapp.dir}), + * not at {@code /exist} like {@link AbstractHttpTest#getServerUri(ExistWebServer)} in exist-core tests. + */ protected static String getServerUri(final ExistWebServer existWebServer) { return "http://localhost:" + existWebServer.getPort(); } @@ -81,26 +86,29 @@ protected static String getRestXqUri(final ExistWebServer existWebServer) { } protected static void enableRestXqTrigger(final ExistWebServer existWebServer, final Executor executor, final String collectionPath) throws IOException { - final HttpResponse response = executor.execute(Request - .Put(getRestUri(existWebServer) + "/db/system/config" + collectionPath + "/" + CollectionConfiguration.DEFAULT_COLLECTION_CONFIG_FILE) + try (final ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(Request + .put(getRestUri(existWebServer) + "/db/system/config" + collectionPath + "/" + CollectionConfiguration.DEFAULT_COLLECTION_CONFIG_FILE) .bodyString(COLLECTION_CONFIG, ContentType.APPLICATION_XML.withCharset(UTF_8)) - ).returnResponse(); - assertEquals(HttpStatus.SC_CREATED, response.getStatusLine().getStatusCode()); + ).returnResponse()) { + assertEquals(HttpStatus.SC_CREATED, response.getCode()); + } } protected static void storeXquery(final ExistWebServer existWebServer, final Executor executor, final String collectionPath, final String xqueryFilename, final String xquery) throws IOException { - final HttpResponse response = executor.execute(Request - .Put(getRestUri(existWebServer) + collectionPath + "/" + xqueryFilename) + try (final ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(Request + .put(getRestUri(existWebServer) + collectionPath + "/" + xqueryFilename) .bodyString(xquery, XQUERY_CONTENT_TYPE) - ).returnResponse(); - assertEquals(HttpStatus.SC_CREATED, response.getStatusLine().getStatusCode()); + ).returnResponse()) { + assertEquals(HttpStatus.SC_CREATED, response.getCode()); + } } protected static void removeXquery(final ExistWebServer existWebServer, final Executor executor, final String collectionPath, final String xqueryFilename) throws IOException { - final HttpResponse response = executor.execute(Request - .Delete(getRestUri(existWebServer) + collectionPath + "/" + xqueryFilename) - ).returnResponse(); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + try (final ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(Request + .delete(getRestUri(existWebServer) + collectionPath + "/" + xqueryFilename) + ).returnResponse()) { + assertEquals(HttpStatus.SC_OK, response.getCode()); + } } protected static void assertRestXqResourceFunctionsCount(final ExistWebServer existWebServer, final Executor executor, final int expectedCount) throws IOException { @@ -108,25 +116,26 @@ protected static void assertRestXqResourceFunctionsCount(final ExistWebServer ex } protected static NodeList getRestXqResourceFunctions(final ExistWebServer existWebServer, final Executor executor) throws IOException { - final HttpResponse response = executor.execute(Request - .Get(getRestUri(existWebServer) + "/db/?_query=rest:resource-functions()") - ).returnResponse(); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); - - final Document doc; - try (final InputStream is = response.getEntity().getContent()) { - assertNotNull(is); - doc = parseXml(is); - } - assertNotNull(doc); + try (final ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(Request + .get(getRestUri(existWebServer) + "/db/?_query=rest:resource-functions()") + ).returnResponse()) { + assertEquals(HttpStatus.SC_OK, response.getCode()); + + final Document doc; + try (final InputStream is = response.getEntity().getContent()) { + assertNotNull(is); + doc = parseXml(is); + } + assertNotNull(doc); - final Element docElem = doc.getDocumentElement(); - assertEquals("exist:result", docElem.getNodeName()); - final NodeList resourceFunctionsList = docElem.getElementsByTagNameNS(Namespace.ANNOTATION_NS, "resource-functions"); - assertEquals(1, resourceFunctionsList.getLength()); + final Element docElem = doc.getDocumentElement(); + assertEquals("exist:result", docElem.getNodeName()); + final NodeList resourceFunctionsList = docElem.getElementsByTagNameNS(Namespace.ANNOTATION_NS, "resource-functions"); + assertEquals(1, resourceFunctionsList.getLength()); - final Element resourceFunctionsElem = (Element) resourceFunctionsList.item(0); - return resourceFunctionsElem.getElementsByTagNameNS(Namespace.ANNOTATION_NS, "resource-function"); + final Element resourceFunctionsElem = (Element) resourceFunctionsList.item(0); + return resourceFunctionsElem.getElementsByTagNameNS(Namespace.ANNOTATION_NS, "resource-function"); + } } protected static Document parseXml(final InputStream inputStream) throws IOException { diff --git a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/MediaTypeIntegrationTest.java b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/MediaTypeIntegrationTest.java index d474fd4fd3e..70291b9466c 100644 --- a/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/MediaTypeIntegrationTest.java +++ b/extensions/exquery/restxq/src/test/java/org/exist/extensions/exquery/restxq/impl/MediaTypeIntegrationTest.java @@ -26,12 +26,12 @@ */ package org.exist.extensions.exquery.restxq.impl; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; -import org.apache.http.message.BasicHeader; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.message.BasicHeader; import org.junit.BeforeClass; import org.junit.Test; @@ -132,15 +132,15 @@ public void mediaTypeXml2() throws IOException { } private void assertMediaTypeResponse(final String uriEndpoint, final ContentType acceptContentType, final String expectedResponseContentType, final String expectedResponseBody) throws IOException { - final HttpResponse response = executor.execute(Request - .Get(getRestXqUri() + uriEndpoint) + final ClassicHttpResponse response = (ClassicHttpResponse) executor.execute(Request + .get(getRestXqUri() + uriEndpoint) .addHeader(new BasicHeader("Accept", acceptContentType.toString())) ).returnResponse(); - assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode()); + assertEquals(HttpStatus.SC_OK, response.getCode()); final HttpEntity responseEntity = response.getEntity(); - assertEquals(expectedResponseContentType, responseEntity.getContentType().getValue()); + assertEquals(expectedResponseContentType, responseEntity.getContentType()); final String responseBody; try (final InputStream is = responseEntity.getContent()) { diff --git a/extensions/modules/file/pom.xml b/extensions/modules/file/pom.xml index 08da6131c37..f7bdaa93eba 100644 --- a/extensions/modules/file/pom.xml +++ b/extensions/modules/file/pom.xml @@ -108,6 +108,14 @@ test + + ${project.groupId} + exist-core + ${project.version} + test-jar + test + + junit junit @@ -122,14 +130,14 @@ - org.apache.httpcomponents - httpcore + org.apache.httpcomponents.core5 + httpcore5 test - org.apache.httpcomponents - fluent-hc + org.apache.httpcomponents.client5 + httpclient5-fluent test diff --git a/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/RestBinariesTest.java b/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/RestBinariesTest.java index de93012eda0..7d969fd2f00 100644 --- a/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/RestBinariesTest.java +++ b/extensions/modules/file/src/test/java/org/exist/xquery/modules/file/RestBinariesTest.java @@ -23,12 +23,12 @@ import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.client.fluent.Executor; -import org.apache.http.client.fluent.Request; -import org.apache.http.entity.ContentType; +import org.apache.hc.client5.http.fluent.Executor; +import org.apache.hc.client5.http.fluent.Request; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.exist.http.AbstractHttpTest; import org.exist.http.jaxb.Query; import org.exist.http.jaxb.Result; import org.exist.test.ExistWebServer; @@ -47,8 +47,8 @@ import java.nio.file.Files; import java.nio.file.Path; -import static org.apache.http.HttpStatus.SC_CREATED; -import static org.apache.http.HttpStatus.SC_OK; +import static org.apache.hc.core5.http.HttpStatus.SC_CREATED; +import static org.apache.hc.core5.http.HttpStatus.SC_OK; import static org.exist.TestUtils.ADMIN_DB_PWD; import static org.exist.TestUtils.ADMIN_DB_USER; import static org.junit.Assert.assertArrayEquals; @@ -65,9 +65,7 @@ public class RestBinariesTest extends AbstractBinariesTest executeXQuery(final String xquery) throws Exception { - final HttpResponse response = postXquery(xquery); + final ClassicHttpResponse response = postXquery(xquery); final HttpEntity entity = response.getEntity(); try(final InputStream is = entity.getContent()) { final JAXBContext jaxbContext = JAXBContext.newInstance("org.exist.http.jaxb"); @@ -160,23 +162,23 @@ protected QueryResultAccessor executeXQuery(final String xque } } - private HttpResponse postXquery(final String xquery) throws JAXBException, IOException { + private ClassicHttpResponse postXquery(final String xquery) throws JAXBException, IOException { final Query query = new Query(); query.setText(xquery); final JAXBContext jaxbContext = JAXBContext.newInstance("org.exist.http.jaxb"); final Marshaller marshaller = jaxbContext.createMarshaller(); - final HttpResponse response; + final ClassicHttpResponse response; try(final UnsynchronizedByteArrayOutputStream baos = UnsynchronizedByteArrayOutputStream.builder().get()) { marshaller.marshal(query, baos); - response = executor.execute(Request.Post(getRestUrl() + "/db/") + response = (ClassicHttpResponse) executor.execute(Request.post(getRestUrl() + "/db/") .bodyByteArray(baos.toByteArray(), ContentType.APPLICATION_XML) ).returnResponse(); } - if(response.getStatusLine().getStatusCode() != SC_OK) { - throw new IOException("Unable to query, HTTP response code: " + response.getStatusLine().getStatusCode()); + if(response.getCode() != SC_OK) { + throw new IOException("Unable to query, HTTP response code: " + response.getCode()); } return response; diff --git a/extensions/modules/persistentlogin/pom.xml b/extensions/modules/persistentlogin/pom.xml index d65335db765..45d1da07e65 100644 --- a/extensions/modules/persistentlogin/pom.xml +++ b/extensions/modules/persistentlogin/pom.xml @@ -100,14 +100,14 @@ - org.apache.httpcomponents - httpcore + org.apache.httpcomponents.core5 + httpcore5 test - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 test diff --git a/extensions/modules/persistentlogin/src/test/java/org/exist/xquery/modules/persistentlogin/LoginModuleIT.java b/extensions/modules/persistentlogin/src/test/java/org/exist/xquery/modules/persistentlogin/LoginModuleIT.java index c6b9dac9a64..de9f38c1c51 100644 --- a/extensions/modules/persistentlogin/src/test/java/org/exist/xquery/modules/persistentlogin/LoginModuleIT.java +++ b/extensions/modules/persistentlogin/src/test/java/org/exist/xquery/modules/persistentlogin/LoginModuleIT.java @@ -21,16 +21,15 @@ */ package org.exist.xquery.modules.persistentlogin; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.config.CookieSpecs; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.protocol.HttpClientContext; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.util.EntityUtils; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.entity.EntityUtils; import org.exist.TestUtils; import org.exist.test.ExistWebServer; import org.exist.xmldb.EXistResource; @@ -48,7 +47,7 @@ import javax.annotation.Nullable; import java.io.IOException; -import static org.apache.http.HttpStatus.SC_OK; +import static org.apache.hc.core5.http.HttpStatus.SC_OK; import static org.junit.Assert.assertEquals; /** @@ -108,12 +107,8 @@ public static void beforeClass() throws XMLDBException { cookieStore = new BasicCookieStore(); httpContext = HttpClientContext.create(); httpContext.setCookieStore(cookieStore); - // Jetty 12 emits RFC 6265 Set-Cookie (RFC1123 Expires). HttpClient 4.x DEFAULT (NetscapeDraftSpec) - // rejects that format; STANDARD is required for automatic cookie storage. See jetty/jetty.project#12771. - client = HttpClientBuilder.create() - .setDefaultRequestConfig(RequestConfig.custom() - .setCookieSpec(CookieSpecs.STANDARD) - .build()) + client = HttpClients.custom() + .disableAutomaticRetries() .build(); } @@ -148,11 +143,17 @@ public void loginAndLogout() throws IOException { private void doGet(@Nullable String params, String expected) throws IOException { final HttpGet httpGet = new HttpGet("http://localhost:" + existWebServer.getPort() + "/rest" + XmldbURI.ROOT_COLLECTION + '/' + XQUERY_FILENAME + (params == null ? "" : "?" + params)); - HttpResponse response = client.execute(httpGet, httpContext); - HttpEntity entity = response.getEntity(); - final String responseBody = EntityUtils.toString(entity); - assertEquals(responseBody, SC_OK, response.getStatusLine().getStatusCode()); - assertEquals(expected, responseBody); + try (final ClassicHttpResponse response = client.executeOpen(null, httpGet, httpContext)) { + final HttpEntity entity = response.getEntity(); + final String responseBody; + try { + responseBody = EntityUtils.toString(entity); + } catch (final ParseException e) { + throw new IOException(e); + } + assertEquals(responseBody, SC_OK, response.getCode()); + assertEquals(expected, responseBody); + } } } diff --git a/extensions/webdav/pom.xml b/extensions/webdav/pom.xml index 3f902141300..d577bd31917 100644 --- a/extensions/webdav/pom.xml +++ b/extensions/webdav/pom.xml @@ -67,9 +67,6 @@ jackrabbit-webdav - - - jakarta.servlet jakarta.servlet-api @@ -92,36 +89,6 @@ test - - - org.exist-db.thirdparty.com.ettrema - milton-client - test - - - org.exist-db.thirdparty.com.ettrema - milton-api - test - - - - com.google.code.findbugs - jsr305 - test - - - - org.apache.httpcomponents - httpclient - test - - - - org.apache.httpcomponents - httpcore - test - - org.eclipse.jetty @@ -172,11 +139,11 @@ true - org.jdom:jdom:jar commons-beanutils:commons-beanutils ${project.groupId}:exist-jetty-config:jar:${project.version} + org.eclipse.jetty:jetty-util:jar:${jetty.version} org.eclipse.jetty:jetty-deploy:jar:${jetty.version} org.eclipse.jetty:jetty-jmx:jar:${jetty.version} diff --git a/extensions/webdav/src/test/java/com/ettrema/cache/Cache.java b/extensions/webdav/src/test/java/com/ettrema/cache/Cache.java deleted file mode 100644 index c60e17b7efa..00000000000 --- a/extensions/webdav/src/test/java/com/ettrema/cache/Cache.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package com.ettrema.cache; - -import javax.annotation.Nullable; - -/** - * Simple guess implementation of a class - * that is missing from Milton but is required by Milton Client. - */ -public interface Cache { - - @Nullable V get(final K key); - - void put(final K key, final V value); - - @Nullable void remove(final K key); -} diff --git a/extensions/webdav/src/test/java/com/ettrema/cache/MemoryCache.java b/extensions/webdav/src/test/java/com/ettrema/cache/MemoryCache.java deleted file mode 100644 index 60d2930382b..00000000000 --- a/extensions/webdav/src/test/java/com/ettrema/cache/MemoryCache.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package com.ettrema.cache; - -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; - -/** - * Simple guess implementation of a class - * that is missing from Milton but is required by Milton Client. - */ -public class MemoryCache implements Cache { - private final String name; - private final int max; - private final int min; - - private final Map storage = new HashMap<>(); - - public MemoryCache(final String name, final int max, final int min) { - this.name = name; - this.max = max; - this.min = min; - } - - @Override - public @Nullable V get(final K key) { - return storage.get(key); - } - - @Override - public void put(final K key, final V value) { - storage.put(key, value); - } - - @Override - public @Nullable void remove(final K key) { - storage.remove(key); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/AlwaysBasicPreAuth.java b/extensions/webdav/src/test/java/org/exist/webdav/AlwaysBasicPreAuth.java deleted file mode 100644 index 6622e74ce05..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/AlwaysBasicPreAuth.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -package org.exist.webdav; - -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.protocol.HttpContext; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; - -class AlwaysBasicPreAuth implements HttpRequestInterceptor { - private final String username; - private final String password; - - public AlwaysBasicPreAuth(final String username, final String password) { - this.username = username; - this.password = password; - } - - @Override - public void process(final HttpRequest request, final HttpContext context) { - String token = Base64.getEncoder().encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8)); - request.addHeader("Authorization", "Basic " + token); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/CDataIntergationTest.java b/extensions/webdav/src/test/java/org/exist/webdav/CDataIntergationTest.java deleted file mode 100644 index 78c2dff9426..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/CDataIntergationTest.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; - -/** - * Tests for retrieving a document containing CDATA via - * WebDAV. - */ -public class CDataIntergationTest { - - private static final String CDATA_CONTENT = "Hello there, \"Bob?\""; - private static final String CDATA_XML = ""; - - @ClassRule - public static final ExistWebServer EXIST_WEB_SERVER = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder TEMP_FOLDER = new TemporaryFolder(); - - private static String PREV_PROPFIND_METHOD_XML_SIZE = null; - - @BeforeClass - public static void setup() { - PREV_PROPFIND_METHOD_XML_SIZE = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); - } - - @AfterClass - public static void cleanup() { - if (PREV_PROPFIND_METHOD_XML_SIZE == null) { - System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); - } else { - System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", PREV_PROPFIND_METHOD_XML_SIZE); - } - } - - @Test - public void cdataWebDavApi() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String docName = "webdav-cdata-test.xml"; - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = EXIST_WEB_SERVER.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient(); - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = TEMP_FOLDER.newFile(); - Files.writeString(tmpStoreFile.toPath(), CDATA_XML); - assertNotNull(folder.uploadFile(docName, tmpStoreFile, null)); - - // retrieve document - final Resource resource = folder.child(docName); - assertNotNull(resource); - assertTrue(resource instanceof File); - assertEquals("application/xml", ((File) resource).contentType); - final java.io.File tempRetrieveFile = TEMP_FOLDER.newFile(); - resource.downloadTo(tempRetrieveFile, null); - assertEquals(CDATA_XML, Files.readString(tempRetrieveFile.toPath())); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/CopyTest.java b/extensions/webdav/src/test/java/org/exist/webdav/CopyTest.java deleted file mode 100644 index 1bad6b8fdd8..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/CopyTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; - -/** - * Tests for copying a document via WebDAV. - */ -public class CopyTest { - - @ClassRule - public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder tempFolder = new TemporaryFolder(); - - private static String PREV_PROPFIND_METHOD_XML_SIZE = null; - - @BeforeClass - public static void setup() { - PREV_PROPFIND_METHOD_XML_SIZE = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); - } - - @AfterClass - public static void cleanup() { - if (PREV_PROPFIND_METHOD_XML_SIZE == null) { - System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); - } else { - System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", PREV_PROPFIND_METHOD_XML_SIZE); - } - } - - @Test - public void copyXmlDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-copy-test.xml"; - final String srcDocContent = "Hello there"; - final String destDocName = "webdav-copied-test.xml"; - copyDocument(srcDocName, srcDocContent, destDocName, "application/xml"); - } - - @Test - public void copyBinDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-copy-test.bin"; - final String srcDocContent = "0123456789"; - final String destDocName = "webdav-copied-test.bin"; - copyDocument(srcDocName, srcDocContent, destDocName, "application/octet-stream"); - } - - private void copyDocument(final String srcDocName, final String srcDocContent, final String destDocName, final String expectedMediaType) throws BadRequestException, HttpException, IOException, NotAuthorizedException, ConflictException, NotFoundException { - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = existWebServer.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient(); - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = tempFolder.newFile(); - Files.writeString(tmpStoreFile.toPath(), srcDocContent); - assertNotNull(folder.uploadFile(srcDocName, tmpStoreFile, null)); - - // retrieve document - final Resource srcResource = folder.child(srcDocName); - assertNotNull(srcResource); - assertTrue(srcResource instanceof File); - assertEquals(expectedMediaType, ((File) srcResource).contentType); - final java.io.File tempRetrievedSrcFile = tempFolder.newFile(); - srcResource.downloadTo(tempRetrievedSrcFile, null); - assertEquals(srcDocContent, Files.readString(tempRetrievedSrcFile.toPath())); - - // copy document - srcResource.copyTo(folder, destDocName); - - // retrieve copied document - final Resource destResource = folder.child(destDocName); - assertNotNull(destResource); - assertTrue(destResource instanceof File); - assertEquals(expectedMediaType, ((File) destResource).contentType); - final java.io.File tempRetrievedDestFile = tempFolder.newFile(); - destResource.downloadTo(tempRetrievedDestFile, null); - assertEquals(srcDocContent, Files.readString(tempRetrievedDestFile.toPath())); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/DeleteTest.java b/extensions/webdav/src/test/java/org/exist/webdav/DeleteTest.java deleted file mode 100644 index 70bad36bcb5..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/DeleteTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; - -/** - * Tests for storing and deleting a document via WebDAV. - */ -public class DeleteTest { - - @ClassRule - public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder tempFolder = new TemporaryFolder(); - - private static String PREV_PROPFIND_METHOD_XML_SIZE = null; - - @BeforeClass - public static void setup() { - PREV_PROPFIND_METHOD_XML_SIZE = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); - } - - @AfterClass - public static void cleanup() { - if (PREV_PROPFIND_METHOD_XML_SIZE == null) { - System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); - } else { - System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", PREV_PROPFIND_METHOD_XML_SIZE); - } - } - - @Test - public void storeAndDeleteXmlDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-store-and-retrieve-test.xml"; - final String srcDocContent = "Hello there"; - storeAndDeleteDocument(srcDocName, srcDocContent, "application/xml"); - } - - @Test - public void storeAndDeleteBinDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-store-and-retrieve-test.bin"; - final String srcDocContent = "0123456789"; - storeAndDeleteDocument(srcDocName, srcDocContent, "application/octet-stream"); - } - - private void storeAndDeleteDocument(final String srcDocName, final String srcDocContent, final String expectedMediaType) throws BadRequestException, HttpException, IOException, NotAuthorizedException, ConflictException, NotFoundException { - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = existWebServer.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient(); - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = tempFolder.newFile(); - Files.writeString(tmpStoreFile.toPath(), srcDocContent); - assertNotNull(folder.uploadFile(srcDocName, tmpStoreFile, null)); - - // retrieve document - final Resource srcResource = folder.child(srcDocName); - assertNotNull(srcResource); - assertTrue(srcResource instanceof File); - assertEquals(expectedMediaType, ((File) srcResource).contentType); - - // delete document - srcResource.delete(); - - // try again to retrieve document... should not be present! - final Resource deletedResource = folder.child(srcDocName); - assertNull(deletedResource); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/LockTest.java b/extensions/webdav/src/test/java/org/exist/webdav/LockTest.java deleted file mode 100644 index 71941bee810..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/LockTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.file.Files; - -import static org.junit.Assert.*; - -/** - * Tests for WebDAV LOCK and UNLOCK operations. - */ -public class LockTest { - - @ClassRule - public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder tempFolder = new TemporaryFolder(); - - @Test - public void lockAndUnlockXmlDocument() throws IOException, NotAuthorizedException, BadRequestException, - HttpException, ConflictException, NotFoundException, URISyntaxException { - final String docName = "webdav-lock-test.xml"; - final String docContent = "lock test"; - - final Host host = buildHost(); - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpFile = tempFolder.newFile(); - Files.writeString(tmpFile.toPath(), docContent); - assertNotNull(folder.uploadFile(docName, tmpFile, null)); - - // lock - final String docUri = docUri(docName); - final String lockToken = host.doLock(docUri); - assertNotNull("LOCK should return a lock token", lockToken); - assertFalse("Lock token should not be empty", lockToken.isEmpty()); - - // unlock - final int unlockStatus = host.doUnLock(docUri, lockToken); - assertTrue("UNLOCK should return 2xx status, got " + unlockStatus, - unlockStatus >= 200 && unlockStatus < 300); - } - - @Test - public void lockAndUnlockBinDocument() throws IOException, NotAuthorizedException, BadRequestException, - HttpException, ConflictException, NotFoundException, URISyntaxException { - final String docName = "webdav-lock-test.bin"; - final String docContent = "binary lock test data"; - - final Host host = buildHost(); - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpFile = tempFolder.newFile(); - Files.writeString(tmpFile.toPath(), docContent); - assertNotNull(folder.uploadFile(docName, tmpFile, null)); - - // lock - final String docUri = docUri(docName); - final String lockToken = host.doLock(docUri); - assertNotNull("LOCK should return a lock token", lockToken); - - // unlock - final int unlockStatus = host.doUnLock(docUri, lockToken); - assertTrue("UNLOCK should return 2xx status, got " + unlockStatus, - unlockStatus >= 200 && unlockStatus < 300); - } - - // Note: RFC 4918 §9.10 requires a second LOCK (without the If header containing the current - // lock token) to return 423 Locked. The ettrema httpclient used in these tests leaves the - // HTTP connection allocated after catching a 4xx response, making it unsuitable for testing - // error-path locking scenarios. That behavior is covered by the litmus compliance suite. - - private String docUri(final String docName) { - return "http://localhost:" + existWebServer.getPort() + "/webdav/db/" + docName; - } - - private Host buildHost() { - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - builder.setPort(existWebServer.getPort()); - builder.setUser(TestUtils.ADMIN_DB_USER); - builder.setPassword(TestUtils.ADMIN_DB_PWD); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // preemptive Basic auth for all requests - final AbstractHttpClient httpClient = (AbstractHttpClient) host.getClient(); - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - return host; - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/RenameTest.java b/extensions/webdav/src/test/java/org/exist/webdav/RenameTest.java deleted file mode 100644 index c1192511c19..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/RenameTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; - -/** - * Tests for renaming a document via WebDAV. - */ -public class RenameTest { - - @ClassRule - public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder tempFolder = new TemporaryFolder(); - - private static String PREV_PROPFIND_METHOD_XML_SIZE = null; - - @BeforeClass - public static void setup() { - PREV_PROPFIND_METHOD_XML_SIZE = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); - } - - @AfterClass - public static void cleanup() { - if (PREV_PROPFIND_METHOD_XML_SIZE == null) { - System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); - } else { - System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", PREV_PROPFIND_METHOD_XML_SIZE); - } - } - - @Test - public void renameXmlDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-store-and-retrieve-test.xml"; - final String srcDocContent = "Hello there"; - renameDocument(srcDocName, srcDocContent, "application/xml"); - } - - @Test - public void renameBinDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-store-and-retrieve-test.bin"; - final String srcDocContent = "0123456789"; - renameDocument(srcDocName, srcDocContent, "application/octet-stream"); - } - - private void renameDocument(final String srcDocName, final String srcDocContent, final String expectedMediaType) throws BadRequestException, HttpException, IOException, NotAuthorizedException, ConflictException, NotFoundException { - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = existWebServer.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient(); - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = tempFolder.newFile(); - Files.writeString(tmpStoreFile.toPath(), srcDocContent); - final String tmpFileName = tmpStoreFile.getName() + "." + srcDocName; - assertNotNull(folder.uploadFile(tmpFileName, tmpStoreFile, null)); - - // rename document - folder.child(tmpFileName).rename(srcDocName); - - // retrieve document - final Resource srcResource = folder.child(srcDocName); - assertNotNull(srcResource); - assertTrue(srcResource instanceof File); - assertEquals(expectedMediaType, ((File) srcResource).contentType); - final java.io.File tempRetrievedSrcFile = tempFolder.newFile(); - srcResource.downloadTo(tempRetrievedSrcFile, null); - assertEquals(srcDocContent, Files.readString(tempRetrievedSrcFile.toPath())); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/ReplaceTest.java b/extensions/webdav/src/test/java/org/exist/webdav/ReplaceTest.java deleted file mode 100644 index ba029216732..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/ReplaceTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; - -/** - * Tests for replacing a document via WebDAV. - */ -public class ReplaceTest { - - @ClassRule - public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder tempFolder = new TemporaryFolder(); - - private static String PREV_PROPFIND_METHOD_XML_SIZE = null; - - @BeforeClass - public static void setup() { - PREV_PROPFIND_METHOD_XML_SIZE = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); - } - - @AfterClass - public static void cleanup() { - if (PREV_PROPFIND_METHOD_XML_SIZE == null) { - System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); - } else { - System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", PREV_PROPFIND_METHOD_XML_SIZE); - } - } - - @Test - public void replaceXmlDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String docName = "webdav-copy-test.xml"; - final String docContent = "Hello there"; - final String replacementDocContent = "Goodbye friend"; - replaceDocument(docName, docContent, replacementDocContent, "application/xml"); - } - - @Test - public void replaceBinDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String docName = "webdav-copy-test.bin"; - final String docContent = "0123456789"; - final String replacementDocContent = "9876543210"; - replaceDocument(docName, docContent, replacementDocContent, "application/octet-stream"); - } - - private void replaceDocument(final String docName, final String docContent, final String replacementDocContent, final String expectedMediaType) throws BadRequestException, HttpException, IOException, NotAuthorizedException, ConflictException, NotFoundException { - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = existWebServer.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient(); - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = tempFolder.newFile(); - Files.writeString(tmpStoreFile.toPath(), docContent); - assertNotNull(folder.uploadFile(docName, tmpStoreFile, null)); - - // retrieve document - final Resource srcResource = folder.child(docName); - assertNotNull(srcResource); - assertTrue(srcResource instanceof File); - assertEquals(expectedMediaType, ((File) srcResource).contentType); - final java.io.File tempRetrievedSrcFile = tempFolder.newFile(); - srcResource.downloadTo(tempRetrievedSrcFile, null); - assertEquals(docContent, Files.readString(tempRetrievedSrcFile.toPath())); - - // replace document - final java.io.File tmpReplacementFile = tempFolder.newFile(); - Files.writeString(tmpReplacementFile.toPath(), replacementDocContent); - assertNotNull(folder.uploadFile(docName, tmpReplacementFile, null)); - - // retrieve replaced document - final Resource replacedResource = folder.child(docName); - assertNotNull(replacedResource); - assertTrue(replacedResource instanceof File); - assertEquals(expectedMediaType, ((File) replacedResource).contentType); - final java.io.File tempRetrievedReplacedFile = tempFolder.newFile(); - replacedResource.downloadTo(tempRetrievedReplacedFile, null); - assertEquals(replacementDocContent, Files.readString(tempRetrievedReplacedFile.toPath())); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/SerializationTest.java b/extensions/webdav/src/test/java/org/exist/webdav/SerializationTest.java deleted file mode 100644 index 9902fe8ca16..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/SerializationTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; -import static org.junit.Assert.assertEquals; - -public class SerializationTest { - - private static final String XML_WITH_DOCTYPE = - """ - - """; - - private static final String XML_WITH_XMLDECL = - """ - - """; - - private static String PREV_PROPFIND_METHOD_XML_SIZE = null; - - @ClassRule - public static final ExistWebServer EXIST_WEB_SERVER = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder TEMP_FOLDER = new TemporaryFolder(); - - @BeforeClass - public static void setup() { - PREV_PROPFIND_METHOD_XML_SIZE = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); - } - - @AfterClass - public static void cleanup() { - if (PREV_PROPFIND_METHOD_XML_SIZE == null) { - System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); - } else { - System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", PREV_PROPFIND_METHOD_XML_SIZE); - } - } - - @Test - public void getDocTypeDefault() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String docName = "test-with-doctype.xml"; - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = EXIST_WEB_SERVER.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - try (final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient()) { - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = TEMP_FOLDER.newFile(); - Files.writeString(tmpStoreFile.toPath(), XML_WITH_DOCTYPE); - assertNotNull(folder.uploadFile(docName, tmpStoreFile, null)); - - // retrieve document - final Resource resource = folder.child(docName); - assertNotNull(resource); - assertTrue(resource instanceof File); - assertEquals("application/xml", ((File) resource).contentType); - final java.io.File tempRetrieveFile = TEMP_FOLDER.newFile(); - resource.downloadTo(tempRetrieveFile, null); - assertEquals(XML_WITH_DOCTYPE, Files.readString(tempRetrieveFile.toPath())); - } - } - - @Test - public void getXmlDeclDefault() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String docName = "test-with-xmldecl.xml"; - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = EXIST_WEB_SERVER.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - try (final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient()) { - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = TEMP_FOLDER.newFile(); - Files.writeString(tmpStoreFile.toPath(), XML_WITH_XMLDECL); - assertNotNull(folder.uploadFile(docName, tmpStoreFile, null)); - - // retrieve document - final Resource resource = folder.child(docName); - assertNotNull(resource); - assertTrue(resource instanceof File); - assertEquals("application/xml", ((File) resource).contentType); - final java.io.File tempRetrieveFile = TEMP_FOLDER.newFile(); - resource.downloadTo(tempRetrieveFile, null); - assertEquals(XML_WITH_XMLDECL, Files.readString(tempRetrieveFile.toPath())); - } - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/StoreAndRetrieveTest.java b/extensions/webdav/src/test/java/org/exist/webdav/StoreAndRetrieveTest.java deleted file mode 100644 index 1fc9560a5cf..00000000000 --- a/extensions/webdav/src/test/java/org/exist/webdav/StoreAndRetrieveTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * eXist-db Open Source Native XML Database - * Copyright (C) 2001 The eXist-db Authors - * - * info@exist-db.org - * http://www.exist-db.org - * - * This library 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.1 of the License, or (at your option) any later version. - * - * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.exist.webdav; - -import com.bradmcevoy.http.exceptions.BadRequestException; -import com.bradmcevoy.http.exceptions.ConflictException; -import com.bradmcevoy.http.exceptions.NotAuthorizedException; -import com.bradmcevoy.http.exceptions.NotFoundException; -import com.ettrema.httpclient.*; -import org.apache.http.impl.client.AbstractHttpClient; -import org.exist.TestUtils; -import org.exist.test.ExistWebServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.nio.file.Files; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.*; - -/** - * Tests for storing and retrieving a document via WebDAV. - */ -public class StoreAndRetrieveTest { - - @ClassRule - public static final ExistWebServer existWebServer = new ExistWebServer(true, false, true, true); - - @ClassRule - public static final TemporaryFolder tempFolder = new TemporaryFolder(); - - private static String PREV_PROPFIND_METHOD_XML_SIZE = null; - - @BeforeClass - public static void setup() { - PREV_PROPFIND_METHOD_XML_SIZE = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); - } - - @AfterClass - public static void cleanup() { - if (PREV_PROPFIND_METHOD_XML_SIZE == null) { - System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); - } else { - System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", PREV_PROPFIND_METHOD_XML_SIZE); - } - } - - @Test - public void storeAndRetrieveXmlDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-store-and-retrieve-test.xml"; - final String srcDocContent = "Hello there"; - storeAndRetrieve(srcDocName, srcDocContent, "application/xml"); - } - - @Test - public void storeAndRetrieveBinDocument() throws IOException, NotAuthorizedException, BadRequestException, HttpException, ConflictException, NotFoundException { - final String srcDocName = "webdav-store-and-retrieve-test.bin"; - final String srcDocContent = "0123456789"; - storeAndRetrieve(srcDocName, srcDocContent, "application/octet-stream"); - } - - private void storeAndRetrieve(final String srcDocName, final String srcDocContent, final String expectedMediaType) throws BadRequestException, HttpException, IOException, NotAuthorizedException, ConflictException, NotFoundException { - final HostBuilder builder = new HostBuilder(); - builder.setServer("localhost"); - final int port = existWebServer.getPort(); - builder.setPort(port); - builder.setRootPath("webdav/db"); - final Host host = builder.buildHost(); - - // workaround pre-emptive auth issues of Milton Client - final AbstractHttpClient httpClient = (AbstractHttpClient)host.getClient(); - httpClient.addRequestInterceptor(new AlwaysBasicPreAuth(TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)); - - final Folder folder = host.getFolder("/"); - assertNotNull(folder); - - // store document - final java.io.File tmpStoreFile = tempFolder.newFile(); - Files.writeString(tmpStoreFile.toPath(), srcDocContent); - assertNotNull(folder.uploadFile(srcDocName, tmpStoreFile, null)); - - // retrieve document - final Resource srcResource = folder.child(srcDocName); - assertNotNull(srcResource); - assertTrue(srcResource instanceof File); - assertEquals(expectedMediaType, ((File) srcResource).contentType); - final java.io.File tempRetrievedSrcFile = tempFolder.newFile(); - srcResource.downloadTo(tempRetrievedSrcFile, null); - assertEquals(srcDocContent, Files.readString(tempRetrievedSrcFile.toPath())); - } -} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/WebDavHttpTest.java b/extensions/webdav/src/test/java/org/exist/webdav/WebDavHttpTest.java new file mode 100644 index 00000000000..7a939bfc841 --- /dev/null +++ b/extensions/webdav/src/test/java/org/exist/webdav/WebDavHttpTest.java @@ -0,0 +1,85 @@ +/* + * eXist-db Open Source Native XML Database + * Copyright (C) 2001 The eXist-db Authors + * + * info@exist-db.org + * http://www.exist-db.org + * + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.webdav; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +/** + * Minimal JDK {@link HttpClient} helper for WebDAV PUT/GET round-trip tests. + * RFC compliance is covered by litmus ({@code exist-docker/.../04-webdav-litmus.bats}). + */ +final class WebDavHttpTest { + + private final HttpClient client; + private final String collectionUri; + private final String authorizationHeader; + + WebDavHttpTest(final int port, final String username, final String password) { + this.collectionUri = "http://localhost:" + port + "/webdav/db/"; + this.authorizationHeader = basicAuthorization(username, password); + this.client = HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); + } + + int putDocument(final String name, final String content, final String contentType) + throws IOException, InterruptedException { + final HttpRequest request = HttpRequest.newBuilder(documentUri(name)) + .PUT(HttpRequest.BodyPublishers.ofString(content, StandardCharsets.UTF_8)) + .header("Authorization", authorizationHeader) + .header("Content-Type", contentType) + .build(); + return client.send(request, HttpResponse.BodyHandlers.discarding()).statusCode(); + } + + HttpResponse getDocument(final String name) throws IOException, InterruptedException { + final HttpRequest request = HttpRequest.newBuilder(documentUri(name)) + .GET() + .header("Authorization", authorizationHeader) + .build(); + return client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + } + + int deleteDocument(final String name) throws IOException, InterruptedException { + final HttpRequest request = HttpRequest.newBuilder(documentUri(name)) + .DELETE() + .header("Authorization", authorizationHeader) + .build(); + return client.send(request, HttpResponse.BodyHandlers.discarding()).statusCode(); + } + + private URI documentUri(final String name) { + return URI.create(collectionUri + name); + } + + private static String basicAuthorization(final String username, final String password) { + final String credentials = username + ":" + password; + final String encoded = Base64.getEncoder().encodeToString(credentials.getBytes(StandardCharsets.UTF_8)); + return "Basic " + encoded; + } +} diff --git a/extensions/webdav/src/test/java/org/exist/webdav/WebDavRoundTripTest.java b/extensions/webdav/src/test/java/org/exist/webdav/WebDavRoundTripTest.java new file mode 100644 index 00000000000..5fb634b5c6b --- /dev/null +++ b/extensions/webdav/src/test/java/org/exist/webdav/WebDavRoundTripTest.java @@ -0,0 +1,133 @@ +/* + * eXist-db Open Source Native XML Database + * Copyright (C) 2001 The eXist-db Authors + * + * info@exist-db.org + * http://www.exist-db.org + * + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.webdav; + +import org.exist.TestUtils; +import org.exist.test.ExistWebServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.net.http.HttpResponse; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * eXist-specific WebDAV round-trip tests (XML serialization edge cases). + * Replaces the former milton-client JUnit suite; protocol compliance is covered by litmus. + */ +public class WebDavRoundTripTest { + + private static final String XML_WITH_DOCTYPE = + """ + + """; + + private static final String XML_WITH_XMLDECL = + """ + + """; + + private static final String CDATA_XML = ""; + + @ClassRule + public static final ExistWebServer EXIST_WEB_SERVER = new ExistWebServer(true, false, true, true); + + private static final List STORED_DOCUMENTS = new ArrayList<>(); + + private static String prevPropfindMethodXmlSize = null; + + @BeforeClass + public static void setup() { + prevPropfindMethodXmlSize = System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", "exact"); + } + + @AfterClass + public static void cleanup() throws Exception { + try { + deleteStoredDocuments(); + } finally { + if (prevPropfindMethodXmlSize == null) { + System.clearProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE"); + } else { + System.setProperty("org.exist.webdav.PROPFIND_METHOD_XML_SIZE", prevPropfindMethodXmlSize); + } + } + } + + @Test + public void getDocTypeDefault() throws Exception { + assertEquals(XML_WITH_DOCTYPE, roundTrip("test-with-doctype.xml", XML_WITH_DOCTYPE, "application/xml")); + } + + @Test + public void getXmlDeclDefault() throws Exception { + assertEquals(XML_WITH_XMLDECL, roundTrip("test-with-xmldecl.xml", XML_WITH_XMLDECL, "application/xml")); + } + + @Test + public void cdataWebDavApi() throws Exception { + assertEquals(CDATA_XML, roundTrip("webdav-cdata-test.xml", CDATA_XML, "application/xml")); + } + + @Test + public void storeAndRetrieveBinDocument() throws Exception { + assertEquals("0123456789", roundTrip("webdav-roundtrip-test.bin", "0123456789", "application/octet-stream")); + } + + private String roundTrip(final String docName, final String content, final String expectedMediaType) throws Exception { + STORED_DOCUMENTS.add(docName); + + final WebDavHttpTest webDav = new WebDavHttpTest( + EXIST_WEB_SERVER.getPort(), TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD); + + final int putStatus = webDav.putDocument(docName, content, expectedMediaType); + assertEquals("PUT " + docName + " failed with status " + putStatus, 201, putStatus); + + final HttpResponse getResponse = webDav.getDocument(docName); + assertEquals("GET " + docName + " failed", 200, getResponse.statusCode()); + final String contentType = getResponse.headers().firstValue("Content-Type").orElse(""); + assertTrue("Unexpected Content-Type: " + contentType, contentType.startsWith(expectedMediaType)); + return getResponse.body(); + } + + private static void deleteStoredDocuments() throws Exception { + if (STORED_DOCUMENTS.isEmpty()) { + return; + } + final WebDavHttpTest webDav = new WebDavHttpTest( + EXIST_WEB_SERVER.getPort(), TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD); + for (final String docName : STORED_DOCUMENTS) { + final int deleteStatus = webDav.deleteDocument(docName); + assertTrue("DELETE " + docName + " failed with status " + deleteStatus, isSuccess(deleteStatus)); + } + STORED_DOCUMENTS.clear(); + } + + private static boolean isSuccess(final int status) { + return status >= 200 && status < 300; + } +}