Merged branch 'jetty-9.2.x' into 'master'.

This commit is contained in:
Simone Bordet 2015-04-21 12:38:04 +02:00
commit 9983f4680e
4 changed files with 103 additions and 70 deletions

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.proxy;
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Enumeration;
@ -33,6 +34,7 @@ import java.util.concurrent.TimeoutException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -611,4 +613,73 @@ public abstract class AbstractProxyServlet extends HttpServlet
{
return System.identityHashCode(clientRequest);
}
/**
* <p>Utility class that implement transparent proxy functionalities.</p>
* <p>Configuration parameters:</p>
* <ul>
* <li>{@code proxyTo} - a mandatory URI like http://host:80/context to which the request is proxied.</li>
* <li>{@code prefix} - an optional URI prefix that is stripped from the start of the forwarded URI.</li>
* </ul>
* <p>For example, if a request is received at "/foo/bar", the {@code proxyTo} parameter is
* "http://host:80/context" and the {@code prefix} parameter is "/foo", then the request would
* be proxied to "http://host:80/context/bar".
*/
protected static class TransparentDelegate
{
private final ProxyServlet proxyServlet;
private String _proxyTo;
private String _prefix;
protected TransparentDelegate(ProxyServlet proxyServlet)
{
this.proxyServlet = proxyServlet;
}
protected void init(ServletConfig config) throws ServletException
{
_proxyTo = config.getInitParameter("proxyTo");
if (_proxyTo == null)
throw new UnavailableException("Init parameter 'proxyTo' is required.");
String prefix = config.getInitParameter("prefix");
if (prefix != null)
{
if (!prefix.startsWith("/"))
throw new UnavailableException("Init parameter 'prefix' must start with a '/'.");
_prefix = prefix;
}
// Adjust prefix value to account for context path
String contextPath = config.getServletContext().getContextPath();
_prefix = _prefix == null ? contextPath : (contextPath + _prefix);
if (proxyServlet._log.isDebugEnabled())
proxyServlet._log.debug(config.getServletName() + " @ " + _prefix + " to " + _proxyTo);
}
protected String rewriteTarget(HttpServletRequest request)
{
String path = request.getRequestURI();
if (!path.startsWith(_prefix))
return null;
StringBuilder uri = new StringBuilder(_proxyTo);
if (_proxyTo.endsWith("/"))
uri.setLength(uri.length() - 1);
String rest = path.substring(_prefix.length());
if (!rest.startsWith("/"))
uri.append("/");
uri.append(rest);
String query = request.getQueryString();
if (query != null)
uri.append("?").append(query);
URI rewrittenURI = URI.create(uri.toString()).normalize();
if (!proxyServlet.validateDestination(rewrittenURI.getHost(), rewrittenURI.getPort()))
return null;
return rewrittenURI.toString();
}
}
}

View File

@ -31,6 +31,7 @@ import java.util.zip.GZIPOutputStream;
import javax.servlet.AsyncContext;
import javax.servlet.ReadListener;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
@ -194,6 +195,29 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet
((Destroyable)serverTransformer).destroy();
}
/**
* <p>Convenience extension of {@link AsyncMiddleManServlet} that offers transparent proxy functionalities.</p>
*
* @see TransparentDelegate
*/
public static class Transparent extends ProxyServlet
{
private final TransparentDelegate delegate = new TransparentDelegate(this);
@Override
public void init(ServletConfig config) throws ServletException
{
super.init(config);
delegate.init(config);
}
@Override
protected String rewriteTarget(HttpServletRequest request)
{
return delegate.rewriteTarget(request);
}
}
protected class ProxyReader extends IteratingCallback implements ReadListener
{
private final byte[] buffer = new byte[getHttpClient().getRequestBufferSize()];
@ -750,5 +774,4 @@ public class AsyncMiddleManServlet extends AbstractProxyServlet
return ByteBuffer.wrap(gzipBytes);
}
}
}

View File

@ -99,6 +99,11 @@ public class AsyncProxyServlet extends ProxyServlet
return new StreamWriter(request, proxyResponse);
}
/**
* <p>Convenience extension of {@link AsyncProxyServlet} that offers transparent proxy functionalities.</p>
*
* @see TransparentDelegate
*/
public static class Transparent extends AsyncProxyServlet
{
private final TransparentDelegate delegate = new TransparentDelegate(this);

View File

@ -20,14 +20,12 @@ package org.eclipse.jetty.proxy;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import javax.servlet.AsyncContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -128,15 +126,9 @@ public class ProxyServlet extends AbstractProxyServlet
}
/**
* This convenience extension to {@link ProxyServlet} configures the servlet as a transparent proxy.
* This servlet is configured with the following init parameters:
* <ul>
* <li>proxyTo - a mandatory URI like http://host:80/context to which the request is proxied.</li>
* <li>prefix - an optional URI prefix that is stripped from the start of the forwarded URI.</li>
* </ul>
* <p>
* For example, if a request is received at "/foo/bar", the 'proxyTo' parameter is "http://host:80/context"
* and the 'prefix' parameter is "/foo", then the request would be proxied to "http://host:80/context/bar".
* <p>Convenience extension of {@link ProxyServlet} that offers transparent proxy functionalities.</p>
*
* @see TransparentDelegate
*/
public static class Transparent extends ProxyServlet
{
@ -156,64 +148,6 @@ public class ProxyServlet extends AbstractProxyServlet
}
}
protected static class TransparentDelegate
{
private final ProxyServlet proxyServlet;
private String _proxyTo;
private String _prefix;
protected TransparentDelegate(ProxyServlet proxyServlet)
{
this.proxyServlet = proxyServlet;
}
protected void init(ServletConfig config) throws ServletException
{
_proxyTo = config.getInitParameter("proxyTo");
if (_proxyTo == null)
throw new UnavailableException("Init parameter 'proxyTo' is required.");
String prefix = config.getInitParameter("prefix");
if (prefix != null)
{
if (!prefix.startsWith("/"))
throw new UnavailableException("Init parameter 'prefix' must start with a '/'.");
_prefix = prefix;
}
// Adjust prefix value to account for context path
String contextPath = config.getServletContext().getContextPath();
_prefix = _prefix == null ? contextPath : (contextPath + _prefix);
if (proxyServlet._log.isDebugEnabled())
proxyServlet._log.debug(config.getServletName() + " @ " + _prefix + " to " + _proxyTo);
}
protected String rewriteTarget(HttpServletRequest request)
{
String path = request.getRequestURI();
if (!path.startsWith(_prefix))
return null;
StringBuilder uri = new StringBuilder(_proxyTo);
if (_proxyTo.endsWith("/"))
uri.setLength(uri.length() - 1);
String rest = path.substring(_prefix.length());
if (!rest.startsWith("/"))
uri.append("/");
uri.append(rest);
String query = request.getQueryString();
if (query != null)
uri.append("?").append(query);
URI rewrittenURI = URI.create(uri.toString()).normalize();
if (!proxyServlet.validateDestination(rewrittenURI.getHost(), rewrittenURI.getPort()))
return null;
return rewrittenURI.toString();
}
}
protected class ProxyResponseListener extends Response.Listener.Adapter
{
private final HttpServletRequest request;