From 3109483219d9d936f378de9e1eb5e0f8000c04b3 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Thu, 28 Nov 2024 17:18:14 +0100 Subject: [PATCH] HTTP Proxy examples Signed-off-by: Thomas Segismont --- http-proxy-examples/README.adoc | 57 +++++++++++++++++++ http-proxy-examples/pom.xml | 38 +++++++++++++ .../example/proxy/interception/Backend.java | 28 +++++++++ .../example/proxy/interception/Proxy.java | 43 ++++++++++++++ .../vertx/example/proxy/simple/Backend.java | 21 +++++++ .../io/vertx/example/proxy/simple/Proxy.java | 28 +++++++++ .../example/proxy/websocket/Backend.java | 27 +++++++++ .../vertx/example/proxy/websocket/Client.java | 25 ++++++++ .../vertx/example/proxy/websocket/Proxy.java | 27 +++++++++ pom.xml | 1 + 10 files changed, 295 insertions(+) create mode 100644 http-proxy-examples/README.adoc create mode 100644 http-proxy-examples/pom.xml create mode 100644 http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Backend.java create mode 100644 http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Proxy.java create mode 100644 http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Backend.java create mode 100644 http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Proxy.java create mode 100644 http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Backend.java create mode 100644 http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Client.java create mode 100644 http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Proxy.java diff --git a/http-proxy-examples/README.adoc b/http-proxy-examples/README.adoc new file mode 100644 index 000000000..fbd21b7c7 --- /dev/null +++ b/http-proxy-examples/README.adoc @@ -0,0 +1,57 @@ += Vert.x HTTP Proxy examples + +Here you will find examples demonstrating Vert.x HTTP Proxy. + +Vert.x HTTP Proxy is a reverse proxy based on Vert.x, it aims to implement reusable reverse proxy logic to focus on higher concerns. + +[#_simple_reverse_proxy] +== Simple reverse proxy + +In this example, there are two verticles: + +* the backend verticle, which is a simple HTTP server replying to requests with a greeting, and +* the proxy verticle, which configures a `ReverseProxy` that relays incoming traffic to the backend. + +After starting the backend and the proxy, browse to http://localhost:8080 or your use your favorite command-line tool, such as `curl` or `HTTPie`. + +link:src/main/java/io/vertx/example/proxy/simple/Backend.java[`Backend`] +link:src/main/java/io/vertx/example/proxy/simple/Proxy.java[`Proxy`] + +== Proxy interceptors + +This example is a follow-up of the <<_simple_reverse_proxy,simple reverse proxy>> example. + +The backend replies with a success code (200) only to requests starting with the `/app` prefix. +Besides, it puts an internal HTTP header value on responses. + +The proxy uses two types of interceptors: head and body interceptors. + +The head interceptor is configured to: + +- add the `/app` prefix to the path of HTTP requests +- remove the internal HTTP header from HTTP responses + +The body interceptor is configured to replace `Hello` with `Hi in the response text. + +After starting the backend and the proxy, browse to http://localhost:8080 or your use your favorite command-line tool, such as `curl` or `HTTPie`. + +link:src/main/java/io/vertx/example/proxy/interception/Backend.java[`Backend`] +link:src/main/java/io/vertx/example/proxy/interception/Proxy.java[`Proxy`] + +== WebSocket support + +In this example, there are three verticles: + +* the backend verticle, which is a simple WebSocket server sending messages periodically to clients, and +* the proxy verticle, which configures a `ReverseProxy` for WebSocket support, and +* the client verticle, which connects a WebSocket to the proxy + +After starting the different parts, the client should print this message every 3 seconds: + +---- +Received message: Hello World +---- + +link:src/main/java/io/vertx/example/proxy/websocket/Backend.java[`Backend`] +link:src/main/java/io/vertx/example/proxy/websocket/Proxy.java[`Proxy`] +link:src/main/java/io/vertx/example/proxy/websocket/Client.java[`Client`] diff --git a/http-proxy-examples/pom.xml b/http-proxy-examples/pom.xml new file mode 100644 index 000000000..e18a70824 --- /dev/null +++ b/http-proxy-examples/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + io.vertx + vertx-examples + 5.0.0.CR2 + + + http-proxy-examples + + + + io.vertx + vertx-core + ${project.version} + + + io.vertx + vertx-launcher-application + ${project.version} + + + + io.vertx + vertx-http-proxy + ${project.version} + + + io.vertx + vertx-web + ${project.version} + + + diff --git a/http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Backend.java b/http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Backend.java new file mode 100644 index 000000000..29be2b653 --- /dev/null +++ b/http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Backend.java @@ -0,0 +1,28 @@ +package io.vertx.example.proxy.interception; + +import io.vertx.core.Future; +import io.vertx.core.VerticleBase; +import io.vertx.launcher.application.VertxApplication; + +public class Backend extends VerticleBase { + + public static void main(String[] args) { + VertxApplication.main(new String[]{Backend.class.getName()}); + } + + @Override + public Future start() { + return vertx + .createHttpServer() + .requestHandler(req -> { + if (req.path().equals("/app") || req.path().startsWith("/app")) { + req.response() + .putHeader("x-internal-header", "some-internal-header-value") + .putHeader("content-type", "text/html") + .end("

Hello from Vert.x!

"); + } else { + req.response().setStatusCode(400).end(); + } + }).listen(7070); + } +} diff --git a/http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Proxy.java b/http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Proxy.java new file mode 100644 index 000000000..1da999ecc --- /dev/null +++ b/http-proxy-examples/src/main/java/io/vertx/example/proxy/interception/Proxy.java @@ -0,0 +1,43 @@ +package io.vertx.example.proxy.interception; + +import io.vertx.core.Future; +import io.vertx.core.VerticleBase; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpServer; +import io.vertx.httpproxy.HttpProxy; +import io.vertx.httpproxy.interceptors.BodyInterceptor; +import io.vertx.httpproxy.interceptors.BodyTransformer; +import io.vertx.httpproxy.interceptors.HeadInterceptor; +import io.vertx.launcher.application.VertxApplication; + +import java.util.Set; + +public class Proxy extends VerticleBase { + + public static void main(String[] args) { + VertxApplication.main(new String[]{Proxy.class.getName()}); + } + + @Override + public Future start() { + HttpClient proxyClient = vertx.createHttpClient(); + + HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); + proxy.origin(7070, "localhost"); + + HeadInterceptor headInterceptor = HeadInterceptor.builder() + .addingPathPrefix("/app") + .filteringResponseHeaders(Set.of("x-internal-header")) + .build(); + proxy.addInterceptor(headInterceptor); + + BodyTransformer responseTransformer = BodyTransformer.transformText(txt -> { + return txt.replace("Hello", "Hi"); + }, "ISO-8859-1"); + proxy.addInterceptor(BodyInterceptor.modifyResponseBody(responseTransformer)); + + HttpServer proxyServer = vertx.createHttpServer(); + + return proxyServer.requestHandler(proxy).listen(8080); + } +} diff --git a/http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Backend.java b/http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Backend.java new file mode 100644 index 000000000..cd3c86ed9 --- /dev/null +++ b/http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Backend.java @@ -0,0 +1,21 @@ +package io.vertx.example.proxy.simple; + +import io.vertx.core.Future; +import io.vertx.core.VerticleBase; +import io.vertx.launcher.application.VertxApplication; + +public class Backend extends VerticleBase { + + public static void main(String[] args) { + VertxApplication.main(new String[]{Backend.class.getName()}); + } + + @Override + public Future start() { + return vertx + .createHttpServer() + .requestHandler(req -> { + req.response().putHeader("content-type", "text/html").end("

Hello from Vert.x!

"); + }).listen(7070); + } +} diff --git a/http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Proxy.java b/http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Proxy.java new file mode 100644 index 000000000..b4de67a83 --- /dev/null +++ b/http-proxy-examples/src/main/java/io/vertx/example/proxy/simple/Proxy.java @@ -0,0 +1,28 @@ +package io.vertx.example.proxy.simple; + +import io.vertx.core.Future; +import io.vertx.core.VerticleBase; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpServer; +import io.vertx.httpproxy.HttpProxy; +import io.vertx.httpproxy.ProxyOptions; +import io.vertx.launcher.application.VertxApplication; + +public class Proxy extends VerticleBase { + + public static void main(String[] args) { + VertxApplication.main(new String[]{Proxy.class.getName()}); + } + + @Override + public Future start() { + HttpClient proxyClient = vertx.createHttpClient(); + + HttpProxy proxy = HttpProxy.reverseProxy(new ProxyOptions().setSupportWebSocket(true), proxyClient); + proxy.origin(7070, "localhost"); + + HttpServer proxyServer = vertx.createHttpServer(); + + return proxyServer.requestHandler(proxy).listen(8080); + } +} diff --git a/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Backend.java b/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Backend.java new file mode 100644 index 000000000..910aa6381 --- /dev/null +++ b/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Backend.java @@ -0,0 +1,27 @@ +package io.vertx.example.proxy.websocket; + +import io.vertx.core.Future; +import io.vertx.core.VerticleBase; +import io.vertx.launcher.application.VertxApplication; + +public class Backend extends VerticleBase { + + public static void main(String[] args) { + VertxApplication.main(new String[]{Backend.class.getName()}); + } + + @Override + public Future start() { + return vertx + .createHttpServer() + .webSocketHandler(ws -> { + vertx.setPeriodic(3000, tid -> { + if (ws.isClosed()) { + vertx.cancelTimer(tid); + return; + } + ws.writeTextMessage("Hello World"); + }); + }).listen(7070); + } +} diff --git a/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Client.java b/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Client.java new file mode 100644 index 000000000..deae3107a --- /dev/null +++ b/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Client.java @@ -0,0 +1,25 @@ +package io.vertx.example.proxy.websocket; + +import io.vertx.core.Future; +import io.vertx.core.VerticleBase; +import io.vertx.core.http.WebSocketClient; +import io.vertx.core.http.WebSocketConnectOptions; +import io.vertx.launcher.application.VertxApplication; + +public class Client extends VerticleBase { + + public static void main(String[] args) { + VertxApplication.main(new String[]{Client.class.getName()}); + } + + private WebSocketClient client; + + @Override + public Future start() throws Exception { + client = vertx.createWebSocketClient(); + return client.connect(new WebSocketConnectOptions().setHost("localhost").setPort(8080)) + .onSuccess(ws -> ws.textMessageHandler(msg -> { + System.out.println("Received message: " + msg); + })); + } +} diff --git a/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Proxy.java b/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Proxy.java new file mode 100644 index 000000000..c9bd1b745 --- /dev/null +++ b/http-proxy-examples/src/main/java/io/vertx/example/proxy/websocket/Proxy.java @@ -0,0 +1,27 @@ +package io.vertx.example.proxy.websocket; + +import io.vertx.core.Future; +import io.vertx.core.VerticleBase; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpServer; +import io.vertx.httpproxy.HttpProxy; +import io.vertx.launcher.application.VertxApplication; + +public class Proxy extends VerticleBase { + + public static void main(String[] args) { + VertxApplication.main(new String[]{Proxy.class.getName()}); + } + + @Override + public Future start() { + HttpClient proxyClient = vertx.createHttpClient(); + + HttpProxy proxy = HttpProxy.reverseProxy(proxyClient); + proxy.origin(7070, "localhost"); + + HttpServer proxyServer = vertx.createHttpServer(); + + return proxyServer.requestHandler(proxy).listen(8080); + } +} diff --git a/pom.xml b/pom.xml index 23492209c..76efff267 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ json-schema-examples config-examples health-check-examples + http-proxy-examples