Many computer networks make use of proxy servers for web and Internet connectivity. This is especially true for business and other organization networks, where their use is required by security and other policies. Due to the typical use of proxy servers, they are often thought of in terms of "restricting access". Instead, they should be thought of in the proper terms of a means of "providing access". Even outside of typical corporate environments, proxy servers can be invaluable for testing and debugging, as well as used as a type of VPN between private networks.
Most web browsers and other networked applications support directing traffic through one or more proxy servers. The typical configuration dialog looks like this, as shown from Mozilla Firefox:
Of the "manual" options, "HTTP" and "SSL" (TLS) are the most basic and common, followed by "FTP". "Gopher" is rarely used anymore - it has already been dropped by Microsoft Internet Explorer, and may be dropped in Mozilla Firefox 4.0. "SOCKS" is arguably the most powerful, supporting any of the above protocols in addition to any other TCP- or UDP-based protocol. (If SOCKS is configured and supported, none of the other protocols need to be configured.)
Unfortunately, directing an entire networks' traffic through a single proxy server can quickly cause a bottle-neck and a common point for failure. This is especially true when all LAN traffic is also sent through the proxy. (In ideal network traffic patterns, there should be many more multiples of LAN traffic over Internet traffic.) Some of the performance and availability concerns can be addressed through DNS or other load balancing. Another common attempt is to configure the "no proxy for" / exception list. Unfortunately, there are some severe limitations to this design. First, the list must be kept up-to-date as the network configuration changes. (There are various tools for this.) More significantly, there are many desired configurations that cannot be accounted for. For example, what if a list is needed for the servers that should be sent to a proxy server, rather than skipping the proxy server (reverse logic)? Or what if traffic must be split among multiple proxy servers, depending upon the destination or other parameters?
The solution to all of the above and other similar concerns is through the use of the last option shown above, and probably the most overlooked: "Automatic proxy configuration URL".
This option is also known as proxy auto-config, or PAC, and was introduced into Netscape Navigator as early as 1996.
Within the PAC function, various load balancing and black- or white-listing tasks can be performed, optionally by maintaining internal state.
A list of multiple proxies may also be returned for attempts by the client.
The PAC file is loaded from a URL (including local
file:// URLs), where it can be centrally maintained and updated.
The PAC file may be cached by the web browser or other client, but should respect the cache settings sent in the HTTP headers if retrieved through HTTP.
chrome:// URL can even be used, allowing for the PAC file to be maintained within a Firefox extension, and updated through Firefox's standard auto-update process for extensions.
Java supports many of the same above proxy options, mostly through the use of system properties.
For full details, see the tech note at java.sun.com, Java Networking and Proxies.
These settings affect any communications made through
Socket, and possibly other network-related classes.
Previously, the proxy configuration options were limited to the "manual" options listed above, with separate options for HTTP, HTTPS, FTP, and SOCKS.
However, Java 1.5/5.0 introduced the
ProxySelector can be configured for the current JVM by calling
Unfortunately, Java does not currently provide any visible support for proxy auto-config (PAC) files.
List<Proxy> select(URI uri) method looks and works very similar to the PAC's
FindProxyForURL(url, host) function.
The most notable difference is that it is strongly-typed to standard Java classes.
As part of my MarkUtils collection, I created MarkUtils-PacProxySelector to provide a
ProxySelector implementation that works with PAC files.
Fortunately, this is easily done through Java, especially with the introduction of the Java Scripting API in Java 1.6/6.0 (JSR-223).
FunctionObject - a class to which there is no publicly visible match in the JDK.
While it is probably possible to hack a work-around to this, my current implementation utilizes Rhino directly.
Besides taking advantage of the improvements in the latest version of Rhino (currently 1.7R2), this allows the utility to be easily used with both Java 1.5/5.0 and 1.6/6.0.
(However, note that JSR-223 is unofficially supported under Java 1.5/5.0 as well by downloading and including the .jar's from the reference implementation.)
Using Rhino directly also avoids some potential security issues, which I reported in Sun Bug 6782031 and Mozilla Bug 468385.
As commented in the
pom.xml file, Mozilla Rhino is currently not available through the central repository, a Mozilla repository, or any other "official" repository.
I've added a dependency to it as "
For this to work properly, Rhino will need to be downloaded and installed into a local repository as named above.
In addition to the standard PAC methods, PacProxySelector supports an added function called "
connectFailed" to take advantage of the
connectFailed(URI, SocketAddress, IOException) functionality on
ProxySelector, just with the
.toString() representations of each of the three parameters.
The PAC file could then store this information within internal state to possibly affect future calls to
For the most flexibility, the constructor to
PacProxySelector accepts a
Reader, which should read from a PAC file.
There is also a
public static configureFromProperties() method that returns a
ProxySelector, assuming that the path to a PAC file is stored as either a Java system or environment property named "
proxy.autoConfig", similar to the other network properties.
After obtaining an instance from either the constructor or the method, it should be passed to
ProxySelector.setDefault(ProxySelector), unless otherwise used directly.
setDefaultFromProperties() convenience method is provided to do this in one call.
I wrote this in mind for plugging into other Java applications.
Ideally, the JDK would provide a system property that accepts the classname for the default
ProxySelector or some other method for setting the default outside of a function call within the code, but this is currently not the case.
However, all that has to be done is finding a way to execute one of the above configuration options from the desired Java application before network access is attempted.
I've successfully written a plugin for Oracle SQL Developer that does exactly this.
The same is also possible for Eclipse, though it requires patching of some of the plugins due to the current infrastructure.
(See Eclipse bug 257443.)
PacProxySelector provides a
main method that calls
setDefaultFromProperties() before chaining execution to another program's
See the included Javadoc for details.
com.ziesemer.utils.pacProxySelector is available on ziesemer.java.net under the GPL license, complete with source code, a compiled .jar, generated JavaDocs, and a suite of JUnit tests.
com.ziesemer.utils.pacProxySelector-*.zip distribution from here.
Please report any bugs or feature requests on the java.net Issue Tracker.