Many systems access the Web and sometimes other non-HTTP parts of the Internet through proxy servers. A proxy server receives a request for a remote server from a local client. The proxy server makes the request to the remote server and forwards the result back to the local client. Sometimes this is done for security reasons, such as to prevent remote hosts from learning private details about the local network configuration. Other times it’s done to prevent users from accessing forbidden sites by filtering outgoing requests and limiting which sites can be viewed. For instance, an elementary school might want to block access to http://www.playboy.com. And still other times it’s done purely for performance, to allow multiple users to retrieve the same popular documents
from a local cache rather than making repeated downloads from the remote server.
Java programs based on the URL class can work through most common proxy servers and protocols. Indeed, this is one reason you might want to choose to use the URL class rather than rolling your own HTTP or other client on top of raw sockets.
For basic operations, all you have to do is set a few system properties to point to the addresses of your local proxy servers. If you are using a pure HTTP proxy, set http.proxyHost to the domain name or the IP address of your proxy server and http.proxyPort to the port of the proxy server (the default is 80). There are several ways to do this, including calling System.setProperty() from within your Java code or using the -D options when launching the program. This example sets the proxy server to 192.168.254.254 and the port to 9000:
<programlisting format="linespecific" id="I_7_tt264">% <userinput moreinfo="none"> java -Dhttp.proxyHost=192.168.254.254 -Dhttp.proxyPort=9000 </userinput> <emphasis role="bolditalic">com.domain.Program</emphasis></programlisting>
If the proxy requires a username and password, you’ll need to install an Authenticator, as we’ll discuss shortly in “Accessing Password-Protected Sites”. If you want to exclude a host from being proxied and connect directly instead, set the http.nonProxyHosts system property to its hostname or IP address. To exclude multiple hosts, separate their names by vertical bars. For example, this code fragment proxies everything except java.oreilly.com and xml.oreilly.com:
System.setProperty("http.proxyHost", "192.168.254.254"); System.setProperty("http.proxyPort", "9000"); System.setProperty("http.nonProxyHosts", "java.oreilly.com|xml.oreilly.com");
You can also use an asterisk as a wildcard to indicate that all the hosts within a particular domain or subdomain should not be proxied. For example, to proxy everything except hosts in the oreilly.com domain:
% java -Dhttp.proxyHost=192.168.254.254 -Dhttp.nonProxyHosts=*.oreilly.com <emphasis role="bolditalic">com.domain.Program</emphasis></programlisting>
If you are using an FTP proxy server, set the ftp.proxyHost, ftp.proxyPort, and ftp.nonProxyHosts properties in the same way. Java does not support any other application layer proxies, but if you’re using a transport layer SOCKS proxy for all TCP connections, you can identify it with the socksProxy Host and socksProxyPort system properties. Java does not provide an option for non‐proxying with SOCKS. It’s an all-or-nothing decision.
The Proxy Class
The Proxy class allows more fine-grained control of proxy servers from within a Java program. Specifically, it allows you to choose different proxy servers for different remote hosts. The proxies themselves are represented by instances of the java.net.Proxy class.
There are still only three kinds of proxies, HTTP, SOCKS, and direct connections (no proxy at all), represented by three constants in the Proxy.Type enum:
Besides its type, the other important piece of information about a proxy is its address and port, given as a SocketAddress object. For example, this code fragment creates a Proxy object representing an HTTP proxy server on port 80 of proxy.example.com:
SocketAddress address = new InetSocketAddress("proxy.example.com", 80); Proxy proxy = new Proxy(Proxy.Type.HTTP, address);
Although there are only three kinds of proxy objects, there can be many proxies of the same type for different proxy servers on different hosts.
The ProxySelector Class
Each running virtual machine has a single java.net.ProxySelector object it uses to locate the proxy server for different connections. The default ProxySelector merely inspects the various system properties and the URL’s protocol to decide how to connect to different hosts. However, you can install your own subclass of ProxySelector in place of the default selector and use it to choose different proxies based on protocol, host, path, time of day, or other criteria. The key to this class is the abstract select() method:
public abstract List<Proxy> select(URI uri)
Java passes this method a URI object (not a URL object) representing the host to which a connection is needed. For a connection made with the URL class, this object typically has the form http://www.example.com/ or ftp://ftp.example.com/pub/files/, for example. For a pure TCP connection made with the Socket class, this URI will have the form socket://host:port:, for instance, socket://www.example.com:80. The ProxySelector object then chooses the right proxies for this type of object and returns them in a List<Proxy>.
The second abstract method in this class you must implement is connectFailed():
public void connectFailed(URI uri, SocketAddress address, IOException ex)
This is a callback method used to warn a program that the proxy server isn’t actually making the connection.
Each virtual machine has exactly one ProxySelector. To change the Proxy Selector, pass the new selector to the static ProxySelector.setDefault() method, like so:
ProxySelector selector = new LocalProxySelector(): ProxySelector.setDefault(selector);
From this point forward, all connections opened by that virtual machine will ask the ProxySelector for the right proxy to use. You normally shouldn’t use this in code running in a shared environment. For instance, you wouldn’t change the ProxySelector in a servlet because that would change the ProxySelector for all servlets running in the same container.