From 2326f1337591da5f183a5e5785844d7fb5c274b5 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Mon, 23 Sep 2024 15:08:49 +0200 Subject: [PATCH] Use HTTP handler for package resources publication --- org.argeo.cms.ee/OSGI-INF/pkgServlet.xml | 9 --- org.argeo.cms.ee/bnd.bnd | 2 - org.argeo.cms/OSGI-INF/pkgHttpHandler.xml | 9 +++ org.argeo.cms/bnd.bnd | 4 +- .../src/org/argeo/cms/http/HttpStatus.java | 8 +++ .../cms/internal/http/PkgHttpHandler.java | 58 ++++++++++++------- 6 files changed, 58 insertions(+), 32 deletions(-) delete mode 100644 org.argeo.cms.ee/OSGI-INF/pkgServlet.xml create mode 100644 org.argeo.cms/OSGI-INF/pkgHttpHandler.xml rename org.argeo.cms.ee/src/org/argeo/cms/servlet/internal/PkgServlet.java => org.argeo.cms/src/org/argeo/cms/internal/http/PkgHttpHandler.java (70%) diff --git a/org.argeo.cms.ee/OSGI-INF/pkgServlet.xml b/org.argeo.cms.ee/OSGI-INF/pkgServlet.xml deleted file mode 100644 index 05978e669..000000000 --- a/org.argeo.cms.ee/OSGI-INF/pkgServlet.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/org.argeo.cms.ee/bnd.bnd b/org.argeo.cms.ee/bnd.bnd index 592abffdb..83df366bb 100644 --- a/org.argeo.cms.ee/bnd.bnd +++ b/org.argeo.cms.ee/bnd.bnd @@ -10,6 +10,4 @@ org.argeo.cms.osgi,\ Service-Component:\ -OSGI-INF/pkgServletContext.xml,\ -OSGI-INF/pkgServlet.xml,\ OSGI-INF/statusHandler.xml,\ diff --git a/org.argeo.cms/OSGI-INF/pkgHttpHandler.xml b/org.argeo.cms/OSGI-INF/pkgHttpHandler.xml new file mode 100644 index 000000000..4afd9a65e --- /dev/null +++ b/org.argeo.cms/OSGI-INF/pkgHttpHandler.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/org.argeo.cms/bnd.bnd b/org.argeo.cms/bnd.bnd index bcba7939e..3fd92c226 100644 --- a/org.argeo.cms/bnd.bnd +++ b/org.argeo.cms/bnd.bnd @@ -1,6 +1,7 @@ Bundle-Activator: org.argeo.cms.internal.osgi.CmsActivator Import-Package: \ +org.osgi.framework.namespace,\ * Export-Package:\ @@ -15,8 +16,9 @@ OSGI-INF/transactionManager.xml,\ OSGI-INF/cmsUserAdmin.xml,\ OSGI-INF/cmsUserManager.xml,\ OSGI-INF/cmsContentRepository.xml,\ -OSGI-INF/cmsAcrHttpHandler.xml,\ OSGI-INF/cmsDeployment.xml,\ OSGI-INF/cmsContext.xml,\ OSGI-INF/cmsFileSystemProvider.xml,\ +OSGI-INF/cmsAcrHttpHandler.xml,\ +OSGI-INF/pkgHttpHandler.xml,\ diff --git a/org.argeo.cms/src/org/argeo/cms/http/HttpStatus.java b/org.argeo.cms/src/org/argeo/cms/http/HttpStatus.java index 3b9a47a38..f899bdcee 100644 --- a/org.argeo.cms/src/org/argeo/cms/http/HttpStatus.java +++ b/org.argeo.cms/src/org/argeo/cms/http/HttpStatus.java @@ -7,15 +7,23 @@ package org.argeo.cms.http; */ public enum HttpStatus { // Successful responses (200–299) + /** 200 */ OK(200, "OK"), // + /** 204 */ NO_CONTENT(204, "No Content"), // + /** 207 */ MULTI_STATUS(207, "Multi-Status"), // WebDav // Client error responses (400–499) + /** 401 */ UNAUTHORIZED(401, "Unauthorized"), // + /** 403 */ FORBIDDEN(403, "Forbidden"), // + /** 404 */ NOT_FOUND(404, "Not Found"), // // Server error responses (500-599) + /** 500 */ INTERNAL_SERVER_ERROR(500, "Internal Server Error"), // + /** 501 */ NOT_IMPLEMENTED(501, "Not Implemented"), // ; diff --git a/org.argeo.cms.ee/src/org/argeo/cms/servlet/internal/PkgServlet.java b/org.argeo.cms/src/org/argeo/cms/internal/http/PkgHttpHandler.java similarity index 70% rename from org.argeo.cms.ee/src/org/argeo/cms/servlet/internal/PkgServlet.java rename to org.argeo.cms/src/org/argeo/cms/internal/http/PkgHttpHandler.java index 07e3ccca0..a737ab672 100644 --- a/org.argeo.cms.ee/src/org/argeo/cms/servlet/internal/PkgServlet.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/http/PkgHttpHandler.java @@ -1,25 +1,24 @@ -package org.argeo.cms.servlet.internal; +package org.argeo.cms.internal.http; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.net.FileNameMap; import java.net.URL; import java.net.URLConnection; import java.util.Collection; +import java.util.Collections; import java.util.SortedMap; import java.util.TreeMap; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - +import org.argeo.cms.http.HttpHeader; +import org.argeo.cms.http.HttpStatus; +import org.argeo.cms.http.server.HttpServerUtils; import org.argeo.cms.osgi.FilterRequirement; import org.argeo.cms.osgi.PublishNamespace; import org.argeo.cms.util.StreamUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; import org.osgi.framework.namespace.PackageNamespace; @@ -28,20 +27,31 @@ import org.osgi.framework.wiring.BundleWiring; import org.osgi.framework.wiring.FrameworkWiring; import org.osgi.resource.Requirement; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; + /** * Publishes client-side web resources (JavaScript, HTML, CSS, images, etc.) * from the OSGi runtime. */ -public class PkgServlet extends HttpServlet { - private static final long serialVersionUID = 7660824185145214324L; +public class PkgHttpHandler implements HttpHandler { + // TODO make it configurable? + private FileNameMap fileNameMap = URLConnection.getFileNameMap(); - private static FileNameMap fileNameMap = URLConnection.getFileNameMap(); + private FrameworkWiring frameworkWiring = null; - private BundleContext bundleContext = FrameworkUtil.getBundle(PkgServlet.class).getBundleContext(); + public void start(BundleContext bundleContext) { + this.frameworkWiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class); + } + + public void stop() { + this.frameworkWiring = null; + } @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String pathInfo = req.getPathInfo(); + public void handle(HttpExchange exchange) throws IOException { + // String pathInfo = req.getPathInfo(); + String pathInfo = HttpServerUtils.subPath(exchange); String pkg, versionStr, file; String[] parts = pathInfo.split("/"); @@ -60,9 +70,10 @@ public class PkgServlet extends HttpServlet { // content type String contentType = fileNameMap.getContentTypeFor(file); - resp.setContentType(contentType); + exchange.getResponseHeaders().put(HttpHeader.CONTENT_TYPE.getHeaderName(), + Collections.singletonList(contentType)); +// resp.setContentType(contentType); - FrameworkWiring frameworkWiring = bundleContext.getBundle(0).adapt(FrameworkWiring.class); String filter; if (versionStr == null) { filter = "(" + PackageNamespace.PACKAGE_NAMESPACE + "=" + pkg + ")"; @@ -81,7 +92,8 @@ public class PkgServlet extends HttpServlet { Requirement requirement = new FilterRequirement(PackageNamespace.PACKAGE_NAMESPACE, filter); Collection packages = frameworkWiring.findProviders(requirement); if (packages.isEmpty()) { - resp.sendError(404); +// resp.sendError(404); + exchange.sendResponseHeaders(HttpStatus.NOT_FOUND.getCode(), -1); return; } @@ -95,7 +107,8 @@ public class PkgServlet extends HttpServlet { String entryPath = '/' + pkg.replace('.', '/') + '/' + file; URL internalURL = bundle.getResource(entryPath); if (internalURL == null) { - resp.sendError(404); +// resp.sendError(404); + exchange.sendResponseHeaders(HttpStatus.NOT_FOUND.getCode(), -1); return; } @@ -133,12 +146,17 @@ public class PkgServlet extends HttpServlet { } if (!publish) { - resp.sendError(404); +// resp.sendError(404); + exchange.sendResponseHeaders(HttpStatus.NOT_FOUND.getCode(), -1); return; } - try (InputStream in = internalURL.openStream()) { - StreamUtils.copy(in, resp.getOutputStream()); + // TODO cache length? + exchange.sendResponseHeaders(HttpStatus.OK.getCode(), 0); + try (InputStream in = internalURL.openStream(); // + OutputStream out = exchange.getResponseBody();) { +// StreamUtils.copy(in, resp.getOutputStream()); + StreamUtils.copy(in, out); } } -- 2.39.5