Setting Tomcat to use different proxies for different hosts

This example shows how to configure Tomcat webserver to use different proxies for different hosts. This example was tested using Tomcat7. First thing to do is to add jproxyloader.jar to classpath of Tomcat. You can do this in many ways. In this example we will use the way how tomcat loads resources from "endorsed" directory. Tomcat, when starting, checks if endorsed directory exists and if it exists, it puts every jar and every zip file from this directory on application classpath.

In first step we create "endorsed" directory inside Tomcat installation directory.

C:\>cd tmp\apache-tomcat-7.0.54

C:\tmp\apache-tomcat-7.0.54>mkdir endorsed

C:\tmp\apache-tomcat-7.0.54>dir

 Directory of C:\tmp\apache-tomcat-7.0.54

2014-07-31  15:25    <DIR>          .
2014-07-31  15:25    <DIR>          ..
2014-07-31  15:19    <DIR>          bin
2014-07-31  15:19    <DIR>          conf
2014-07-31  15:25    <DIR>          endorsed
2014-07-31  15:20    <DIR>          lib
2014-07-31  15:19            57 862 LICENSE
2014-05-19  22:27    <DIR>          logs
2014-07-31  15:19             1 228 NOTICE
2014-07-31  15:19             9 204 RELEASE-NOTES
2014-07-31  15:19            16 682 RUNNING.txt
2014-07-31  15:20    <DIR>          temp
2014-07-31  15:20    <DIR>          webapps
2014-05-19  22:27    <DIR>          work
               4 File(s)         84 976 bytes
              10 Dir(s)  150 176 464 896 bytes free

C:\tmp\apache-tomcat-7.0.54>

Inside endorsed directory we put jproxyloader.jar and also we create new file jproxyloader.properties and pack it to zip file (name of the zip file does not matter since as mentioned above tomcat reads every zip and jar file from endorsed directory). JProxyLoader when starting will detect that jproxyloader.properties is on classpath and automatically load proxies definition from this file. After this action endorsed directory should look like below:

C:\tmp\apache-tomcat-7.0.54>cd endorsed

C:\tmp\apache-tomcat-7.0.54\endorsed>dir
 Volume in drive C has no label.
 Volume Serial Number is 4A95-897A

 Directory of C:\tmp\apache-tomcat-7.0.54\endorsed

2014-07-31  15:36    <DIR>          .
2014-07-31  15:36    <DIR>          ..
2014-07-31  15:14            33 900 jproxyloader-1.0-RC1.jar
2014-07-31  15:36               180 jproxyloader-properties.zip
               2 File(s)         33 900 bytes
               2 Dir(s)  150 174 498 816 bytes free

Now we place a proxy definition inside jproxyloader.properties file (you need to pack this file again to the zip file you created a second ago):

proxydef.myproxy.hostname=101.55.12.75
proxydef.myproxy.port=1080 
proxydef.myproxy.type=socks
proxydef.myproxy.proxified.hosts=apache.org   

With this definition we declared a socks proxy which should handle connections to apache.org. Last thing to do is to instruct tomcat to use jProxyLoader while running. To make this happen we need to add jvm parameter to tomcat startup scripts: "-Djava.system.class.loader=net.sf.jproxyloader.JProxyLoader". We will use the fact that tomcat adds to its jvm parameters every parameter from system variable CATALINA_OPTS. CATALINA_OPTS variable can be set in setenv.bat file in bin folder of tomcat (on linux it will be setenv.sh file), so first we need to create setenv.bat file.

C:\tmp\apache-tomcat-7.0.54>cd bin

C:\tmp\apache-tomcat-7.0.54\bin>dir

 Directory of C:\tmp\apache-tomcat-7.0.54\bin

2014-07-31  15:46    <DIR>          .
2014-07-31  15:46    <DIR>          ..
2014-07-31  15:19            27 831 bootstrap.jar
2014-07-31  15:19             2 168 catalina-tasks.xml
2014-07-31  15:19            13 003 catalina.bat
2014-07-31  15:19            20 779 catalina.sh
(...)
2014-07-31  15:46                 0 setenv.bat
(...)
2014-07-31  15:19             5 024 tool-wrapper.sh
2014-07-31  15:19             2 026 version.bat
2014-07-31  15:19             1 908 version.sh

We edit setenv.bat file (or setenv.sh on linux) to set up the CATALINA_OPTS variable. We also add -DjplLoggingLevel=DEBUG variable in order to get more debugging info. The content of this file should be following:

SET CATALINA_OPTS=-Djava.system.class.loader=net.sf.jproxyloader.JProxyLoader -DjplLoggingLevel=DEBUG

Note: for linux you should use the linux way of setting up environment variables (use "export" command instead of "SET").

Now when we run the server (for example by running "catalina.bat run" command from commnad line) we see following message on console (or catalina.out log file):

jProxyLoader: Initializing proxy jProxySelector with no proxy hosts: [], custom dns servers: [] and custom proxies config: []

It means that jProxyLoader was installed correctly to tomcat. Proxy definitions were not yet initialized because every configuration file which is located on classpath is read by jProxyLoader when first connection is made (not when application starts). So we need to create simple web application which connects to some urls. As a test application you can create simple war archive containing only one jsp file which will try to open connection to another host. In example below the connection is opened to apache.org website.

<%@ page import="java.net.URL" %>
<%@ page import="java.net.URLConnection" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title></title>
</head>
<body>

<%
    String url = "http://apache.org";

    URL oracle = new URL(url);
    URLConnection yc = oracle.openConnection();
    yc.setConnectTimeout(Integer.MAX_VALUE);
    yc.setReadTimeout(Integer.MAX_VALUE);

    BufferedReader in = new BufferedReader(new InputStreamReader(yc.getInputStream()));
    String inputLine;
    long responseLength = 0;

    while ((inputLine = in.readLine()) != null) {
    responseLength += inputLine.length();
    }
    in.close();

    System.out.println("The length of response for " + url + " is " + responseLength);
    
%>

</body>
</html>

Now when you deploy this application to tomcat and enter the url to this application in web browser you will see in tomcat console that jProxyLoader reinitialized configuration from jproxyloader.properties (which we placed inside zip file in endorsed directory). From the log you can see that jProxyLoader forwards connection to apache.org to defined proxy.

 hosts: [] and custom proxies[[socks@101.55.12.75:1080#[apache.org]]]
jProxyLoader: Reinitialized jProxySelector with no proxy hosts: [], custom dns servers: [] and custom proxies config: [[socks@101.55.12.75:1080#[apache.org]]]
jProxyLoader: select for URL : http://apache.org/
jProxyLoader: Testing proxy config for host: apache.org against following proxy configs: [[socks@101.55.12.75:1080#[apache.org]]]
jProxyLoader: Matching proxy config: [socks@101.55.12.75:1080#[apache.org]] against hostname: apache.org
jProxyLoader: Found matching proxy: [socks@101.55.12.75:1080#[apache.org]] for host: apache.org
jProxyLoader: Testing proxy config for host: apache.org against following proxy configs: [[socks@101.55.12.75:1080#[apache.org]]]
jProxyLoader: Matching proxy config: [socks@101.55.12.75:1080#[apache.org]] against hostname: apache.org
jProxyLoader: Found matching proxy: [socks@101.55.12.75:1080#[apache.org]] for host: apache.org
The length of response for http://apache.org is 39532