An HTTP intermediary forwards requests and responses between clients and servers.
client ⇄ { intermediary } ⇄ server
We can implement an intermediary by using HttpServer and HttpClient
client ⇄ { HttpServer ⇄ HttpClient } ⇄ server
The simplest implementation of a proxy would be:
new HttpServer( new HttpClient()::send ).start();
However, some default features of HttpServer and HttpClient are not appropriate for intermediaries; they should be disabled by HttpServerConf.setProxyDefaults() and HttpClient.send0().
The following sections show two examples of intermediaries: Proxy, Load Balancer.
To create a simple HTTP proxy at port 9090:
HttpClient downstream = new HttpClient();
HttpHandler proxyHandler = request->
{
return downstream.send0(request, null); // use send0() instead of send()
};
HttpServer proxy = new HttpServer(proxyHandler);
proxy.conf()
.port(9090)
.setProxyDefaults() // use proxy settings
.trafficDump(System.out::print)
;
proxy.start();
It doesn't do much, except the traffic is dumped which can be used for diagnostics.
See also _HttpProxy.java for a simple HTTP+HTTPS proxy demo.
We can add any custom behaviors to the proxy. For example, to block spam hosts:
Set<String> spamHosts = new ConcurrentHashMap<String,Boolean>().keySet(true);
HttpHandler adminHandler = request->
{
String add = request.uriParam("add");
if(add!=null) spamHosts.add(add);
return HttpResponse.text(200, "spamHosts:"+spamHosts);
};
HttpClient downstream = new HttpClient();
HttpHandler proxyHandler = request->
{
// use <http://proxy-admin/> to manage the spam list.
if(request.host().equals("proxy-admin"))
return adminHandler.handle(request);
if(spamHosts.contains(request.host()))
return HttpResponse.text(403, "blocked");
return downstream.send0(request, null);
};
A load balancer dispatches a client request to one of several internal servers, based on request cookie, URI, IP, etc.
In the following demo, we have two internal servers at port 8081 and 8082. The load balancer runs at port 80, and dispatches requests based on URIs.
for(int port: new int[]{8081, 8082})
{
HttpServer server = new HttpServer(request->
HttpResponse.text(200, "from server "+port));
server.conf().port(port);
server.start();
}
HttpClient downstream = new HttpClient();
HttpServer loadBalancer = new HttpServer(request->
{
TcpAddress dest = new TcpAddress("127.0.0.1", 8081);
if(request.uriPath().equals("/cat"))
dest = new TcpAddress("127.0.0.1", 8082);
HttpRequestImpl reqMod = new HttpRequestImpl(request); // copy and modify
reqMod.header("X-Forwarded-For", request.ip().getHostAddress());
reqMod.header("X-Forwarded-Proto", request.scheme());
return downstream.send0(reqMod, dest);
});
loadBalancer.conf()
.port(80)
.setProxyDefaults()
;
loadBalancer.start();