From b897c27d370ad4772b5ae4b2c22cc505ef5d1a3f Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Thu, 15 Sep 2022 06:11:27 +0200 Subject: [PATCH] HTTP GET support for ACR. --- .../src/org/argeo/api/acr/CrName.java | 36 +++++++++--------- .../src/org/argeo/api/cms/CmsConstants.java | 4 +- org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml | 1 + .../org/argeo/cms/acr/CmsContentSession.java | 2 + .../internal/runtime/CmsAcrHttpHandler.java | 38 ++++++++++++++++++- .../src/org/argeo/util/dav/DavResponse.java | 2 +- .../org/argeo/util/dav/DavServerHandler.java | 10 +++-- .../org/argeo/util/dav/MultiStatusReader.java | 2 +- .../argeo/util/http/HttpResponseStatus.java | 5 ++- .../argeo/cms/swt/acr/AcrSwtImageManager.java | 2 +- 10 files changed, 73 insertions(+), 29 deletions(-) diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/CrName.java b/org.argeo.api.acr/src/org/argeo/api/acr/CrName.java index 22aa82b91..3fe3462b9 100644 --- a/org.argeo.api.acr/src/org/argeo/api/acr/CrName.java +++ b/org.argeo.api.acr/src/org/argeo/api/acr/CrName.java @@ -1,9 +1,7 @@ package org.argeo.api.acr; -import javax.xml.namespace.QName; - /** Standard names. */ -public enum CrName { +public enum CrName implements QNamed { /* * TYPES @@ -14,7 +12,7 @@ public enum CrName { * ATTRIBUTES */ uuid, // the UUID of a content - mount, + mount, // a mount point cc, // content class /* @@ -45,24 +43,24 @@ public enum CrName { public final static String ROLE_NAMESPACE_URI = "http://www.argeo.org/ns/role"; public final static String ROLE_DEFAULT_PREFIX = "role"; - private final ContentName value; - - CrName() { - value = new ContentName(CR_NAMESPACE_URI, name(), RuntimeNamespaceContext.getNamespaceContext()); - } - - public QName qName() { - return value; - } +// private final ContentName value; -// @Override -// public String getNamespaceURI() { -// return CR_NAMESPACE_URI; +// CrName() { +// value = new ContentName(CR_NAMESPACE_URI, name(), RuntimeNamespaceContext.getNamespaceContext()); // } // -// @Override -// public String getDefaultPrefix() { -// return CR_DEFAULT_PREFIX; +// public QName qName() { +// return value; // } + @Override + public String getNamespace() { + return CR_NAMESPACE_URI; + } + + @Override + public String getDefaultPrefix() { + return CR_DEFAULT_PREFIX; + } + } diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/CmsConstants.java b/org.argeo.api.cms/src/org/argeo/api/cms/CmsConstants.java index 29cf12e2b..bae874b16 100644 --- a/org.argeo.api.cms/src/org/argeo/api/cms/CmsConstants.java +++ b/org.argeo.api.cms/src/org/argeo/api/cms/CmsConstants.java @@ -36,12 +36,11 @@ public interface CmsConstants { String PUBLIC_WORKSPACE = "public"; String SECURITY_WORKSPACE = "security"; String MIGRATION_WORKSPACE = "migration"; - + /* * ACR CONVENTIONS */ String SRV_BASE = "/srv"; - /* * BASE DNs @@ -76,6 +75,7 @@ public interface CmsConstants { String PATH_JCR = "/jcr"; String PATH_FILES = "/files"; // String PATH_JCR_PUB = "/pub"; + String PATH_API_ACR = "/api/acr"; /* * FILE SYSTEMS diff --git a/org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml b/org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml index 35b144935..6b05a9004 100644 --- a/org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml +++ b/org.argeo.cms/OSGI-INF/cmsAcrHttpHandler.xml @@ -5,4 +5,5 @@ + diff --git a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java index 9f10d3f31..757dad143 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java @@ -61,6 +61,8 @@ class CmsContentSession implements ProvidedSession { @Override public Content get(String path) { + if (!path.startsWith(ContentUtils.ROOT_SLASH)) + throw new IllegalArgumentException(path + " is not an absolute path"); ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path); String mountPath = contentProvider.getMountPath(); String relativePath = extractRelativePath(mountPath, path); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java index d9fa9e751..7799a8c4e 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsAcrHttpHandler.java @@ -1,7 +1,43 @@ package org.argeo.cms.internal.runtime; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; + +import org.argeo.api.acr.Content; +import org.argeo.api.acr.ContentSession; +import org.argeo.api.acr.CrName; +import org.argeo.api.acr.spi.ProvidedRepository; +import org.argeo.cms.acr.ContentUtils; +import org.argeo.cms.auth.RemoteAuthUtils; +import org.argeo.cms.internal.http.RemoteAuthHttpExchange; +import org.argeo.util.StreamUtils; import org.argeo.util.dav.DavServerHandler; +import org.argeo.util.http.HttpResponseStatus; +import org.argeo.util.http.HttpServerUtils; + +import com.sun.net.httpserver.HttpExchange; + +public class CmsAcrHttpHandler extends DavServerHandler { + private ProvidedRepository contentRepository; + + @Override + protected void handleGET(HttpExchange exchange) { + ContentSession session = RemoteAuthUtils.doAs(() -> contentRepository.get(), + new RemoteAuthHttpExchange(exchange)); + String relativePath = HttpServerUtils.relativize(exchange); + Content content = session.get(ContentUtils.ROOT_SLASH + relativePath); + Optional size = content.get(CrName.size, Long.class); + try (InputStream in = content.open(InputStream.class)) { + exchange.sendResponseHeaders(HttpResponseStatus.OK.getStatusCode(), size.orElse(0l)); + StreamUtils.copy(in, exchange.getResponseBody()); + } catch (IOException e) { + throw new RuntimeException("Cannot process " + relativePath, e); + } + } -public class CmsAcrHttpHandler extends DavServerHandler { + public void setContentRepository(ProvidedRepository contentRepository) { + this.contentRepository = contentRepository; + } } diff --git a/org.argeo.util/src/org/argeo/util/dav/DavResponse.java b/org.argeo.util/src/org/argeo/util/dav/DavResponse.java index 22ffa17d1..424a0e8b7 100644 --- a/org.argeo.util/src/org/argeo/util/dav/DavResponse.java +++ b/org.argeo.util/src/org/argeo/util/dav/DavResponse.java @@ -10,7 +10,7 @@ import java.util.Set; import javax.xml.namespace.QName; public class DavResponse { - final static String MODE_DAV_NAMESPACE = "http://apache.org/dav/props/"; + final static String MOD_DAV_NAMESPACE = "http://apache.org/dav/props/"; private String href; private boolean collection; diff --git a/org.argeo.util/src/org/argeo/util/dav/DavServerHandler.java b/org.argeo.util/src/org/argeo/util/dav/DavServerHandler.java index f9fba4761..29d689dbb 100644 --- a/org.argeo.util/src/org/argeo/util/dav/DavServerHandler.java +++ b/org.argeo.util/src/org/argeo/util/dav/DavServerHandler.java @@ -13,17 +13,21 @@ public class DavServerHandler implements HttpHandler { public void handle(HttpExchange exchange) throws IOException { String method = exchange.getRequestMethod(); if (DavMethod.PROPFIND.name().equals(method)) { - handle(exchange); + handlePROPFIND(exchange); } else if (HttpMethod.GET.name().equals(method)) { - exchange.getResponseBody().write("Hello Dav!".getBytes()); + handleGET(exchange); } else { throw new IllegalArgumentException("Unsupported method " + method); } } + protected void handleGET(HttpExchange exchange) { + throw new UnsupportedOperationException(); + } + protected DavResponse handlePROPFIND(HttpExchange exchange) { - return null; + throw new UnsupportedOperationException(); } } diff --git a/org.argeo.util/src/org/argeo/util/dav/MultiStatusReader.java b/org.argeo.util/src/org/argeo/util/dav/MultiStatusReader.java index 966100e4a..cc7921523 100644 --- a/org.argeo.util/src/org/argeo/util/dav/MultiStatusReader.java +++ b/org.argeo.util/src/org/argeo/util/dav/MultiStatusReader.java @@ -98,7 +98,7 @@ class MultiStatusReader implements Iterator { value = reader.getText(); } - if (name.getNamespaceURI().equals(DavResponse.MODE_DAV_NAMESPACE)) + if (name.getNamespaceURI().equals(DavResponse.MOD_DAV_NAMESPACE)) continue elements; // skip mod_dav properties assert currentResponse != null; diff --git a/org.argeo.util/src/org/argeo/util/http/HttpResponseStatus.java b/org.argeo.util/src/org/argeo/util/http/HttpResponseStatus.java index ec67cce5e..db7fbe30b 100644 --- a/org.argeo.util/src/org/argeo/util/http/HttpResponseStatus.java +++ b/org.argeo.util/src/org/argeo/util/http/HttpResponseStatus.java @@ -6,9 +6,12 @@ package org.argeo.util.http; * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status */ public enum HttpResponseStatus { + // Successful responses (200–299) + OK(200), // + // Client error responses (400–499) UNAUTHORIZED(401), // FORBIDDEN(403), // - NOT_FOUND(404),// + NOT_FOUND(404), // ; private final int statusCode; diff --git a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java index e683d9630..78a993005 100644 --- a/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java +++ b/swt/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/AcrSwtImageManager.java @@ -41,7 +41,7 @@ public class AcrSwtImageManager extends AbstractSwtImageManager { /** A path in the node repository */ protected String getDataPath(Content node) { // TODO make it more configurable? - StringBuilder buf = new StringBuilder(CmsConstants.PATH_DATA); + StringBuilder buf = new StringBuilder(CmsConstants.PATH_API_ACR); buf.append(node.getPath()); return buf.toString(); } -- 2.30.2