| author | Thomas Becker | 2011-09-23 11:43:07 (EDT) |
|---|---|---|
| committer | Jesse McConnell | 2011-09-26 18:50:27 (EDT) |
| commit | 88ce9aceb25fd3bce460904a66c98095391f220b (patch) (side-by-side diff) | |
| tree | ba0b14b1364485a1453e0a993db8304d9e01841a | |
| parent | b94f901433df1554ab5b0ab1b106e619de508958 (diff) | |
| download | org.eclipse.jetty.project-88ce9aceb25fd3bce460904a66c98095391f220b.zip org.eclipse.jetty.project-88ce9aceb25fd3bce460904a66c98095391f220b.tar.gz org.eclipse.jetty.project-88ce9aceb25fd3bce460904a66c98095391f220b.tar.bz2 | |
Added ProxyRule.java and ProxyRuleTest.java
| -rw-r--r-- | jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java | 282 | ||||
| -rw-r--r-- | jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ProxyRuleTest.java | 77 |
2 files changed, 359 insertions, 0 deletions
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java new file mode 100644 index 0000000..b5516bc --- a/dev/null +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java @@ -0,0 +1,282 @@ +package org.eclipse.jetty.rewrite.handler; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.HashSet; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpExchange; +import org.eclipse.jetty.http.HttpHeaderValues; +import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpSchemes; +import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.io.Buffer; +import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.thread.QueuedThreadPool; + +public class ProxyRule extends Rule +{ + private static final Logger _log = Log.getLogger(ProxyRule.class); + + protected HttpClient _client; + protected String _hostHeader; + + protected HashSet<String> _DontProxyHeaders = new HashSet<String>(); + { + _DontProxyHeaders.add("proxy-connection"); + _DontProxyHeaders.add("connection"); + _DontProxyHeaders.add("keep-alive"); + _DontProxyHeaders.add("transfer-encoding"); + _DontProxyHeaders.add("te"); + _DontProxyHeaders.add("trailer"); + _DontProxyHeaders.add("proxy-authorization"); + _DontProxyHeaders.add("proxy-authenticate"); + _DontProxyHeaders.add("upgrade"); + } + + public ProxyRule() + { + _handling = true; + _terminating = true; + + } + + private void initializeClient() throws Exception + { + _client = new HttpClient(); + _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + _client.setThreadPool(new QueuedThreadPool()); + _client.start(); + } + + /* ------------------------------------------------------------ */ + protected HttpURI proxyHttpURI(String scheme, String serverName, int serverPort, String uri) throws MalformedURLException + { + return new HttpURI(scheme + "://" + serverName + ":" + serverPort + uri); + } + + @Override + public String matchAndApply(String target, HttpServletRequest req, HttpServletResponse res) throws IOException + { + synchronized (this) + { + if (_client == null) + { + try + { + initializeClient(); + } + catch (Exception e) + { + throw new IOException("Unable to proxy: " + e.getMessage()); + } + } + } + + final HttpServletRequest request = (HttpServletRequest)req; + final HttpServletResponse response = (HttpServletResponse)res; + + final int debug = _log.isDebugEnabled()?request.hashCode():0; + + final InputStream in = request.getInputStream(); + final OutputStream out = response.getOutputStream(); + + String uri = request.getRequestURI(); + if (request.getQueryString() != null) + uri += "?" + request.getQueryString(); + + HttpURI url = proxyHttpURI(request.getScheme(),request.getServerName(),request.getServerPort(),uri); + + if (debug != 0) + _log.debug(debug + " proxy " + uri + "-->" + url); + + if (url == null) + { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return target; + } + + HttpExchange exchange = new HttpExchange() + { + protected void onRequestCommitted() throws IOException + { + } + + protected void onRequestComplete() throws IOException + { + } + + protected void onResponseComplete() throws IOException + { + if (debug != 0) + _log.debug(debug + " complete"); + } + + protected void onResponseContent(Buffer content) throws IOException + { + if (debug != 0) + _log.debug(debug + " content" + content.length()); + content.writeTo(out); + } + + protected void onResponseHeaderComplete() throws IOException + { + } + + protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException + { + if (debug != 0) + _log.debug(debug + " " + version + " " + status + " " + reason); + + if (reason != null && reason.length() > 0) + response.setStatus(status,reason.toString()); + else + response.setStatus(status); + } + + protected void onResponseHeader(Buffer name, Buffer value) throws IOException + { + String s = name.toString().toLowerCase(); + if (!_DontProxyHeaders.contains(s) || (HttpHeaders.CONNECTION_BUFFER.equals(name) && HttpHeaderValues.CLOSE_BUFFER.equals(value))) + { + if (debug != 0) + _log.debug(debug + " " + name + ": " + value); + + response.addHeader(name.toString(),value.toString()); + } + else if (debug != 0) + _log.debug(debug + " " + name + "! " + value); + } + + protected void onConnectionFailed(Throwable ex) + { + _log.warn(ex.toString()); + _log.debug(ex); + if (!response.isCommitted()) + { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + + protected void onException(Throwable ex) + { + if (ex instanceof EofException) + { + _log.ignore(ex); + return; + } + _log.warn(ex.toString()); + _log.debug(ex); + if (!response.isCommitted()) + { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + + protected void onExpire() + { + if (!response.isCommitted()) + { + response.setStatus(HttpServletResponse.SC_GATEWAY_TIMEOUT); + } + } + + }; + + exchange.setScheme(HttpSchemes.HTTPS.equals(request.getScheme())?HttpSchemes.HTTPS_BUFFER:HttpSchemes.HTTP_BUFFER); + exchange.setMethod(request.getMethod()); + exchange.setURL(url.toString()); + exchange.setVersion(request.getProtocol()); + + if (debug != 0) + _log.debug(debug + " " + request.getMethod() + " " + url + " " + request.getProtocol()); + + // check connection header + String connectionHdr = request.getHeader("Connection"); + if (connectionHdr != null) + { + connectionHdr = connectionHdr.toLowerCase(); + if (connectionHdr.indexOf("keep-alive") < 0 && connectionHdr.indexOf("close") < 0) + connectionHdr = null; + } + + // force host + if (_hostHeader != null) + exchange.setRequestHeader("Host",_hostHeader); + + // copy headers + boolean xForwardedFor = false; + boolean hasContent = false; + long contentLength = -1; + Enumeration<?> enm = request.getHeaderNames(); + while (enm.hasMoreElements()) + { + // TODO could be better than this! + String hdr = (String)enm.nextElement(); + String lhdr = hdr.toLowerCase(); + + if (_DontProxyHeaders.contains(lhdr)) + continue; + if (connectionHdr != null && connectionHdr.indexOf(lhdr) >= 0) + continue; + if (_hostHeader != null && "host".equals(lhdr)) + continue; + + if ("content-type".equals(lhdr)) + hasContent = true; + else if ("content-length".equals(lhdr)) + { + contentLength = request.getContentLength(); + exchange.setRequestHeader(HttpHeaders.CONTENT_LENGTH,Long.toString(contentLength)); + if (contentLength > 0) + hasContent = true; + } + else if ("x-forwarded-for".equals(lhdr)) + xForwardedFor = true; + + Enumeration<?> vals = request.getHeaders(hdr); + while (vals.hasMoreElements()) + { + String val = (String)vals.nextElement(); + if (val != null) + { + if (debug != 0) + _log.debug(debug + " " + hdr + ": " + val); + + exchange.setRequestHeader(hdr,val); + } + } + } + + // Proxy headers + exchange.setRequestHeader("Via","1.1 (jetty)"); + if (!xForwardedFor) + { + exchange.addRequestHeader("X-Forwarded-For",request.getRemoteAddr()); + exchange.addRequestHeader("X-Forwarded-Proto",request.getScheme()); + exchange.addRequestHeader("X-Forwarded-Host",request.getServerName()); + exchange.addRequestHeader("X-Forwarded-Server",request.getLocalName()); + } + + if (hasContent) + exchange.setRequestContentSource(in); + + /* + * we need to set the timeout on the continuation to take into account the timeout of the HttpClient and the HttpExchange + */ + long ctimeout = (_client.getTimeout() > exchange.getTimeout())?_client.getTimeout():exchange.getTimeout(); + + _client.send(exchange); + + return target; + } + +} diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ProxyRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ProxyRuleTest.java new file mode 100644 index 0000000..9f021a5 --- a/dev/null +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ProxyRuleTest.java @@ -0,0 +1,77 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.rewrite.handler; + +import java.io.IOException; +import java.net.URI; +import java.net.URLEncoder; + +import org.eclipse.jetty.client.Address; +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.HttpExchange; +import org.eclipse.jetty.http.HttpHeaders; +import org.eclipse.jetty.http.HttpMethods; +import org.eclipse.jetty.toolchain.test.SimpleRequest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ProxyRuleTest extends AbstractRuleTestCase +{ + private ProxyRule _rule; + private RewriteHandler _handler; + + @Before + public void init() throws Exception + { + start(false); + _rule = new ProxyRule(); + + _handler = new RewriteHandler(); + _handler.setRewriteRequestURI(true); + + _handler.setRules(new Rule[] { _rule } ); + + _server.setHandler(_handler); + } + + @After + public void destroy() + { + _rule = null; + } + + @Test + public void testProxy() throws Exception + { +// HttpClient httpClient = new HttpClient(); +// httpClient.setProxy(new Address("localhost", proxyPort())); +// httpClient.start(); +// +// try +// { +// ContentExchange exchange = new ContentExchange(true); +// exchange.setMethod(HttpMethods.GET); +// String body = "BODY"; +// exchange.setURL("https://localhost:" + serverConnector.getLocalPort() + "/echo?body=" + URLEncoder.encode(body, "UTF-8")); +// +// httpClient.send(exchange); +// assertEquals(HttpExchange.STATUS_COMPLETED, exchange.waitForDone()); +// //_rule.matchAndApply(null, _request, _response); +// +// //assertEquals(location, _response.getHeader(HttpHeaders.LOCATION)); + } +} |

