= Vert.x Http Proxy
:toc: left

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.

WARNING: This module has _Tech Preview_ status, this means the API can change between versions.

== Using Vert.x Http Proxy

To use Vert.x Http Proxy, add the following dependency to the _dependencies_ section of your build descriptor:

* Maven (in your `pom.xml`):

[source,xml,subs="+attributes"]
----
<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-http-proxy</artifactId>
 <version>4.3.3</version>
</dependency>
----

* Gradle (in your `build.gradle` file):

[source,groovy,subs="+attributes"]
----
dependencies {
 compile 'io.vertx:vertx-http-proxy:4.3.3'
}
----

== Reverse proxy server

In order to accomplish a reverse proxy with Vert.x Http Proxy you need the following:

1. *Proxy Server* that handles user-agent requests and forward them to the *origin server*
2. *Origin Server* that handles requests from the *proxy server* and respond accordingly

You can create a *proxy server* that listens to port `8080` and implement reverse proxy logic

[source,java]
----
HttpClient proxyClient = vertx.createHttpClient();

HttpProxy proxy = HttpProxy.reverseProxy(proxyClient);
proxy.origin(7070, "origin");

HttpServer proxyServer = vertx.createHttpServer();

proxyServer.requestHandler(proxy).listen(8080);
----

All user-agent requests are forwarded to the *origin server* conveniently.

=== WebSockets

The proxy supports WebSocket by default.

WebSocket handshake requests  are forwarded to the origin server (including the `connection` header)  and the handshake
happens between the user agent and the origin server.

You can configure WebSocket support with `link:../../apidocs/io/vertx/httpproxy/ProxyOptions.html#setSupportWebSocket-boolean-[setSupportWebSocket]`.

=== Proxy caching

By default the proxy does not cache response and ignores most cache directives, you can enable caching by setting the cache options.

[source,java]
----
HttpProxy proxy = HttpProxy.reverseProxy(new ProxyOptions().setCacheOptions(new CacheOptions()), proxyClient);
----

=== Proxy interception

Interception is a powerful way to extend the proxy withg new features.

You can implement `link:../../apidocs/io/vertx/httpproxy/ProxyInterceptor.html#handleProxyRequest-io.vertx.httpproxy.ProxyContext-[handleProxyRequest]` to perform any operation on the proxy request

[source,java]
----
proxy.addInterceptor(new ProxyInterceptor() {
  @Override
  public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
    ProxyRequest proxyRequest = context.request();

    filter(proxyRequest.headers());

    // Continue the interception chain
    return context.sendRequest();
  }
});
----

Likewise with the proxy response

[source,java]
----
proxy.addInterceptor(new ProxyInterceptor() {
  @Override
  public Future<Void> handleProxyResponse(ProxyContext context) {
    ProxyResponse proxyResponse = context.response();

    filter(proxyResponse.headers());

    // Continue the interception chain
    return context.sendResponse();
  }
});
----

==== Body filtering

You can filter body by simply replacing the original `link:../../apidocs/io/vertx/httpproxy/Body.html[Body]` with a new one

[source,java]
----
proxy.addInterceptor(new ProxyInterceptor() {
  @Override
  public Future<Void> handleProxyResponse(ProxyContext context) {
    ProxyResponse proxyResponse = context.response();

    // Create a filtered body
    Body filteredBody = filter(proxyResponse.getBody());

    // And then let the response use it
    proxyResponse.setBody(filteredBody);

    // Continue the interception chain
    return context.sendResponse();
  }
});
----

==== Interception control

`link:../../apidocs/io/vertx/httpproxy/ProxyContext.html#sendRequest--[sendRequest]` and `link:../../apidocs/io/vertx/httpproxy/ProxyContext.html#sendResponse--[sendResponse]` continue the
current interception chain and then send the result to the origin server or the user-agent.

You can change the control, e.g you can send a response immediately to the user-agent without even requesting the origin server

[source,java]
----
proxy.addInterceptor(new ProxyInterceptor() {
  @Override
  public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {

    ProxyRequest proxyRequest = context.request();

    // Release the underlying resources
    proxyRequest.release();

    // Create a response and populate it
    ProxyResponse proxyResponse = proxyRequest.response()
      .setStatusCode(200)
      .putHeader("content-type", "text/plain")
      .setBody(Body.body(Buffer.buffer("Hello World")));

    return Future.succeededFuture(proxyResponse);
  }
});
----