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();