Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/main/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,45 @@ Nevertheless, you can override the request authority:

When the request authority is overridden, the `x-forwarded-host` header is automatically set on the request to the origin server with the original authority value.

==== Forwarded headers

As a reverse proxy, it's often required to send information about the client request to the origin server through headers.
The proxy supports both the de-facto standard `X-Forwarded-*` headers and the RFC 7239 `Forwarded` header.

By default, forwarded headers are disabled.
You can enable them by configuring {@link io.vertx.httpproxy.ForwardedHeadersOptions}:

[source,java]
----
{@link examples.HttpProxyExamples#forwardedHeaders}
----

You can control which headers are added:

[source,java]
----
{@link examples.HttpProxyExamples#forwardedHeadersSelective}
----

Alternatively, you can use the RFC 7239 standardized `Forwarded` header instead of the de-facto `X-Forwarded-*` headers:

[source,java]
----
{@link examples.HttpProxyExamples#forwardedHeadersRfc7239}
----

The following headers are supported:

* `X-Forwarded-For` - contains the client IP address.
When a proxy chain exists, the proxy appends the client IP to preserve the chain.
* `X-Forwarded-Proto` - contains the original request scheme (http or https)
* `X-Forwarded-Host` - contains the original request host
* `X-Forwarded-Port` - contains the original request port
* `Forwarded` - RFC 7239 standardized header that combines the above information in a structured format: `for=<client-ip>;proto=<scheme>;host=<host>`

IMPORTANT: The `X-Forwarded-*` and `Forwarded` headers can be used by origin servers to determine the actual client IP, protocol, and host when behind a reverse proxy.
This is useful for generating proper URLs, security decisions, and logging.

=== WebSockets

The proxy supports WebSocket by default.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.vertx.httpproxy;

import io.vertx.core.json.JsonObject;
import io.vertx.core.json.JsonArray;

/**
* Converter and mapper for {@link io.vertx.httpproxy.ForwardedHeadersOptions}.
* NOTE: This class has been automatically generated from the {@link io.vertx.httpproxy.ForwardedHeadersOptions} original class using Vert.x codegen.
*/
public class ForwardedHeadersOptionsConverter {

static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, ForwardedHeadersOptions obj) {
for (java.util.Map.Entry<String, Object> member : json) {
switch (member.getKey()) {
case "enabled":
if (member.getValue() instanceof Boolean) {
obj.setEnabled((Boolean)member.getValue());
}
break;
case "forwardFor":
if (member.getValue() instanceof Boolean) {
obj.setForwardFor((Boolean)member.getValue());
}
break;
case "forwardProto":
if (member.getValue() instanceof Boolean) {
obj.setForwardProto((Boolean)member.getValue());
}
break;
case "forwardHost":
if (member.getValue() instanceof Boolean) {
obj.setForwardHost((Boolean)member.getValue());
}
break;
case "forwardPort":
if (member.getValue() instanceof Boolean) {
obj.setForwardPort((Boolean)member.getValue());
}
break;
case "useRfc7239":
if (member.getValue() instanceof Boolean) {
obj.setUseRfc7239((Boolean)member.getValue());
}
break;
}
}
}

static void toJson(ForwardedHeadersOptions obj, JsonObject json) {
toJson(obj, json.getMap());
}

static void toJson(ForwardedHeadersOptions obj, java.util.Map<String, Object> json) {
json.put("enabled", obj.isEnabled());
json.put("forwardFor", obj.isForwardFor());
json.put("forwardProto", obj.isForwardProto());
json.put("forwardHost", obj.isForwardHost());
json.put("forwardPort", obj.isForwardPort());
json.put("useRfc7239", obj.isUseRfc7239());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ static void fromJson(Iterable<java.util.Map.Entry<String, Object>> json, ProxyOp
obj.setSupportWebSocket((Boolean)member.getValue());
}
break;
case "forwardedHeadersOptions":
if (member.getValue() instanceof JsonObject) {
obj.setForwardedHeadersOptions(new io.vertx.httpproxy.ForwardedHeadersOptions((io.vertx.core.json.JsonObject)member.getValue()));
}
break;
}
}
}
Expand All @@ -35,5 +40,8 @@ static void toJson(ProxyOptions obj, java.util.Map<String, Object> json) {
json.put("cacheOptions", obj.getCacheOptions().toJson());
}
json.put("supportWebSocket", obj.getSupportWebSocket());
if (obj.getForwardedHeadersOptions() != null) {
json.put("forwardedHeadersOptions", obj.getForwardedHeadersOptions().toJson());
}
}
}
43 changes: 43 additions & 0 deletions src/main/java/examples/HttpProxyExamples.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
/*
* Copyright (c) 2011-2026 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/

package examples;

import io.vertx.core.Future;
Expand Down Expand Up @@ -214,4 +225,36 @@ public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
public void cacheConfig(Vertx vertx, HttpClient proxyClient) {
HttpProxy proxy = HttpProxy.reverseProxy(new ProxyOptions().setCacheOptions(new CacheOptions()), proxyClient);
}

public void forwardedHeaders(Vertx vertx, HttpClient proxyClient) {
ProxyOptions options = new ProxyOptions()
.setForwardedHeadersOptions(new ForwardedHeadersOptions()
.setEnabled(true));

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

public void forwardedHeadersSelective(Vertx vertx, HttpClient proxyClient) {
ProxyOptions options = new ProxyOptions()
.setForwardedHeadersOptions(new ForwardedHeadersOptions()
.setEnabled(true)
.setForwardFor(true)
.setForwardProto(true)
.setForwardHost(true)
.setForwardPort(false)); // Don't forward port

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

public void forwardedHeadersRfc7239(Vertx vertx, HttpClient proxyClient) {
ProxyOptions options = new ProxyOptions()
.setForwardedHeadersOptions(new ForwardedHeadersOptions()
.setEnabled(true)
.setUseRfc7239(true)); // Use RFC 7239 Forwarded header

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