diff --git a/README.md b/README.md index 0a7b4f82..947a9320 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ HTTP POST. Other application parameters can be in your POSTed url-encoded-form s proxyArgs. Build & Installation ------------- +-------------------- Simply build the jar using "mvn package" at the command line. The jar is built to "target/smiley-http-proxy-servlet-VERSION.jar". @@ -49,7 +49,7 @@ add this to your dependencies in your pom like so: org.mitre.dsmiley.httpproxy smiley-http-proxy-servlet - 1.7 + 1.9.1 Ivy and other dependency managers can be used as well. @@ -136,4 +136,43 @@ proxy: solr: servlet_url: /solr/* target_url: http://solrserver:8983/solr +``` + +Here is an example of using the proxy with an externalized properties file `http-proxy.properties` and / or `http-proxy-override.properties` which would be plugged into the `web.xml` if it is available in the classpath: + +```xml + ... + + solr + org.mitre.dsmiley.httpproxy.ProxyServlet + + targetUri + ${some-url} + + + log + true + + + ... +``` + +make sure you put **${**some-url**}** is used if you want to pickup values from the properties file. + +The properties file could be: + +**http-proxy.properties**: + +```properties +some-url=http://www.cisco.com/{x-some-parameter}/someEndpoint +``` + +Assuming `x-some-parameter` is a custom header parameter. + +If this property needs to be overridden for some reason for a different environment for example, then the override properties file could be: + +**http-proxy-override.properties** + +```properties +some-url=http://www.cisco.com/someContext/someEndpoint ``` \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7a6cdf4c..02220dc3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.mitre.dsmiley.httpproxy smiley-http-proxy-servlet - 1.9-SNAPSHOT + 1.9.1 jar Smiley's HTTP Proxy Servlet @@ -35,7 +35,7 @@ https://github.com/dsmiley/HTTP-Proxy-Servlet scm:git:https://dsmiley@github.com/dsmiley/HTTP-Proxy-Servlet.git scm:git:git@github.com:dsmiley/HTTP-Proxy-Servlet.git - HEAD + smiley-http-proxy-servlet-1.9 diff --git a/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java b/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java index dc927338..e8791a94 100644 --- a/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java +++ b/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java @@ -36,16 +36,13 @@ import org.apache.http.message.BasicHttpRequest; import org.apache.http.message.HeaderGroup; import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.HttpParams; import org.apache.http.util.EntityUtils; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.Closeable; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.net.HttpCookie; @@ -54,6 +51,13 @@ import java.util.Enumeration; import java.util.Formatter; import java.util.List; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * An HTTP reverse proxy/gateway servlet. It is designed to be extended for customization @@ -112,6 +116,8 @@ public class ProxyServlet extends HttpServlet { private HttpClient proxyClient; + private Properties configurationProperties = null; + @Override public String getServletInfo() { return "A proxy servlet by David Smiley, dsmiley@apache.org"; @@ -129,9 +135,80 @@ protected HttpHost getTargetHost(HttpServletRequest servletRequest) { /** * Reads a configuration parameter. By default it reads servlet init parameters but * it can be overridden. + * In case if you are using an externalized properties file http-proxy.properties and / or + * http-proxy-override.properties which would be plugged into the web.xml if it is available in the classpath: + * + * ... + * <servlet> + * <servlet-name>solr</servlet-name> + * <servlet-class>org.mitre.dsmiley.httpproxy.ProxyServlet</servlet-class> + * <init-param> + * <param-name>targetUri</param-name> + * <param-value>${some-url}</param-value> + * </init-param> + * <init-param> + * <param-name>log</param-name> + * <param-value>true</param-value> + * </init-param> + * </servlet> + * ... + * + * make sure you put ${some-url} is used if you want to pickup values from the properties file. + * + * The properties file could be: + * + * http-proxy.properties: + * + * some-url=http://www.cisco.com/{x-some-parameter}/someEndpoint + * + * Assuming x-some-parameter is a custom header parameter. + * + * If this property needs to be overridden for some reason for a different environment for example, then the override properties file could be: + * + * http-proxy-override.properties + * + * some-url=http://www.cisco.com/someContext/someEndpoint */ + protected String getConfigParam(String key) { - return getServletConfig().getInitParameter(key); + if(configurationProperties == null) { + configurationProperties = getConfigurationProperties(); + } + return getValue(configurationProperties, getServletConfig().getInitParameter(key)); + } + + protected String getValue(Properties configurationProperties, String value){ + if(value == null){ + return value; + } + if(value.startsWith("${") && value.endsWith("}")){ + String key = value.replaceAll("\\$\\{(.*)\\}", "$1"); + return (String) configurationProperties.get(key); + } + return value; + } + protected Properties getConfigurationProperties() + { + Properties configurationProperties = new Properties(); + try + { + InputStream proxyPropertiesResource = Thread.currentThread().getContextClassLoader().getResourceAsStream("http-proxy.properties"); + if (proxyPropertiesResource != null) { + configurationProperties.load(proxyPropertiesResource); + } + } + catch (IOException e) {} + Properties proxyOverrideProperties = new Properties(); + try + { + InputStream proxyOverridePropertiesResource = Thread.currentThread().getContextClassLoader().getResourceAsStream("http-proxy-override.properties"); + if (proxyOverridePropertiesResource != null) { + proxyOverrideProperties.load(proxyOverridePropertiesResource); + } + } + catch (IOException e) {} + configurationProperties.putAll(proxyOverrideProperties); + return configurationProperties; } @Override @@ -161,6 +238,12 @@ public void init() throws ServletException { hcParams.setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES); hcParams.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false); // See #70 readConfigParam(hcParams, ClientPNames.HANDLE_REDIRECTS, Boolean.class); + readConfigParam(hcParams, ClientPNames.ALLOW_CIRCULAR_REDIRECTS, Boolean.class); + readConfigParam(hcParams, "http.conn-manager.timeout", Integer.class); + readConfigParam(hcParams, ClientPNames.MAX_REDIRECTS, Integer.class); + readConfigParam(hcParams, CoreConnectionPNames.CONNECTION_TIMEOUT, Integer.class); + readConfigParam(hcParams, CoreConnectionPNames.SO_TIMEOUT, Integer.class); + readConfigParam(hcParams, CoreConnectionPNames.STALE_CONNECTION_CHECK, Boolean.class); proxyClient = createHttpClient(hcParams); } @@ -650,6 +733,10 @@ protected static CharSequence encodeUriQuery(CharSequence in) { formatter.format("%%%02X",(int)c);//TODO } } + + if(formatter!= null){ + formatter.close(); + } return outBuf != null ? outBuf : in; } diff --git a/src/main/java/org/mitre/dsmiley/httpproxy/URITemplateProxyServlet.java b/src/main/java/org/mitre/dsmiley/httpproxy/URITemplateProxyServlet.java index 95354d66..90fb226d 100644 --- a/src/main/java/org/mitre/dsmiley/httpproxy/URITemplateProxyServlet.java +++ b/src/main/java/org/mitre/dsmiley/httpproxy/URITemplateProxyServlet.java @@ -20,9 +20,6 @@ import org.apache.http.client.utils.URIUtils; import org.apache.http.client.utils.URLEncodedUtils; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -32,6 +29,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + /** * A proxy servlet in which the target URI is templated from incoming request parameters. The * format adheres to the URI Template RFC, "Level @@ -55,7 +56,7 @@ public class URITemplateProxyServlet extends ProxyServlet { * But that's not how the spec works. So for now we will require a proxy arg to be present * if defined for this proxy URL. */ - protected static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\{([a-zA-Z0-9_%.]+)\\}"); + protected static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\{(.+?)\\}"); private static final String ATTR_QUERY_STRING = URITemplateProxyServlet.class.getSimpleName() + ".queryString"; @@ -107,7 +108,10 @@ protected void service(HttpServletRequest servletRequest, HttpServletResponse se String arg = matcher.group(1); String replacement = params.remove(arg);//note we remove if (replacement == null) { - throw new ServletException("Missing HTTP parameter "+arg+" to fill the template"); + replacement = servletRequest.getHeader(arg) ; + if (replacement == null) { + throw new ServletException("Missing HTTP parameter " + arg + " to fill the template"); + } } matcher.appendReplacement(urlBuf, replacement); } @@ -140,4 +144,5 @@ protected void service(HttpServletRequest servletRequest, HttpServletResponse se protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) { return (String) servletRequest.getAttribute(ATTR_QUERY_STRING); } + }