
When creating desktop applications it is often taken for granted that you can open socket connections and call out to the internet. That is, until you have a corporate client with a locked down computer and an Internet proxy.
This article shows how, using Java's proxy-vole library, you can create middleware for Butter that automatically set proxies from your user's system settings.
Reliably detecting and setting proxy configuration settings in Java is notoriously difficult. Questions such as this and this on Stackoverflow prove that many people struggle with it. Sure, you can invent your own config files and make your user edit the settings in yet another place, but what of Proxy Auto-Config (PAC) files that are becoming increasingly prevalent?
Proxy-Vole

Thankfully someone else (Bernd Rosstauscher) sought a solution to the problem and created the proxy-vole library. Proxy-vole does all the hard work for you and system proxy settings can be discovered in just a few lines of Java code:
// proxy-vole codeProxySearch proxySearch = ProxySearch.getDefaultProxySearch(); ProxySelector myProxySelector = proxySearch.getProxySelector();// standard java proxy codeList<Proxy> proxies = proxySelector.select(new URI("http://foo/bar")); if (proxies != null) for (Proxy proxy : proxies) { InetSocketAddress addr = (InetSocketAddress) proxy.address(); if (addr != null) { System.out.println("proxy host : " + addr.getHostName()); System.out.println("proxy port : " + addr.getPort()); } }
To use proxy-vole in Fantom, you need to download the jar and place it in the %FAN_HOME%\lib\java\etc\ directory.
Butter Middleware

Butter, as of v1.1, lets you specify a proxy. The proxy Uri just needs to be set in the request stash. It is then picked up and used by the default HttpTerminator.
Converting the above Java code to Fantom and wrapping it up as Butter middleware is a trivial task:
using afButter
using [java] java.lang::System
using [java] java.net::InetSocketAddress
using [java] java.net::Proxy
using [java] java.net::ProxySelector
using [java] java.net::URI
using [java] com.btr.proxy.search::ProxySearch
class ProxyVoleMiddleware : ButterMiddleware {
ProxySelector? proxySelector
new make() {
// proxySelector is null if the system doesn't use a proxy
proxySelector = ProxySearch.getDefaultProxySearch.getProxySelector
}
override ButterResponse sendRequest(Butter butter, ButterRequest req) {
if (proxySelector == null)
return butter.sendRequest(req)
iter := proxySelector.select(URI(req.url.encode)).iterator
while (iter.hasNext) {
proxy := (Proxy) iter.next
addr := (InetSocketAddress?) proxy.address
if (addr != null) {
proxyUrl := `${req.url.scheme}://${addr.getHostName}:${addr.getPort}`
req.stash["afButter.proxy"] = proxyUrl
break
}
}
return butter.sendRequest(req)
}
}
To use the ProxyVoleMiddleware just ensure it is included in the middleware stack when you create your Butter / ButterDish instance:
middleware := Butter.defaultStack.insert(0, ProxyVoleMiddleware()) butterdish := ButterDish(Butter.churnOut(middleware)) response := butterdish.get(`http://www.example.org/`)
And that's it!
When you now make any Butter calls, the proxy settings are automatically detected for the URL being called and placed in the request stash for the HttpTerminator to use.
Logging
Sometimes you may wish to debug what proxy-vole is doing. In those cases you can turn on debugging; create a proxy-vole logger class:
using [java] java.lang::Class
using [java] com.btr.proxy.util::Logger
using [java] com.btr.proxy.util::Logger$LogBackEnd as LogBackEnd
using [java] com.btr.proxy.util::Logger$LogLevel as LogLevel
class MyLogger : LogBackEnd {
static Void enable() {
Logger.setBackend(MyLogger())
}
override Bool isLogginEnabled(LogLevel? logLevel) {
true
}
override Void log(Class? clas, LogLevel? loglevel, Str? msg, Obj?[]? params) {
echo("$msg + $params")
}
}
To enable and use, just call the static method and any subsequent calls to proxy-vole should be echoed to the console.
MyLogger.enable()