diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WellKnownProperties.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WellKnownProperties.java
index 9d479a3..321f5cf 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WellKnownProperties.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/WellKnownProperties.java
@@ -2,6 +2,11 @@
import java.util.List;
+/**
+ * Holds constants for the well-known properties defined by the Proxy-Wasm ABI.
+ *
+ * see: spec
+ */
public final class WellKnownProperties {
private WellKnownProperties() {}
diff --git a/proxy-wasm-jaxrs/pom.xml b/proxy-wasm-jaxrs/pom.xml
index 938a7a8..610f38d 100644
--- a/proxy-wasm-jaxrs/pom.xml
+++ b/proxy-wasm-jaxrs/pom.xml
@@ -26,12 +26,30 @@
+
+ io.quarkus
+ quarkus-arc
+ true
+
io.roastedroot
proxy-wasm-java-host
1.0-SNAPSHOT
+
+
+ io.vertx
+ vertx-core
+ true
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ true
+
+
+
jakarta.enterprise
jakarta.enterprise.cdi-api
@@ -42,8 +60,6 @@
jakarta.inject-api
provided
-
-
jakarta.ws.rs
jakarta.ws.rs-api
@@ -51,11 +67,6 @@
-
- io.quarkus
- quarkus-arc
- test
-
io.quarkus
quarkus-junit5
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java
index 7a39640..cd7f5d3 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java
@@ -1,6 +1,29 @@
package io.roastedroot.proxywasm.jaxrs;
+import static io.roastedroot.proxywasm.Helpers.bytes;
import static io.roastedroot.proxywasm.Helpers.string;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_DNS_SAN_LOCAL_CERTIFICATE;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_DNS_SAN_PEER_CERTIFICATE;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_ID;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_MTLS;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_REQUESTED_SERVER_NAME;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_SHA256_PEER_CERTIFICATE_DIGEST;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_SUBJECT_LOCAL_CERTIFICATE;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_SUBJECT_PEER_CERTIFICATE;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_TLS_VERSION;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_URI_SAN_LOCAL_CERTIFICATE;
+import static io.roastedroot.proxywasm.WellKnownProperties.CONNECTION_URI_SAN_PEER_CERTIFICATE;
+import static io.roastedroot.proxywasm.WellKnownProperties.DESTINATION_ADDRESS;
+import static io.roastedroot.proxywasm.WellKnownProperties.DESTINATION_PORT;
+import static io.roastedroot.proxywasm.WellKnownProperties.REQUEST_DURATION;
+import static io.roastedroot.proxywasm.WellKnownProperties.REQUEST_PROTOCOL;
+import static io.roastedroot.proxywasm.WellKnownProperties.REQUEST_SIZE;
+import static io.roastedroot.proxywasm.WellKnownProperties.REQUEST_TIME;
+import static io.roastedroot.proxywasm.WellKnownProperties.REQUEST_TOTAL_SIZE;
+import static io.roastedroot.proxywasm.WellKnownProperties.RESPONSE_SIZE;
+import static io.roastedroot.proxywasm.WellKnownProperties.RESPONSE_TOTAL_SIZE;
+import static io.roastedroot.proxywasm.WellKnownProperties.SOURCE_ADDRESS;
+import static io.roastedroot.proxywasm.WellKnownProperties.SOURCE_PORT;
import io.roastedroot.proxywasm.Action;
import io.roastedroot.proxywasm.ChainedHandler;
@@ -10,18 +33,24 @@
import io.roastedroot.proxywasm.StreamType;
import io.roastedroot.proxywasm.WasmException;
import io.roastedroot.proxywasm.WasmResult;
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.core.Response;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
class HttpHandler extends ChainedHandler {
private final PluginHandler next;
+ private final HttpServer httpServer;
+ private final long startedAt;
- HttpHandler(PluginHandler pluginHandler) {
+ HttpHandler(PluginHandler pluginHandler, HttpServer httpServer) {
this.next = pluginHandler;
+ this.httpServer = httpServer;
+ this.startedAt = System.currentTimeMillis();
}
@Override
@@ -237,11 +266,113 @@ public Action getAction() {
@Override
public byte[] getProperty(List path) throws WasmException {
+
+ // Check to see if it's a well known property
+
+ // Downstream connection properties
+ if (CONNECTION_ID.equals(path)) {
+ // Do we need to generate one?
+ return null;
+ } else if (SOURCE_ADDRESS.equals(path)) {
+ return bytes(httpServer.remoteAddress());
+ } else if (SOURCE_PORT.equals(path)) {
+ return bytes(httpServer.remotePort());
+ } else if (DESTINATION_ADDRESS.equals(path)) {
+ return bytes(httpServer.localAddress());
+ } else if (DESTINATION_PORT.equals(path)) {
+ return bytes(httpServer.localPort());
+ }
+
+ // TLS connection properties
+ else if (CONNECTION_TLS_VERSION.equals(path)) {
+ return null;
+ } else if (CONNECTION_REQUESTED_SERVER_NAME.equals(path)) {
+ return null;
+ } else if (CONNECTION_MTLS.equals(path)) {
+ return null;
+ } else if (CONNECTION_SUBJECT_LOCAL_CERTIFICATE.equals(path)) {
+ return null;
+ } else if (CONNECTION_SUBJECT_PEER_CERTIFICATE.equals(path)) {
+ return null;
+ } else if (CONNECTION_DNS_SAN_LOCAL_CERTIFICATE.equals(path)) {
+ return null;
+ } else if (CONNECTION_DNS_SAN_PEER_CERTIFICATE.equals(path)) {
+ return null;
+ } else if (CONNECTION_URI_SAN_LOCAL_CERTIFICATE.equals(path)) {
+ return null;
+ } else if (CONNECTION_URI_SAN_PEER_CERTIFICATE.equals(path)) {
+ return null;
+ } else if (CONNECTION_SHA256_PEER_CERTIFICATE_DIGEST.equals(path)) {
+ return null;
+ }
+
+ // Upstream connection properties: we are not directly connecting to an upstream server, so
+ // these are not implemented.
+ // else if (UPSTREAM_ADDRESS.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_PORT.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_LOCAL_ADDRESS.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_LOCAL_PORT.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_TLS_VERSION.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_SUBJECT_LOCAL_CERTIFICATE.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_SUBJECT_PEER_CERTIFICATE.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_DNS_SAN_LOCAL_CERTIFICATE.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_DNS_SAN_PEER_CERTIFICATE.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_URI_SAN_LOCAL_CERTIFICATE.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_URI_SAN_PEER_CERTIFICATE.equals(path)) {
+ // return null;
+ // } else if (UPSTREAM_SHA256_PEER_CERTIFICATE_DIGEST.equals(path)) {
+ // return null;
+ // }
+
+ // HTTP request properties
+ else if (REQUEST_PROTOCOL.equals(path)) {
+ if (requestContext == null) {
+ return null;
+ }
+ return bytes(requestContext.getUriInfo().getRequestUri().getScheme());
+ } else if (REQUEST_TIME.equals(path)) {
+ // TODO: check encoding /w other impls
+ return bytes(new Date(startedAt).toString());
+ } else if (REQUEST_DURATION.equals(path)) {
+ // TODO: check encoding /w other impls
+ return bytes("" + (System.currentTimeMillis() - startedAt));
+ } else if (REQUEST_SIZE.equals(path)) {
+ if (httpRequestBody == null) {
+ return null;
+ }
+ // TODO: check encoding /w other impls
+ return bytes("" + httpRequestBody.length);
+ } else if (REQUEST_TOTAL_SIZE.equals(path)) {
+ return null;
+ }
+
+ // HTTP response properties
+ else if (RESPONSE_SIZE.equals(path)) {
+ if (httpResponseBody == null) {
+ return null;
+ }
+ // TODO: check encoding /w other impls
+ return bytes("" + httpResponseBody.length);
+ } else if (RESPONSE_TOTAL_SIZE.equals(path)) {
+ // TODO: how can we do this?
+ return null;
+ }
+
byte[] result = properties.get(path);
- if (result == null) {
- return next().getProperty(path);
+ if (result != null) {
+ return result;
}
- return result;
+ return next().getProperty(path);
}
@Override
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java
index e1bf473..b8223f8 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java
@@ -3,6 +3,8 @@
import io.roastedroot.proxywasm.Action;
import io.roastedroot.proxywasm.HttpContext;
import io.roastedroot.proxywasm.StartException;
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
+import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.container.ContainerRequestContext;
@@ -28,9 +30,12 @@ public class ProxyWasmFilter
private final WasmPluginFactory pluginFactory;
+ Instance httpServer;
+
@Inject
- public ProxyWasmFilter(WasmPluginFactory pluginFactory) {
+ public ProxyWasmFilter(WasmPluginFactory pluginFactory, Instance httpServer) {
this.pluginFactory = pluginFactory;
+ this.httpServer = httpServer;
}
// TODO: the HttpContext and ProxyWasm object's should be closed once the request is done.
@@ -40,9 +45,9 @@ static class WasmHttpFilterContext {
final HttpHandler handler;
final HttpContext wasm;
- public WasmHttpFilterContext(WasmPlugin plugin) {
+ public WasmHttpFilterContext(WasmPlugin plugin, HttpServer httpServer) {
this.pluginHandler = plugin.pluginHandler();
- this.handler = new HttpHandler(plugin.pluginHandler());
+ this.handler = new HttpHandler(plugin.pluginHandler(), httpServer);
this.wasm = plugin.proxyWasm().createHttpContext(this.handler);
}
}
@@ -58,7 +63,7 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
Response.status(Response.Status.INTERNAL_SERVER_ERROR).build());
}
- var wasmHttpFilterContext = new WasmHttpFilterContext(plugin);
+ var wasmHttpFilterContext = new WasmHttpFilterContext(plugin, this.httpServer.get());
requestContext.setProperty(FILTER_CONTEXT_PROPERTY_NAME, wasmHttpFilterContext);
// the plugin may not be interested in the request headers.
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java
index 0220db2..703e6ad 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java
@@ -1,6 +1,7 @@
package io.roastedroot.proxywasm.jaxrs;
import io.roastedroot.proxywasm.StartException;
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
@@ -15,6 +16,8 @@ public class WasmPluginFeature implements DynamicFeature {
private HashMap plugins = new HashMap<>();
+ @Inject @Any Instance requestAdaptor;
+
@Inject
public WasmPluginFeature(@Any Instance factories) throws StartException {
for (var factory : factories) {
@@ -41,7 +44,7 @@ public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (pluignNameAnnotation != null) {
WasmPluginFactory factory = plugins.get(pluignNameAnnotation.value());
if (factory != null) {
- context.register(new ProxyWasmFilter(factory));
+ context.register(new ProxyWasmFilter(factory, requestAdaptor));
}
}
}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServer.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServer.java
new file mode 100644
index 0000000..9b62c43
--- /dev/null
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServer.java
@@ -0,0 +1,39 @@
+package io.roastedroot.proxywasm.jaxrs.servlet;
+
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
+import jakarta.annotation.Priority;
+import jakarta.enterprise.inject.Alternative;
+import jakarta.enterprise.inject.Instance;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.core.Context;
+
+@Alternative
+@Priority(100)
+public class ServletHttpServer implements HttpServer {
+
+ private final HttpServletRequest request;
+
+ public ServletHttpServer(@Context Instance request) {
+ this.request = request.get();
+ }
+
+ @Override
+ public String remoteAddress() {
+ return request.getRemoteAddr();
+ }
+
+ @Override
+ public String remotePort() {
+ return "" + request.getRemotePort();
+ }
+
+ @Override
+ public String localAddress() {
+ return request.getLocalAddr();
+ }
+
+ @Override
+ public String localPort() {
+ return "" + request.getLocalPort();
+ }
+}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServer.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServer.java
new file mode 100644
index 0000000..720f74e
--- /dev/null
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServer.java
@@ -0,0 +1,15 @@
+package io.roastedroot.proxywasm.jaxrs.spi;
+
+/**
+ * This interface will help us deal with differences in the http server impl.
+ */
+public interface HttpServer {
+
+ String remoteAddress();
+
+ String remotePort();
+
+ String localAddress();
+
+ String localPort();
+}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServer.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServer.java
new file mode 100644
index 0000000..97d3b5a
--- /dev/null
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServer.java
@@ -0,0 +1,41 @@
+package io.roastedroot.proxywasm.jaxrs.vertx;
+
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
+import io.vertx.core.http.HttpServerRequest;
+import jakarta.annotation.Priority;
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.enterprise.inject.Alternative;
+import jakarta.enterprise.inject.Instance;
+import jakarta.ws.rs.core.Context;
+
+@Alternative
+@Priority(200)
+@RequestScoped
+public class VertxHttpServer implements HttpServer {
+
+ private final HttpServerRequest request;
+
+ public VertxHttpServer(@Context Instance request) {
+ this.request = request.get();
+ }
+
+ @Override
+ public String remoteAddress() {
+ return request.remoteAddress().hostAddress();
+ }
+
+ @Override
+ public String remotePort() {
+ return "" + request.remoteAddress().port();
+ }
+
+ @Override
+ public String localAddress() {
+ return request.localAddress().hostAddress();
+ }
+
+ @Override
+ public String localPort() {
+ return "" + request.localAddress().port();
+ }
+}