Skip to content

Instantly share code, notes, and snippets.

@ppkarwasz
Last active December 28, 2020 13:10
Show Gist options
  • Save ppkarwasz/925520383962ea37aa3025882f71640a to your computer and use it in GitHub Desktop.
Save ppkarwasz/925520383962ea37aa3025882f71640a to your computer and use it in GitHub Desktop.
An example how to register `ProxyServlet` instances during runtime.
package pl.copernik.servlet;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.TreeMap;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.mitre.dsmiley.httpproxy.ProxyServlet;
public class MetaProxyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* To configure a {@link ProxyServlet} without modifying its code.
*/
private static class ProxyServletConfig implements ServletConfig {
private static final String P_TARGET_URI = "targetUri";
private final String servletName;
private final ServletContext servletContext;
private final String targetUri;
public ProxyServletConfig(String servletName, ServletContext servletContext, String targetUri) {
this.servletName = servletName;
this.servletContext = servletContext;
this.targetUri = targetUri;
}
@Override
public String getServletName() {
return servletName;
}
@Override
public ServletContext getServletContext() {
return servletContext;
}
@Override
public String getInitParameter(String name) {
return P_TARGET_URI.equals(name) ? targetUri : null;
}
@Override
public Enumeration<String> getInitParameterNames() {
return Collections.enumeration(Collections.singleton(P_TARGET_URI));
}
}
/**
* Serves to modify the pathInfo of the request.
*/
private static class RewrittenServletRequest extends HttpServletRequestWrapper {
private final String pathInfo;
public RewrittenServletRequest(HttpServletRequest request, String pathInfo) {
super(request);
this.pathInfo = pathInfo;
}
@Override
public String getPathInfo() {
return pathInfo;
}
}
private TreeMap<String, ProxyServlet> proxyServlets = new TreeMap<>();
/**
* Adds a reverse proxy between {@code pathPrefix} of this servlets namespace
* and {@code targetUri}.
*
* @param pathPrefix
* must start with '/'
* @param targetUri
* URI to be proxied
* @throws ServletException
*/
public void addRedirect(String pathPrefix, String targetUri) throws ServletException {
Objects.requireNonNull(pathPrefix);
Objects.requireNonNull(targetUri);
final ProxyServlet servlet = new ProxyServlet();
servlet.init(new ProxyServletConfig(pathPrefix, getServletContext(), targetUri));
proxyServlets.put(pathPrefix, servlet);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String pathInfo = req.getPathInfo();
Entry<String, ProxyServlet> entry = proxyServlets.floorEntry(pathInfo);
// entry.getKey() precedes, but not necessarily is a prefix for pathInfo
if (entry != null && pathInfo.startsWith(entry.getKey())) {
String rewrittenPathInfo = pathInfo.substring(entry.getKey().length());
entry.getValue()//
.service(new RewrittenServletRequest(req, rewrittenPathInfo), resp);
} else {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment