This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 162d68c85c7 embedded HTTP server can now be used for static pages like
a html web app (#15399)
162d68c85c7 is described below
commit 162d68c85c7ac62d6a28019a0116c53184cf356b
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 2 17:07:51 2024 +0200
embedded HTTP server can now be used for static pages like a html web app
(#15399)
CAMEL-21110: Add support for serving static content in embedded main HTTP
server
---
.../main/camel-main-configuration-metadata.json | 2 +
.../http/main/DefaultMainHttpServerFactory.java | 2 +
.../platform/http/main/MainHttpServer.java | 91 ++++++++++++++++++++++
...ttpServerConfigurationPropertiesConfigurer.java | 12 +++
.../camel-main-configuration-metadata.json | 2 +
core/camel-main/src/main/docs/main.adoc | 4 +-
.../main/HttpServerConfigurationProperties.java | 45 +++++++++++
7 files changed, 157 insertions(+), 1 deletion(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index df98648028e..a4e6e092707 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -274,6 +274,8 @@
{ "name": "camel.server.metricsEnabled", "description": "Whether to enable
metrics. If enabled then you can access metrics on context-path: \/q\/metrics",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "boolean", "javaType": "boolean", "defaultValue": "false" },
{ "name": "camel.server.path", "description": "Context-path to use for
embedded HTTP server", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "defaultValue": "\/" },
{ "name": "camel.server.port", "description": "Port to use for binding
embedded HTTP server", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer",
"javaType": "int", "defaultValue": 8080 },
+ { "name": "camel.server.staticContextPath", "description": "The
context-path to use for serving static content. By default, the root path is
used. And if there is an index.html page then this is automatically loaded.",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "defaultValue": "\/" },
+ { "name": "camel.server.staticEnabled", "description": "Whether serving
static files is enabled. If enabled then Camel can host html\/js and other web
files that makes it possible to include small web applications.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": "false" },
{ "name": "camel.server.uploadEnabled", "description": "Whether to enable
file upload via HTTP (not intended for production use). This functionality is
for development to be able to reload Camel routes and code with source changes
(if reload is enabled). If enabled then you can upload\/delete files via HTTP
PUT\/DELETE on context-path: \/q\/upload\/{name}. You must also configure the
uploadSourceDir option.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "t [...]
{ "name": "camel.server.uploadSourceDir", "description": "Source directory
when upload is enabled.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String" },
{ "name": "camel.server.useGlobalSslContextParameters", "description":
"Whether to use global SSL configuration for securing the embedded HTTP
server.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": "false" },
diff --git
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
index d0de015667a..e1da6e422de 100644
---
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
+++
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
@@ -55,6 +55,8 @@ public class DefaultMainHttpServerFactory implements
CamelContextAware, MainHttp
}
server.setUseGlobalSslContextParameters(configuration.isUseGlobalSslContextParameters());
server.setInfoEnabled(configuration.isInfoEnabled());
+ server.setStaticEnabled(configuration.isStaticEnabled());
+ server.setStaticContextPath(configuration.getStaticContextPath());
server.setDevConsoleEnabled(configuration.isDevConsoleEnabled());
server.setHealthCheckEnabled(configuration.isHealthCheckEnabled());
server.setJolokiaEnabled(configuration.isJolokiaEnabled());
diff --git
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
index 94a03fcf682..c2d3169462d 100644
---
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
+++
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
@@ -17,8 +17,10 @@
package org.apache.camel.component.platform.http.main;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.ArrayList;
@@ -37,6 +39,7 @@ import java.util.stream.Collectors;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.impl.MimeMapping;
import io.vertx.ext.web.RequestBody;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.RoutingContext;
@@ -102,6 +105,8 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
private VertxPlatformHttpServerConfiguration configuration = new
VertxPlatformHttpServerConfiguration();
private boolean infoEnabled;
+ private boolean staticEnabled;
+ private String staticContextPath;
private boolean devConsoleEnabled;
private boolean healthCheckEnabled;
private boolean jolokiaEnabled;
@@ -137,6 +142,29 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
this.infoEnabled = infoEnabled;
}
+ @ManagedAttribute(description = "Whether serving static content is enabled
(such as html pages)")
+ public boolean isStaticEnabled() {
+ return staticEnabled;
+ }
+
+ public void setStaticEnabled(boolean staticEnabled) {
+ this.staticEnabled = staticEnabled;
+ }
+
+ @ManagedAttribute(description = "The context-path for serving static
content")
+ public String getStaticContextPath() {
+ return staticContextPath;
+ }
+
+ public void setStaticContextPath(String staticContextPath) {
+ this.staticContextPath = staticContextPath;
+ }
+
+ @ManagedAttribute(description = "Whether serving static content is enabled
(such as html pages)")
+ public boolean isStaticFilePattern() {
+ return staticEnabled;
+ }
+
@ManagedAttribute(description = "Whether dev console is enabled (/q/dev)")
public boolean isDevConsoleEnabled() {
return devConsoleEnabled;
@@ -336,6 +364,9 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
if (infoEnabled) {
setupInfo();
}
+ if (staticEnabled) {
+ setupStatic();
+ }
if (devConsoleEnabled) {
setupDevConsole();
}
@@ -437,6 +468,66 @@ public class MainHttpServer extends ServiceSupport
implements CamelContextAware,
});
}
+ protected void setupStatic() {
+ String path = staticContextPath;
+ if (!path.endsWith("*")) {
+ path = path + "*";
+ }
+ final Route web = router.route(path);
+ web.produces("*");
+ web.consumes("*");
+ web.order(Integer.MAX_VALUE); // run this last so all other are served
first
+
+ Handler<RoutingContext> handler = new Handler<RoutingContext>() {
+ @Override
+ public void handle(RoutingContext ctx) {
+ String u = ctx.normalizedPath();
+ if (u.isBlank() || u.endsWith("/") || u.equals("index.html")) {
+ u = "index.html";
+ } else {
+ u = FileUtil.stripLeadingSeparator(u);
+ }
+
+ InputStream is = null;
+ File f = new File(u);
+ if (f.exists()) {
+ // load directly from file system first
+ try {
+ is = new FileInputStream(f);
+ } catch (Exception e) {
+ // ignore
+ }
+ } else {
+ is =
camelContext.getClassResolver().loadResourceAsStream(u);
+ }
+ if (is != null) {
+ String mime =
MimeMapping.getMimeTypeForFilename(f.getName());
+ if (mime != null) {
+ ctx.response().putHeader("content-type", mime);
+ }
+ String text = null;
+ try {
+ text = IOHelper.loadText(is);
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ IOHelper.close(is);
+ }
+ ctx.response().setStatusCode(200);
+ ctx.end(text);
+ } else {
+ ctx.response().setStatusCode(404);
+ ctx.end();
+ }
+ }
+ };
+
+ // use blocking handler as the task can take longer time to complete
+ web.handler(new BlockingHandlerDecorator(handler, true));
+
+ platformHttpComponent.addHttpEndpoint(staticContextPath, null, null,
null, null);
+ }
+
protected void setupInfo() {
final Route info = router.route("/q/info");
info.method(HttpMethod.GET);
diff --git
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
index d90376adc33..af40d20036f 100644
---
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
+++
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
@@ -53,6 +53,10 @@ public class HttpServerConfigurationPropertiesConfigurer
extends org.apache.came
case "metricsEnabled": target.setMetricsEnabled(property(camelContext,
boolean.class, value)); return true;
case "path": target.setPath(property(camelContext,
java.lang.String.class, value)); return true;
case "port": target.setPort(property(camelContext, int.class, value));
return true;
+ case "staticcontextpath":
+ case "staticContextPath":
target.setStaticContextPath(property(camelContext, java.lang.String.class,
value)); return true;
+ case "staticenabled":
+ case "staticEnabled": target.setStaticEnabled(property(camelContext,
boolean.class, value)); return true;
case "uploadenabled":
case "uploadEnabled": target.setUploadEnabled(property(camelContext,
boolean.class, value)); return true;
case "uploadsourcedir":
@@ -96,6 +100,10 @@ public class HttpServerConfigurationPropertiesConfigurer
extends org.apache.came
case "metricsEnabled": return boolean.class;
case "path": return java.lang.String.class;
case "port": return int.class;
+ case "staticcontextpath":
+ case "staticContextPath": return java.lang.String.class;
+ case "staticenabled":
+ case "staticEnabled": return boolean.class;
case "uploadenabled":
case "uploadEnabled": return boolean.class;
case "uploadsourcedir":
@@ -140,6 +148,10 @@ public class HttpServerConfigurationPropertiesConfigurer
extends org.apache.came
case "metricsEnabled": return target.isMetricsEnabled();
case "path": return target.getPath();
case "port": return target.getPort();
+ case "staticcontextpath":
+ case "staticContextPath": return target.getStaticContextPath();
+ case "staticenabled":
+ case "staticEnabled": return target.isStaticEnabled();
case "uploadenabled":
case "uploadEnabled": return target.isUploadEnabled();
case "uploadsourcedir":
diff --git
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index df98648028e..a4e6e092707 100644
---
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -274,6 +274,8 @@
{ "name": "camel.server.metricsEnabled", "description": "Whether to enable
metrics. If enabled then you can access metrics on context-path: \/q\/metrics",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "boolean", "javaType": "boolean", "defaultValue": "false" },
{ "name": "camel.server.path", "description": "Context-path to use for
embedded HTTP server", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "defaultValue": "\/" },
{ "name": "camel.server.port", "description": "Port to use for binding
embedded HTTP server", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer",
"javaType": "int", "defaultValue": 8080 },
+ { "name": "camel.server.staticContextPath", "description": "The
context-path to use for serving static content. By default, the root path is
used. And if there is an index.html page then this is automatically loaded.",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "defaultValue": "\/" },
+ { "name": "camel.server.staticEnabled", "description": "Whether serving
static files is enabled. If enabled then Camel can host html\/js and other web
files that makes it possible to include small web applications.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": "false" },
{ "name": "camel.server.uploadEnabled", "description": "Whether to enable
file upload via HTTP (not intended for production use). This functionality is
for development to be able to reload Camel routes and code with source changes
(if reload is enabled). If enabled then you can upload\/delete files via HTTP
PUT\/DELETE on context-path: \/q\/upload\/{name}. You must also configure the
uploadSourceDir option.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "t [...]
{ "name": "camel.server.uploadSourceDir", "description": "Source directory
when upload is enabled.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String" },
{ "name": "camel.server.useGlobalSslContextParameters", "description":
"Whether to use global SSL configuration for securing the embedded HTTP
server.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": "false" },
diff --git a/core/camel-main/src/main/docs/main.adoc
b/core/camel-main/src/main/docs/main.adoc
index df6c0047c07..84338b63325 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -170,7 +170,7 @@ The camel.routecontroller supports 12 options, which are
listed below.
=== Camel Embedded HTTP Server (only for standalone; not Spring Boot or
Quarkus) configurations
-The camel.server supports 20 options, which are listed below.
+The camel.server supports 22 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
@@ -192,6 +192,8 @@ The camel.server supports 20 options, which are listed
below.
| *camel.server.metricsEnabled* | Whether to enable metrics. If enabled then
you can access metrics on context-path: /q/metrics | false | boolean
| *camel.server.path* | Context-path to use for embedded HTTP server | / |
String
| *camel.server.port* | Port to use for binding embedded HTTP server | 8080 |
int
+| *camel.server.staticContextPath* | The context-path to use for serving
static content. By default, the root path is used. And if there is an
index.html page then this is automatically loaded. | / | String
+| *camel.server.staticEnabled* | Whether serving static files is enabled. If
enabled then Camel can host html/js and other web files that makes it possible
to include small web applications. | false | boolean
| *camel.server.uploadEnabled* | Whether to enable file upload via HTTP (not
intended for production use). This functionality is for development to be able
to reload Camel routes and code with source changes (if reload is enabled). If
enabled then you can upload/delete files via HTTP PUT/DELETE on context-path:
/q/upload/\{name}. You must also configure the uploadSourceDir option. | false
| boolean
| *camel.server.uploadSourceDir* | Source directory when upload is enabled. |
| String
| *camel.server.useGlobalSsl{zwsp}ContextParameters* | Whether to use global
SSL configuration for securing the embedded HTTP server. | false | boolean
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
index c5dd5ec54f9..96d5e0128b6 100644
---
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
+++
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
@@ -40,6 +40,9 @@ public class HttpServerConfigurationProperties implements
BootstrapCloseable {
private boolean useGlobalSslContextParameters;
private boolean infoEnabled;
+ private boolean staticEnabled;
+ @Metadata(defaultValue = "/")
+ private String staticContextPath = "/";
private boolean devConsoleEnabled;
private boolean healthCheckEnabled;
private boolean jolokiaEnabled;
@@ -151,6 +154,30 @@ public class HttpServerConfigurationProperties implements
BootstrapCloseable {
this.infoEnabled = infoEnabled;
}
+ public boolean isStaticEnabled() {
+ return staticEnabled;
+ }
+
+ /**
+ * Whether serving static files is enabled. If enabled then Camel can host
html/js and other web files that makes it
+ * possible to include small web applications.
+ */
+ public void setStaticEnabled(boolean staticEnabled) {
+ this.staticEnabled = staticEnabled;
+ }
+
+ public String getStaticContextPath() {
+ return staticContextPath;
+ }
+
+ /**
+ * The context-path to use for serving static content. By default, the
root path is used. And if there is an
+ * index.html page then this is automatically loaded.
+ */
+ public void setStaticContextPath(String staticContextPath) {
+ this.staticContextPath = staticContextPath;
+ }
+
public boolean isDevConsoleEnabled() {
return devConsoleEnabled;
}
@@ -360,6 +387,24 @@ public class HttpServerConfigurationProperties implements
BootstrapCloseable {
return this;
}
+ /**
+ * Whether serving static files is enabled. If enabled then Camel can host
html/js and other web files that makes it
+ * possible to include small web applications.
+ */
+ public HttpServerConfigurationProperties withStaticEnabled(boolean
staticEnabled) {
+ this.staticEnabled = staticEnabled;
+ return this;
+ }
+
+ /**
+ * The context-path to use for serving static content. By default, the
root path is used. And if there is an
+ * index.html page then this is automatically loaded.
+ */
+ public HttpServerConfigurationProperties withStaticContextPath(String
staticContextPath) {
+ this.staticContextPath = staticContextPath;
+ return this;
+ }
+
/**
* Whether to enable developer console (not intended for production use).
Dev console must also be enabled on
* CamelContext. For example by setting camel.context.dev-console=true in
application.properties, or via code