Class ProxyServlet

  • All Implemented Interfaces:
    Serializable, javax.servlet.Servlet, javax.servlet.ServletConfig
    Direct Known Subclasses:
    URITemplateProxyServlet

    public class ProxyServlet
    extends javax.servlet.http.HttpServlet
    An HTTP reverse proxy/gateway servlet. It is designed to be extended for customization if desired. Most of the work is handled by Apache HttpClient.

    There are alternatives to a servlet based proxy such as Apache mod_proxy if that is available to you. However this servlet is easily customizable by Java, secure-able by your web application's security (e.g. spring-security), portable across servlet engines, and is embeddable into another web application.

    Inspiration: http://httpd.apache.org/docs/2.0/mod/mod_proxy.html

    Author:
    David Smiley dsmiley@apache.org
    See Also:
    Serialized Form
    • Constructor Summary

      Constructors 
      Constructor Description
      ProxyServlet()  
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      protected org.apache.http.client.HttpClient buildHttpClient​(org.apache.http.impl.client.HttpClientBuilder clientBuilder)
      Creates a HttpClient from the given builder.
      protected String buildProxyCookiePath​(javax.servlet.http.HttpServletRequest servletRequest)
      Create path for proxy cookie.
      protected org.apache.http.client.config.RequestConfig buildRequestConfig()
      Sub-classes can override specific behaviour of RequestConfig.
      protected org.apache.http.config.SocketConfig buildSocketConfig()
      Sub-classes can override specific behaviour of SocketConfig.
      protected void closeQuietly​(Closeable closeable)  
      protected void copyProxyCookie​(javax.servlet.http.HttpServletRequest servletRequest, javax.servlet.http.HttpServletResponse servletResponse, String headerValue)
      Copy cookie from the proxy to the servlet client.
      protected void copyRequestHeader​(javax.servlet.http.HttpServletRequest servletRequest, org.apache.http.HttpRequest proxyRequest, String headerName)
      Copy a request header from the servlet client to the proxy request.
      protected void copyRequestHeaders​(javax.servlet.http.HttpServletRequest servletRequest, org.apache.http.HttpRequest proxyRequest)
      Copy request headers from the servlet client to the proxy request.
      protected void copyResponseEntity​(org.apache.http.HttpResponse proxyResponse, javax.servlet.http.HttpServletResponse servletResponse, org.apache.http.HttpRequest proxyRequest, javax.servlet.http.HttpServletRequest servletRequest)
      Copy response body data (the entity) from the proxy to the servlet client.
      protected void copyResponseHeader​(javax.servlet.http.HttpServletRequest servletRequest, javax.servlet.http.HttpServletResponse servletResponse, org.apache.http.Header header)
      Copy a proxied response header back to the servlet client.
      protected void copyResponseHeaders​(org.apache.http.HttpResponse proxyResponse, javax.servlet.http.HttpServletRequest servletRequest, javax.servlet.http.HttpServletResponse servletResponse)
      Copy proxied response headers back to the servlet client.
      protected org.apache.http.client.HttpClient createHttpClient()
      Called from GenericServlet.init(javax.servlet.ServletConfig).
      protected javax.servlet.http.Cookie createProxyCookie​(javax.servlet.http.HttpServletRequest servletRequest, HttpCookie cookie)
      Creates a proxy cookie from the original cookie.
      void destroy()  
      protected org.apache.http.HttpResponse doExecute​(javax.servlet.http.HttpServletRequest servletRequest, javax.servlet.http.HttpServletResponse servletResponse, org.apache.http.HttpRequest proxyRequest)  
      protected CharSequence encodeUriQuery​(CharSequence in, boolean encodePercent)
      Encodes characters in the query or fragment part of the URI.
      protected String getConfigParam​(String key)
      Reads a configuration parameter.
      protected String getCookieNamePrefix​(String name)
      The string prefixing rewritten cookies.
      protected org.apache.http.impl.client.HttpClientBuilder getHttpClientBuilder()
      Creates a HttpClientBuilder.
      protected org.apache.http.client.HttpClient getProxyClient()
      The http client used.
      protected String getProxyCookieName​(HttpCookie cookie)
      Set cookie name prefixed with a proxy value so it won't collide with other cookies.
      protected String getRealCookie​(String cookieValue)
      Take any client cookies that were originally from the proxy and prepare them to send to the proxy.
      String getServletInfo()  
      protected org.apache.http.HttpHost getTargetHost​(javax.servlet.http.HttpServletRequest servletRequest)  
      String getTargetUri()
      The target URI as configured.
      protected String getTargetUri​(javax.servlet.http.HttpServletRequest servletRequest)  
      protected void handleRequestException​(org.apache.http.HttpRequest proxyRequest, org.apache.http.HttpResponse proxyResonse, Exception e)  
      void init()  
      protected void initTarget()  
      protected org.apache.http.HttpRequest newProxyRequestWithEntity​(String method, String proxyRequestUri, javax.servlet.http.HttpServletRequest servletRequest)  
      protected String rewritePathInfoFromRequest​(javax.servlet.http.HttpServletRequest servletRequest)
      Allow overrides of HttpServletRequest.getPathInfo().
      protected String rewriteQueryStringFromRequest​(javax.servlet.http.HttpServletRequest servletRequest, String queryString)  
      protected String rewriteUrlFromRequest​(javax.servlet.http.HttpServletRequest servletRequest)
      Reads the request URI from servletRequest and rewrites it, considering targetUri.
      protected String rewriteUrlFromResponse​(javax.servlet.http.HttpServletRequest servletRequest, String theUrl)
      For a redirect response from the target server, this translates theUrl to redirect to and translates it to one the original client can use.
      protected void service​(javax.servlet.http.HttpServletRequest servletRequest, javax.servlet.http.HttpServletResponse servletResponse)  
      • Methods inherited from class javax.servlet.http.HttpServlet

        doDelete, doGet, doHead, doOptions, doPost, doPut, doTrace, getLastModified, service
      • Methods inherited from class javax.servlet.GenericServlet

        getInitParameter, getInitParameterNames, getServletConfig, getServletContext, getServletName, init, log, log
    • Field Detail

      • P_LOG

        public static final String P_LOG
        A boolean parameter name to enable logging of input and target URLs to the servlet log.
        See Also:
        Constant Field Values
      • P_FORWARDEDFOR

        public static final String P_FORWARDEDFOR
        A boolean parameter name to enable forwarding of the client IP
        See Also:
        Constant Field Values
      • P_PRESERVEHOST

        public static final String P_PRESERVEHOST
        A boolean parameter name to keep HOST parameter as-is
        See Also:
        Constant Field Values
      • P_PRESERVECOOKIES

        public static final String P_PRESERVECOOKIES
        A boolean parameter name to keep COOKIES as-is
        See Also:
        Constant Field Values
      • P_HANDLEREDIRECTS

        public static final String P_HANDLEREDIRECTS
        A boolean parameter name to have auto-handle redirects
        See Also:
        Constant Field Values
      • P_CONNECTTIMEOUT

        public static final String P_CONNECTTIMEOUT
        An integer parameter name to set the socket connection timeout (millis)
        See Also:
        Constant Field Values
      • P_READTIMEOUT

        public static final String P_READTIMEOUT
        An integer parameter name to set the socket read timeout (millis)
        See Also:
        Constant Field Values
      • P_CONNECTIONREQUESTTIMEOUT

        public static final String P_CONNECTIONREQUESTTIMEOUT
        An integer parameter name to set the connection request timeout (millis)
        See Also:
        Constant Field Values
      • P_MAXCONNECTIONS

        public static final String P_MAXCONNECTIONS
        An integer parameter name to set max connection number
        See Also:
        Constant Field Values
      • P_USESYSTEMPROPERTIES

        public static final String P_USESYSTEMPROPERTIES
        A boolean parameter whether to use JVM-defined system properties to configure various networking aspects.
        See Also:
        Constant Field Values
      • P_HANDLECOMPRESSION

        public static final String P_HANDLECOMPRESSION
        A boolean parameter to enable handling of compression in the servlet. If it is false, compressed streams are passed through unmodified.
        See Also:
        Constant Field Values
      • P_TARGET_URI

        public static final String P_TARGET_URI
        The parameter name for the target (destination) URI to proxy to.
        See Also:
        Constant Field Values
      • ATTR_TARGET_URI

        protected static final String ATTR_TARGET_URI
      • ATTR_TARGET_HOST

        protected static final String ATTR_TARGET_HOST
      • doLog

        protected boolean doLog
      • doForwardIP

        protected boolean doForwardIP
      • doSendUrlFragment

        protected boolean doSendUrlFragment
        User agents shouldn't send the url fragment but what if it does?
      • doPreserveHost

        protected boolean doPreserveHost
      • doPreserveCookies

        protected boolean doPreserveCookies
      • doHandleRedirects

        protected boolean doHandleRedirects
      • useSystemProperties

        protected boolean useSystemProperties
      • doHandleCompression

        protected boolean doHandleCompression
      • connectTimeout

        protected int connectTimeout
      • readTimeout

        protected int readTimeout
      • connectionRequestTimeout

        protected int connectionRequestTimeout
      • maxConnections

        protected int maxConnections
      • targetUri

        protected String targetUri
        From the configured parameter "targetUri".
      • targetUriObj

        protected URI targetUriObj
      • targetHost

        protected org.apache.http.HttpHost targetHost
      • hopByHopHeaders

        protected static final org.apache.http.message.HeaderGroup hopByHopHeaders
        These are the "hop-by-hop" headers that should not be copied. http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html I use an HttpClient HeaderGroup class instead of Set<String> because this approach does case insensitive lookup faster.
      • asciiQueryChars

        protected static final BitSet asciiQueryChars
    • Constructor Detail

      • ProxyServlet

        public ProxyServlet()
    • Method Detail

      • getServletInfo

        public String getServletInfo()
        Specified by:
        getServletInfo in interface javax.servlet.Servlet
        Overrides:
        getServletInfo in class javax.servlet.GenericServlet
      • getTargetUri

        protected String getTargetUri​(javax.servlet.http.HttpServletRequest servletRequest)
      • getTargetHost

        protected org.apache.http.HttpHost getTargetHost​(javax.servlet.http.HttpServletRequest servletRequest)
      • getConfigParam

        protected String getConfigParam​(String key)
        Reads a configuration parameter. By default it reads servlet init parameters but it can be overridden.
      • init

        public void init()
                  throws javax.servlet.ServletException
        Overrides:
        init in class javax.servlet.GenericServlet
        Throws:
        javax.servlet.ServletException
      • buildRequestConfig

        protected org.apache.http.client.config.RequestConfig buildRequestConfig()
        Sub-classes can override specific behaviour of RequestConfig.
      • buildSocketConfig

        protected org.apache.http.config.SocketConfig buildSocketConfig()
        Sub-classes can override specific behaviour of SocketConfig.
      • initTarget

        protected void initTarget()
                           throws javax.servlet.ServletException
        Throws:
        javax.servlet.ServletException
      • createHttpClient

        protected org.apache.http.client.HttpClient createHttpClient()
        Called from GenericServlet.init(javax.servlet.ServletConfig). HttpClient offers many opportunities for customization. In any case, it should be thread-safe.
      • buildHttpClient

        protected org.apache.http.client.HttpClient buildHttpClient​(org.apache.http.impl.client.HttpClientBuilder clientBuilder)
        Creates a HttpClient from the given builder. Meant as postprocessor to possibly adapt the client builder prior to creating the HttpClient.
        Parameters:
        clientBuilder - pre-configured client builder
        Returns:
        HttpClient
      • getHttpClientBuilder

        protected org.apache.http.impl.client.HttpClientBuilder getHttpClientBuilder()
        Creates a HttpClientBuilder. Meant as preprocessor to possibly adapt the client builder prior to any configuration got applied.
        Returns:
        HttpClient builder
      • getProxyClient

        protected org.apache.http.client.HttpClient getProxyClient()
        The http client used.
        See Also:
        createHttpClient()
      • destroy

        public void destroy()
        Specified by:
        destroy in interface javax.servlet.Servlet
        Overrides:
        destroy in class javax.servlet.GenericServlet
      • service

        protected void service​(javax.servlet.http.HttpServletRequest servletRequest,
                               javax.servlet.http.HttpServletResponse servletResponse)
                        throws javax.servlet.ServletException,
                               IOException
        Overrides:
        service in class javax.servlet.http.HttpServlet
        Throws:
        javax.servlet.ServletException
        IOException
      • handleRequestException

        protected void handleRequestException​(org.apache.http.HttpRequest proxyRequest,
                                              org.apache.http.HttpResponse proxyResonse,
                                              Exception e)
                                       throws javax.servlet.ServletException,
                                              IOException
        Throws:
        javax.servlet.ServletException
        IOException
      • doExecute

        protected org.apache.http.HttpResponse doExecute​(javax.servlet.http.HttpServletRequest servletRequest,
                                                         javax.servlet.http.HttpServletResponse servletResponse,
                                                         org.apache.http.HttpRequest proxyRequest)
                                                  throws IOException
        Throws:
        IOException
      • newProxyRequestWithEntity

        protected org.apache.http.HttpRequest newProxyRequestWithEntity​(String method,
                                                                        String proxyRequestUri,
                                                                        javax.servlet.http.HttpServletRequest servletRequest)
                                                                 throws IOException
        Throws:
        IOException
      • closeQuietly

        protected void closeQuietly​(Closeable closeable)
      • copyRequestHeaders

        protected void copyRequestHeaders​(javax.servlet.http.HttpServletRequest servletRequest,
                                          org.apache.http.HttpRequest proxyRequest)
        Copy request headers from the servlet client to the proxy request. This is easily overridden to add your own.
      • copyRequestHeader

        protected void copyRequestHeader​(javax.servlet.http.HttpServletRequest servletRequest,
                                         org.apache.http.HttpRequest proxyRequest,
                                         String headerName)
        Copy a request header from the servlet client to the proxy request. This is easily overridden to filter out certain headers if desired.
      • copyResponseHeaders

        protected void copyResponseHeaders​(org.apache.http.HttpResponse proxyResponse,
                                           javax.servlet.http.HttpServletRequest servletRequest,
                                           javax.servlet.http.HttpServletResponse servletResponse)
        Copy proxied response headers back to the servlet client.
      • copyResponseHeader

        protected void copyResponseHeader​(javax.servlet.http.HttpServletRequest servletRequest,
                                          javax.servlet.http.HttpServletResponse servletResponse,
                                          org.apache.http.Header header)
        Copy a proxied response header back to the servlet client. This is easily overwritten to filter out certain headers if desired.
      • copyProxyCookie

        protected void copyProxyCookie​(javax.servlet.http.HttpServletRequest servletRequest,
                                       javax.servlet.http.HttpServletResponse servletResponse,
                                       String headerValue)
        Copy cookie from the proxy to the servlet client. Replaces cookie path to local path and renames cookie to avoid collisions.
      • createProxyCookie

        protected javax.servlet.http.Cookie createProxyCookie​(javax.servlet.http.HttpServletRequest servletRequest,
                                                              HttpCookie cookie)
        Creates a proxy cookie from the original cookie.
        Parameters:
        servletRequest - original request
        cookie - original cookie
        Returns:
        proxy cookie
      • getProxyCookieName

        protected String getProxyCookieName​(HttpCookie cookie)
        Set cookie name prefixed with a proxy value so it won't collide with other cookies.
        Parameters:
        cookie - cookie to get proxy cookie name for
        Returns:
        non-conflicting proxy cookie name
      • buildProxyCookiePath

        protected String buildProxyCookiePath​(javax.servlet.http.HttpServletRequest servletRequest)
        Create path for proxy cookie.
        Parameters:
        servletRequest - original request
        Returns:
        proxy cookie path
      • getRealCookie

        protected String getRealCookie​(String cookieValue)
        Take any client cookies that were originally from the proxy and prepare them to send to the proxy. This relies on cookie headers being set correctly according to RFC 6265 Sec 5.4. This also blocks any local cookies from being sent to the proxy.
      • getCookieNamePrefix

        protected String getCookieNamePrefix​(String name)
        The string prefixing rewritten cookies.
      • copyResponseEntity

        protected void copyResponseEntity​(org.apache.http.HttpResponse proxyResponse,
                                          javax.servlet.http.HttpServletResponse servletResponse,
                                          org.apache.http.HttpRequest proxyRequest,
                                          javax.servlet.http.HttpServletRequest servletRequest)
                                   throws IOException
        Copy response body data (the entity) from the proxy to the servlet client.
        Throws:
        IOException
      • rewriteUrlFromRequest

        protected String rewriteUrlFromRequest​(javax.servlet.http.HttpServletRequest servletRequest)
        Reads the request URI from servletRequest and rewrites it, considering targetUri. It's used to make the new request.
      • rewriteQueryStringFromRequest

        protected String rewriteQueryStringFromRequest​(javax.servlet.http.HttpServletRequest servletRequest,
                                                       String queryString)
      • rewritePathInfoFromRequest

        protected String rewritePathInfoFromRequest​(javax.servlet.http.HttpServletRequest servletRequest)
        Allow overrides of HttpServletRequest.getPathInfo(). Useful when url-pattern of servlet-mapping (web.xml) requires manipulation.
      • rewriteUrlFromResponse

        protected String rewriteUrlFromResponse​(javax.servlet.http.HttpServletRequest servletRequest,
                                                String theUrl)
        For a redirect response from the target server, this translates theUrl to redirect to and translates it to one the original client can use.
      • getTargetUri

        public String getTargetUri()
        The target URI as configured. Not null.
      • encodeUriQuery

        protected CharSequence encodeUriQuery​(CharSequence in,
                                              boolean encodePercent)
        Encodes characters in the query or fragment part of the URI.

        Unfortunately, an incoming URI sometimes has characters disallowed by the spec. HttpClient insists that the outgoing proxied request has a valid URI because it uses Java's URI. To be more forgiving, we must escape the problematic characters. See the URI class for the spec.

        Parameters:
        in - example: name=value&foo=bar#fragment
        encodePercent - determine whether percent characters need to be encoded