From 27753fa747430bc6834eed2d0bfe7c8252de2328 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 26 Sep 2011 23:00:57 +1000 Subject: [PATCH 1/9] removed debug --- .../eclipse/jetty/client/AsyncSslHttpExchangeTest.java | 8 ++++++++ .../jetty/server/ssl/SslSelectChannelConnector.java | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java index 8cfe3d7d2e6..e8c2accd48d 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/AsyncSslHttpExchangeTest.java @@ -29,4 +29,12 @@ public class AsyncSslHttpExchangeTest extends SslHttpExchangeTest _httpClient = serverAndClientCreator.createClient(3000L,3500L,2000); _port = _server.getConnectors()[0].getLocalPort(); } + + @Override + public void testPerf() throws Exception + { + super.testPerf(); + } + + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java index 8bfe80a4f8a..b1b3347321c 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ssl/SslSelectChannelConnector.java @@ -98,9 +98,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint; SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine(); SSLSession sslSession=sslEngine.getSession(); - - System.err.println(sslSession.getProtocol()); - + SslCertificates.customize(sslSession,endpoint,request); } From 88ce9aceb25fd3bce460904a66c98095391f220b Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Fri, 23 Sep 2011 17:43:07 +0200 Subject: [PATCH 2/9] Added ProxyRule.java and ProxyRuleTest.java --- .../jetty/rewrite/handler/ProxyRule.java | 282 ++++++++++++++++++ .../jetty/rewrite/handler/ProxyRuleTest.java | 77 +++++ 2 files changed, 359 insertions(+) create mode 100644 jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/ProxyRule.java create mode 100644 jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/ProxyRuleTest.java 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 00000000000..b5516bcbf68 --- /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 _DontProxyHeaders = new HashSet(); + { + _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 00000000000..9f021a5794f --- /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)); + } +} From 0d8bd99d6a9984358f9b8d62c84b4fb12364cb15 Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Mon, 26 Sep 2011 14:41:15 +0200 Subject: [PATCH 3/9] Basic functionality for ProxyRule implemented --- .../java/org/eclipse/jetty/http/PathMap.java | 120 +++++++++--------- jetty-rewrite/pom.xml | 5 + .../jetty/rewrite/handler/ProxyRule.java | 80 ++++++++---- .../jetty/rewrite/handler/ProxyRuleTest.java | 91 +++++++++---- 4 files changed, 183 insertions(+), 113 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java index 7e24daa3ebf..19da9e00104 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java @@ -4,11 +4,11 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.http; @@ -34,7 +34,7 @@ import org.eclipse.jetty.util.URIUtil; * /foo/bar - an exact path specification. * /foo/* - a prefix path specification (must end '/*'). * *.ext - a suffix path specification. - * / - the default path specification. + * / - the default path specification. * * Matching is performed in the following order *
  • Exact match. @@ -43,24 +43,24 @@ import org.eclipse.jetty.util.URIUtil; *
  • default. * * Multiple path specifications can be mapped by providing a list of - * specifications. By default this class uses characters ":," as path - * separators, unless configured differently by calling the static - * method @see PathMap#setPathSpecSeparators(String) + * specifications. By default this class uses characters ":," as path + * separators, unless configured differently by calling the static + * method @see PathMap#setPathSpecSeparators(String) *

    * Special characters within paths such as '?� and ';' are not treated specially - * as it is assumed they would have been either encoded in the original URL or + * as it is assumed they would have been either encoded in the original URL or * stripped from the path. *

    * This class is not synchronized. If concurrent modifications are * possible then it should be synchronized at a higher level. * - * + * */ public class PathMap extends HashMap implements Externalizable { /* ------------------------------------------------------------ */ private static String __pathSpecSeparators = ":,"; - + /* ------------------------------------------------------------ */ /** Set the path spec separator. * Multiple path specification may be included in a single string @@ -72,7 +72,7 @@ public class PathMap extends HashMap implements Externalizable { __pathSpecSeparators=s; } - + /* --------------------------------------------------------------- */ final StringMap _prefixMap=new StringMap(); final StringMap _suffixMap=new StringMap(); @@ -83,7 +83,7 @@ public class PathMap extends HashMap implements Externalizable Entry _default=null; final Set _entrySet; boolean _nodefault=false; - + /* --------------------------------------------------------------- */ /** Construct empty PathMap. */ @@ -102,7 +102,7 @@ public class PathMap extends HashMap implements Externalizable _entrySet=entrySet(); _nodefault=nodefault; } - + /* --------------------------------------------------------------- */ /** Construct empty PathMap. */ @@ -111,7 +111,7 @@ public class PathMap extends HashMap implements Externalizable super (capacity); _entrySet=entrySet(); } - + /* --------------------------------------------------------------- */ /** Construct from dictionary PathMap. */ @@ -120,7 +120,7 @@ public class PathMap extends HashMap implements Externalizable putAll(m); _entrySet=entrySet(); } - + /* ------------------------------------------------------------ */ public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException @@ -128,7 +128,7 @@ public class PathMap extends HashMap implements Externalizable HashMap map = new HashMap(this); out.writeObject(map); } - + /* ------------------------------------------------------------ */ public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException @@ -136,7 +136,7 @@ public class PathMap extends HashMap implements Externalizable HashMap map = (HashMap)in.readObject(); this.putAll(map); } - + /* --------------------------------------------------------------- */ /** Add a single path match to the PathMap. * @param pathSpec The path specification, or comma separated list of @@ -148,16 +148,16 @@ public class PathMap extends HashMap implements Externalizable { StringTokenizer tok = new StringTokenizer(pathSpec.toString(),__pathSpecSeparators); Object old =null; - + while (tok.hasMoreTokens()) { String spec=tok.nextToken(); - + if (!spec.startsWith("/") && !spec.startsWith("*.")) throw new IllegalArgumentException("PathSpec "+spec+". must start with '/' or '*.'"); - + old = super.put(spec,object); - + // Make entry that was just created. Entry entry = new Entry(spec,object); @@ -176,7 +176,7 @@ public class PathMap extends HashMap implements Externalizable else if (spec.startsWith("*.")) _suffixMap.put(spec.substring(2),entry); else if (spec.equals(URIUtil.SLASH)) - { + { if (_nodefault) _exactMap.put(spec,entry); else @@ -193,7 +193,7 @@ public class PathMap extends HashMap implements Externalizable } } } - + return old; } @@ -209,8 +209,8 @@ public class PathMap extends HashMap implements Externalizable return entry.getValue(); return null; } - - + + /* --------------------------------------------------------------- */ /** Get the entry mapped by the best specification. * @param path the path. @@ -222,14 +222,14 @@ public class PathMap extends HashMap implements Externalizable if (path==null) return null; - - int l=path.length(); + + int l=path.length(); // try exact match entry=_exactMap.getEntry(path,0,l); if (entry!=null) return (Entry) entry.getValue(); - + // prefix search int i=l; while((i=path.lastIndexOf('/',i-1))>=0) @@ -238,11 +238,11 @@ public class PathMap extends HashMap implements Externalizable if (entry!=null) return (Entry) entry.getValue(); } - + // Prefix Default if (_prefixDefault!=null) return _prefixDefault; - + // Extension search i=0; while ((i=path.indexOf('.',i+1))>0) @@ -250,12 +250,12 @@ public class PathMap extends HashMap implements Externalizable entry=_suffixMap.getEntry(path,i+1,l-i-1); if (entry!=null) return (Entry) entry.getValue(); - } - + } + // Default return _default; } - + /* --------------------------------------------------------------- */ /** Get all entries matched by the path. * Best match first. @@ -263,20 +263,20 @@ public class PathMap extends HashMap implements Externalizable * @return LazyList of Map.Entry instances key=pathSpec */ public Object getLazyMatches(String path) - { + { Map.Entry entry; Object entries=null; if (path==null) return LazyList.getList(entries); - + int l=path.length(); // try exact match entry=_exactMap.getEntry(path,0,l); if (entry!=null) entries=LazyList.add(entries,entry.getValue()); - + // prefix search int i=l-1; while((i=path.lastIndexOf('/',i-1))>=0) @@ -285,11 +285,11 @@ public class PathMap extends HashMap implements Externalizable if (entry!=null) entries=LazyList.add(entries,entry.getValue()); } - + // Prefix Default if (_prefixDefault!=null) entries=LazyList.add(entries,_prefixDefault); - + // Extension search i=0; while ((i=path.indexOf('.',i+1))>0) @@ -305,13 +305,13 @@ public class PathMap extends HashMap implements Externalizable // Optimization for just the default if (entries==null) return _defaultSingletonList; - + entries=LazyList.add(entries,_default); } - + return entries; } - + /* --------------------------------------------------------------- */ /** Get all entries matched by the path. * Best match first. @@ -319,7 +319,7 @@ public class PathMap extends HashMap implements Externalizable * @return List of Map.Entry instances key=pathSpec */ public List getMatches(String path) - { + { return LazyList.getList(getLazyMatches(path)); } @@ -330,12 +330,12 @@ public class PathMap extends HashMap implements Externalizable * @return Whether the PathMap contains any entries that match this */ public boolean containsMatch(String path) - { + { Entry match = getMatch(path); return match!=null && !match.equals(_default); } - /* --------------------------------------------------------------- */ + /* --------------------------------------------------------------- */ @Override public Object remove(Object pathSpec) { @@ -362,7 +362,7 @@ public class PathMap extends HashMap implements Externalizable } return super.remove(pathSpec); } - + /* --------------------------------------------------------------- */ @Override public void clear() @@ -374,7 +374,7 @@ public class PathMap extends HashMap implements Externalizable _defaultSingletonList=null; super.clear(); } - + /* --------------------------------------------------------------- */ /** * @return true if match. @@ -397,7 +397,7 @@ public class PathMap extends HashMap implements Externalizable { if (!noDefault && pathSpec.length()==1 || pathSpec.equals(path)) return true; - + if(isPathWildcardMatch(pathSpec, path)) return true; } @@ -419,24 +419,24 @@ public class PathMap extends HashMap implements Externalizable } return false; } - - + + /* --------------------------------------------------------------- */ /** Return the portion of a path that matches a path spec. * @return null if no match at all. */ public static String pathMatch(String pathSpec, String path) - { + { char c = pathSpec.charAt(0); - + if (c=='/') { if (pathSpec.length()==1) return path; - + if (pathSpec.equals(path)) return path; - + if (isPathWildcardMatch(pathSpec, path)) return path.substring(0,pathSpec.length()-2); } @@ -448,7 +448,7 @@ public class PathMap extends HashMap implements Externalizable } return null; } - + /* --------------------------------------------------------------- */ /** Return the portion of a path that is after a path spec. * @return The path info string @@ -456,12 +456,12 @@ public class PathMap extends HashMap implements Externalizable public static String pathInfo(String pathSpec, String path) { char c = pathSpec.charAt(0); - + if (c=='/') { if (pathSpec.length()==1) return null; - + boolean wildcard = isPathWildcardMatch(pathSpec, path); // handle the case where pathSpec uses a wildcard and path info is "/*" @@ -474,7 +474,7 @@ public class PathMap extends HashMap implements Externalizable return null; return path.substring(pathSpec.length()-2); } - } + } return null; } @@ -484,7 +484,7 @@ public class PathMap extends HashMap implements Externalizable * @param base The base the path is relative to. * @param pathSpec The spec of the path segment to ignore. * @param path the additional path - * @return base plus path with pathspec removed + * @return base plus path with pathspec removed */ public static String relativePath(String base, String pathSpec, @@ -508,7 +508,7 @@ public class PathMap extends HashMap implements Externalizable path = base + URIUtil.SLASH + info; return path; } - + /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ @@ -516,7 +516,7 @@ public class PathMap extends HashMap implements Externalizable { private final Object key; private final Object value; - private String mapped; + private String mapped; private transient String string; Entry(Object key, Object value) @@ -529,7 +529,7 @@ public class PathMap extends HashMap implements Externalizable { return key; } - + public Object getValue() { return value; diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index a08b6edc75d..bdaeaaf0123 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -74,6 +74,11 @@ jetty-server ${project.version} + + org.eclipse.jetty + jetty-client + ${project.version} + javax.servlet servlet-api 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 index b5516bcbf68..ca2614f828d 100644 --- 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 @@ -14,22 +14,23 @@ 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.server.Request; 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 +public class ProxyRule extends PatternRule implements Rule.ApplyURI { private static final Logger _log = Log.getLogger(ProxyRule.class); - protected HttpClient _client; - protected String _hostHeader; + private HttpClient _client; + private String _hostHeader; + private String _proxyTo; - protected HashSet _DontProxyHeaders = new HashSet(); + private HashSet _DontProxyHeaders = new HashSet(); { _DontProxyHeaders.add("proxy-connection"); _DontProxyHeaders.add("connection"); @@ -58,13 +59,18 @@ public class ProxyRule extends Rule } /* ------------------------------------------------------------ */ - protected HttpURI proxyHttpURI(String scheme, String serverName, int serverPort, String uri) throws MalformedURLException + private HttpURI proxyHttpURI(String uri) throws MalformedURLException { - return new HttpURI(scheme + "://" + serverName + ":" + serverPort + uri); + return new HttpURI(_proxyTo + uri); + } + + public void applyURI(Request request, String oldTarget, String newTarget) throws IOException + { + System.out.println("applyURI called"); } @Override - public String matchAndApply(String target, HttpServletRequest req, HttpServletResponse res) throws IOException + protected String apply(String target, HttpServletRequest request, final HttpServletResponse response) throws IOException { synchronized (this) { @@ -81,9 +87,6 @@ public class ProxyRule extends Rule } } - final HttpServletRequest request = (HttpServletRequest)req; - final HttpServletResponse response = (HttpServletResponse)res; - final int debug = _log.isDebugEnabled()?request.hashCode():0; final InputStream in = request.getInputStream(); @@ -93,7 +96,7 @@ public class ProxyRule extends Rule if (request.getQueryString() != null) uri += "?" + request.getQueryString(); - HttpURI url = proxyHttpURI(request.getScheme(),request.getServerName(),request.getServerPort(),uri); + HttpURI url = proxyHttpURI(uri); if (debug != 0) _log.debug(debug + " proxy " + uri + "-->" + url); @@ -106,20 +109,24 @@ public class ProxyRule extends Rule HttpExchange exchange = new HttpExchange() { + @Override protected void onRequestCommitted() throws IOException { } + @Override protected void onRequestComplete() throws IOException { } + @Override protected void onResponseComplete() throws IOException { if (debug != 0) _log.debug(debug + " complete"); } + @Override protected void onResponseContent(Buffer content) throws IOException { if (debug != 0) @@ -127,10 +134,13 @@ public class ProxyRule extends Rule content.writeTo(out); } + @Override protected void onResponseHeaderComplete() throws IOException { } + @SuppressWarnings("deprecation") + @Override protected void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException { if (debug != 0) @@ -142,6 +152,7 @@ public class ProxyRule extends Rule response.setStatus(status); } + @Override protected void onResponseHeader(Buffer name, Buffer value) throws IOException { String s = name.toString().toLowerCase(); @@ -156,6 +167,7 @@ public class ProxyRule extends Rule _log.debug(debug + " " + name + "! " + value); } + @Override protected void onConnectionFailed(Throwable ex) { _log.warn(ex.toString()); @@ -166,6 +178,7 @@ public class ProxyRule extends Rule } } + @Override protected void onException(Throwable ex) { if (ex instanceof EofException) @@ -181,6 +194,7 @@ public class ProxyRule extends Rule } } + @Override protected void onExpire() { if (!response.isCommitted()) @@ -191,7 +205,6 @@ public class ProxyRule extends Rule }; - 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()); @@ -199,6 +212,30 @@ public class ProxyRule extends Rule if (debug != 0) _log.debug(debug + " " + request.getMethod() + " " + url + " " + request.getProtocol()); + boolean hasContent = createHeaders(request,debug,exchange); + + 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); + try + { + exchange.waitForDone(); + } + catch (InterruptedException e) + { + _log.info(e); + } + return target; + } + + private boolean createHeaders(final HttpServletRequest request, final int debug, HttpExchange exchange) + { // check connection header String connectionHdr = request.getHeader("Connection"); if (connectionHdr != null) @@ -265,18 +302,11 @@ public class ProxyRule extends Rule 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; + return hasContent; } + public void setProxyTo(String proxyTo) + { + this._proxyTo = proxyTo; + } } 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 index 9f021a5794f..8a9415853f4 100644 --- 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 @@ -12,40 +12,66 @@ // ======================================================================== package org.eclipse.jetty.rewrite.handler; +import static org.junit.Assert.assertEquals; + import java.io.IOException; -import java.net.URI; import java.net.URLEncoder; -import org.eclipse.jetty.client.Address; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + 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.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertEquals; - -public class ProxyRuleTest extends AbstractRuleTestCase +public class ProxyRuleTest { private ProxyRule _rule; private RewriteHandler _handler; + private Server _proxyServer = new Server(); + private Connector _proxyServerConnector = new SelectChannelConnector(); + private Server _targetServer = new Server(); + private Connector _targetServerConnector= new SelectChannelConnector(); + private HttpClient httpClient = new HttpClient(); @Before public void init() throws Exception { - start(false); - _rule = new ProxyRule(); - + _targetServer.addConnector(_targetServerConnector); + _targetServer.setHandler(new AbstractHandler() + { + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, + ServletException + { + baseRequest.setHandled(true); + response.setStatus(201); + } + }); + _targetServer.start(); + + _rule = new ProxyRule(); + _rule.setPattern("/foo/*"); + _rule.setProxyTo("http://localhost:" + _targetServerConnector.getLocalPort()); _handler = new RewriteHandler(); _handler.setRewriteRequestURI(true); + _handler.setRules(new Rule[] + { _rule }); - _handler.setRules(new Rule[] { _rule } ); + _proxyServer.addConnector(_proxyServerConnector); + _proxyServer.setHandler(_handler); + _proxyServer.start(); - _server.setHandler(_handler); + httpClient.start(); } @After @@ -57,21 +83,30 @@ public class ProxyRuleTest extends AbstractRuleTestCase @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)); + + ContentExchange exchange = new ContentExchange(true); + exchange.setMethod(HttpMethods.GET); + String body = "BODY"; + String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo?body=" + URLEncoder.encode(body,"UTF-8"); + exchange.setURL(url); + + httpClient.send(exchange); + assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone()); + assertEquals(201,exchange.getResponseStatus()); + } + + @Test + public void testProxyNoMatch() throws Exception + { + + ContentExchange exchange = new ContentExchange(true); + exchange.setMethod(HttpMethods.GET); + String body = "BODY"; + String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foobar?body=" + URLEncoder.encode(body,"UTF-8"); + exchange.setURL(url); + + httpClient.send(exchange); + assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone()); + assertEquals(404,exchange.getResponseStatus()); } } From 5e6a9ea78e5030d7dc29de2a1122065f02cb731c Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Mon, 26 Sep 2011 17:14:07 +0200 Subject: [PATCH 4/9] beautified code, added javadoc --- .../jetty/rewrite/handler/ProxyRule.java | 28 ++++--- .../jetty/rewrite/handler/RewriteHandler.java | 73 ++++++++++--------- .../jetty/rewrite/handler/ProxyRuleTest.java | 24 +++++- 3 files changed, 80 insertions(+), 45 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 index ca2614f828d..a913ca67e68 100644 --- 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 @@ -15,6 +15,7 @@ import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.http.HttpHeaderValues; import org.eclipse.jetty.http.HttpHeaders; import org.eclipse.jetty.http.HttpURI; +import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.server.Request; @@ -92,14 +93,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI final InputStream in = request.getInputStream(); final OutputStream out = response.getOutputStream(); - String uri = request.getRequestURI(); - if (request.getQueryString() != null) - uri += "?" + request.getQueryString(); - - HttpURI url = proxyHttpURI(uri); - - if (debug != 0) - _log.debug(debug + " proxy " + uri + "-->" + url); + HttpURI url = createUrl(request,debug); if (url == null) { @@ -221,6 +215,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI * 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(); + exchange.setTimeout(ctimeout); _client.send(exchange); try @@ -229,11 +224,26 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI } catch (InterruptedException e) { - _log.info(e); + _log.info("Exception while waiting for response on proxied request", e); } return target; } + private HttpURI createUrl(HttpServletRequest request, final int debug) throws MalformedURLException + { + String uri = request.getRequestURI(); + if (request.getQueryString() != null) + uri += "?" + request.getQueryString(); + uri = PathMap.pathInfo(_pattern,uri); + if(uri==null) + uri = "/"; + HttpURI url = proxyHttpURI(uri); + + if (debug != 0) + _log.debug(debug + " proxy " + uri + "-->" + url); + return url; + } + private boolean createHeaders(final HttpServletRequest request, final int debug, HttpExchange exchange) { // check connection header diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java index 98b9d0631a2..e563abd72f4 100644 --- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java +++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/RewriteHandler.java @@ -5,11 +5,11 @@ // 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 +// 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. +// You may elect to redistribute this code under either of these licenses. // ======================================================================== package org.eclipse.jetty.rewrite.handler; @@ -19,25 +19,24 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.HandlerWrapper; /* ------------------------------------------------------------ */ /** *

    Rewrite handler is responsible for managing the rules. Its capabilities - * is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule. - * There is also handling for cookies, headers, redirection, setting status or error codes - * whenever the rule finds a match. - * - *

    The rules can be matched by the either: pattern matching of PathMap - * (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set + * is not only limited for URL rewrites such as RewritePatternRule or RewriteRegexRule. + * There is also handling for cookies, headers, redirection, setting status or error codes + * whenever the rule finds a match. + * + *

    The rules can be matched by the either: pattern matching of PathMap + * (eg {@link PatternRule}), regular expressions (eg {@link RegexRule}) or certain conditions set * (eg {@link MsieSslRule} - the requests must be in SSL mode). - * - *

    The rules can be grouped into rule containers (class {@link RuleContainer}), and will only + * + *

    The rules can be grouped into rule containers (class {@link RuleContainer}), and will only * be applied if the request matches the conditions for their container * (e.g., by virtual host name) - * + * *

    The list of predefined rules is: *

      *
    • {@link CookiePatternRule} - adds a new cookie in response.
    • @@ -46,28 +45,36 @@ import org.eclipse.jetty.server.handler.HandlerWrapper; *
    • {@link ResponsePatternRule} - sets the status/error codes.
    • *
    • {@link RewritePatternRule} - rewrites the requested URI.
    • *
    • {@link RewriteRegexRule} - rewrites the requested URI using regular expression for pattern matching.
    • + *
    • {@link ProxyRule} - proxies the requested URI to the host defined in proxyTo.
    • *
    • {@link MsieSslRule} - disables the keep alive on SSL for IE5 and IE6.
    • *
    • {@link LegacyRule} - the old version of rewrite.
    • *
    • {@link ForwardedSchemeHeaderRule} - set the scheme according to the headers present.
    • *
    • {@link VirtualHostRuleContainer} - checks whether the request matches one of a set of virtual host names.
    • *
    * - * + * * Here is a typical jetty.xml configuration would be:
    - * 
    + *
      *   <Set name="handler">
      *     <New id="Handlers" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
      *       <Set name="rules">
      *         <Array type="org.eclipse.jetty.rewrite.handler.Rule">
      *
    - *           <Item> 
    + *           <Item>
      *             <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
      *               <Set name="pattern">/*</Set>
      *               <Set name="replacement">/test</Set>
      *             </New>
      *           </Item>
      *
    - *           <Item> 
    + *           <Item>
    + *             <New id="rewrite" class="org.eclipse.jetty.rewrite.handler.ProxyRule">
    + *               <Set name="pattern">/*</Set>
    + *               <Set name="proxyTo">http://webtide.com:8080</Set>
    + *             </New>
    + *           </Item>
    + *
    + *           <Item>
      *             <New id="response" class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
      *               <Set name="pattern">/session/</Set>
      *               <Set name="code">400</Set>
    @@ -75,7 +82,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
      *             </New>
      *           </Item>
      *
    - *           <Item> 
    + *           <Item>
      *             <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
      *               <Set name="pattern">*.jsp</Set>
      *               <Set name="name">server</Set>
    @@ -83,7 +90,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
      *             </New>
      *           </Item>
      *
    - *           <Item> 
    + *           <Item>
      *             <New id="header" class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
      *               <Set name="pattern">*.jsp</Set>
      *               <Set name="name">title</Set>
    @@ -91,28 +98,28 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
      *             </New>
      *           </Item>
      *
    - *           <Item> 
    + *           <Item>
      *             <New id="redirect" class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
      *               <Set name="pattern">/test/dispatch</Set>
      *               <Set name="location">http://jetty.eclipse.org</Set>
      *             </New>
      *           </Item>
      *
    - *           <Item> 
    + *           <Item>
      *             <New id="regexRewrite" class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
      *               <Set name="regex">/test-jaas/$</Set>
      *               <Set name="replacement">/demo</Set>
      *             </New>
      *           </Item>
    - *           
    - *           <Item> 
    + *
    + *           <Item>
      *             <New id="forwardedHttps" class="org.eclipse.jetty.rewrite.handler.ForwardedSchemeHeaderRule">
      *               <Set name="header">X-Forwarded-Scheme</Set>
      *               <Set name="headerValue">https</Set>
      *               <Set name="scheme">https</Set>
      *             </New>
      *           </Item>
    - *           
    + *
      *           <Item>
      *             <New id="virtualHost" class="org.eclipse.jetty.rewrite.handler.VirtualHostRuleContainer">
      *
    @@ -134,10 +141,10 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
      *                   </New>
      *                 </Arg>
      *               </Call>
    - *    
    + *
      *             </New>
      *           </      Item>
    - * 
    + *
      *         </Array>
      *       </Set>
      *
    @@ -162,13 +169,13 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
      *     </New>
      *   </Set>
      * 
    - * + * */ public class RewriteHandler extends HandlerWrapper { - + private RuleContainer _rules; - + /* ------------------------------------------------------------ */ public RewriteHandler() { @@ -179,7 +186,7 @@ public class RewriteHandler extends HandlerWrapper /** * To enable configuration from jetty.xml on rewriteRequestURI, rewritePathInfo and * originalPathAttribute - * + * * @param legacyRule old style rewrite rule */ @Deprecated @@ -201,7 +208,7 @@ public class RewriteHandler extends HandlerWrapper /* ------------------------------------------------------------ */ /** * Assigns the rules to process. - * @param rules an array of {@link Rule}. + * @param rules an array of {@link Rule}. */ public void setRules(Rule[] rules) { @@ -297,13 +304,13 @@ public class RewriteHandler extends HandlerWrapper public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (isStarted()) - { + { String returned = _rules.matchAndApply(target, request, response); target = (returned == null) ? target : returned; - + if (!baseRequest.isHandled()) super.handle(target, baseRequest, request, response); } } - + } 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 index 8a9415853f4..65a0b4d0377 100644 --- 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 @@ -41,7 +41,7 @@ public class ProxyRuleTest private Server _proxyServer = new Server(); private Connector _proxyServerConnector = new SelectChannelConnector(); private Server _targetServer = new Server(); - private Connector _targetServerConnector= new SelectChannelConnector(); + private Connector _targetServerConnector = new SelectChannelConnector(); private HttpClient httpClient = new HttpClient(); @Before @@ -51,9 +51,11 @@ public class ProxyRuleTest _targetServer.setHandler(new AbstractHandler() { public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, - ServletException + ServletException { baseRequest.setHandled(true); + String responseString = "uri: " + request.getRequestURI() + " some content"; + response.getOutputStream().write(responseString.getBytes()); response.setStatus(201); } }); @@ -92,13 +94,29 @@ public class ProxyRuleTest httpClient.send(exchange); assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone()); + assertEquals("uri: / some content",exchange.getResponseContent()); + assertEquals(201,exchange.getResponseStatus()); + } + + @Test + public void testProxyWithDeeperPath() throws Exception + { + + ContentExchange exchange = new ContentExchange(true); + exchange.setMethod(HttpMethods.GET); + String body = "BODY"; + String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo/bar/foobar?body=" + URLEncoder.encode(body,"UTF-8"); + exchange.setURL(url); + + httpClient.send(exchange); + assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone()); + assertEquals("uri: /bar/foobar some content",exchange.getResponseContent()); assertEquals(201,exchange.getResponseStatus()); } @Test public void testProxyNoMatch() throws Exception { - ContentExchange exchange = new ContentExchange(true); exchange.setMethod(HttpMethods.GET); String body = "BODY"; From e14cc536ee9021a622a163cd5fbb17b6e48d292f Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Mon, 26 Sep 2011 17:48:52 +0200 Subject: [PATCH 5/9] JETTY-1415: Start/Stop Server and Client only once in test, code format --- .../jetty/rewrite/handler/ProxyRule.java | 14 +++---- .../jetty/rewrite/handler/ProxyRuleTest.java | 37 ++++++++++--------- 2 files changed, 27 insertions(+), 24 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 index a913ca67e68..65efebc72a3 100644 --- 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 @@ -18,12 +18,11 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.server.Request; 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 PatternRule implements Rule.ApplyURI +public class ProxyRule extends PatternRule { private static final Logger _log = Log.getLogger(ProxyRule.class); @@ -44,6 +43,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI _DontProxyHeaders.add("upgrade"); } + /* ------------------------------------------------------------ */ public ProxyRule() { _handling = true; @@ -51,6 +51,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI } + /* ------------------------------------------------------------ */ private void initializeClient() throws Exception { _client = new HttpClient(); @@ -65,11 +66,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI return new HttpURI(_proxyTo + uri); } - public void applyURI(Request request, String oldTarget, String newTarget) throws IOException - { - System.out.println("applyURI called"); - } - + /* ------------------------------------------------------------ */ @Override protected String apply(String target, HttpServletRequest request, final HttpServletResponse response) throws IOException { @@ -229,6 +226,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI return target; } + /* ------------------------------------------------------------ */ private HttpURI createUrl(HttpServletRequest request, final int debug) throws MalformedURLException { String uri = request.getRequestURI(); @@ -244,6 +242,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI return url; } + /* ------------------------------------------------------------ */ private boolean createHeaders(final HttpServletRequest request, final int debug, HttpExchange exchange) { // check connection header @@ -315,6 +314,7 @@ public class ProxyRule extends PatternRule implements Rule.ApplyURI return hasContent; } + /* ------------------------------------------------------------ */ public void setProxyTo(String proxyTo) { this._proxyTo = proxyTo; 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 index 65a0b4d0377..d4c90bee069 100644 --- 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 @@ -30,22 +30,22 @@ import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.junit.After; -import org.junit.Before; +import org.junit.AfterClass; +import org.junit.BeforeClass; import org.junit.Test; public class ProxyRuleTest { - private ProxyRule _rule; - private RewriteHandler _handler; - private Server _proxyServer = new Server(); - private Connector _proxyServerConnector = new SelectChannelConnector(); - private Server _targetServer = new Server(); - private Connector _targetServerConnector = new SelectChannelConnector(); - private HttpClient httpClient = new HttpClient(); + private static ProxyRule _rule; + private static RewriteHandler _handler; + private static Server _proxyServer = new Server(); + private static Connector _proxyServerConnector = new SelectChannelConnector(); + private static Server _targetServer = new Server(); + private static Connector _targetServerConnector = new SelectChannelConnector(); + private static HttpClient _httpClient = new HttpClient(); - @Before - public void init() throws Exception + @BeforeClass + public static void setupOnce() throws Exception { _targetServer.addConnector(_targetServerConnector); _targetServer.setHandler(new AbstractHandler() @@ -73,12 +73,15 @@ public class ProxyRuleTest _proxyServer.setHandler(_handler); _proxyServer.start(); - httpClient.start(); + _httpClient.start(); } - @After - public void destroy() + @AfterClass + public static void destroy() throws Exception { + _httpClient.stop(); + _proxyServer.stop(); + _targetServer.stop(); _rule = null; } @@ -92,7 +95,7 @@ public class ProxyRuleTest String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo?body=" + URLEncoder.encode(body,"UTF-8"); exchange.setURL(url); - httpClient.send(exchange); + _httpClient.send(exchange); assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone()); assertEquals("uri: / some content",exchange.getResponseContent()); assertEquals(201,exchange.getResponseStatus()); @@ -108,7 +111,7 @@ public class ProxyRuleTest String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foo/bar/foobar?body=" + URLEncoder.encode(body,"UTF-8"); exchange.setURL(url); - httpClient.send(exchange); + _httpClient.send(exchange); assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone()); assertEquals("uri: /bar/foobar some content",exchange.getResponseContent()); assertEquals(201,exchange.getResponseStatus()); @@ -123,7 +126,7 @@ public class ProxyRuleTest String url = "http://localhost:" + _proxyServerConnector.getLocalPort() + "/foobar?body=" + URLEncoder.encode(body,"UTF-8"); exchange.setURL(url); - httpClient.send(exchange); + _httpClient.send(exchange); assertEquals(HttpExchange.STATUS_COMPLETED,exchange.waitForDone()); assertEquals(404,exchange.getResponseStatus()); } From bee0a6e7774979b3a3bd82e64d27c49551675885 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Mon, 26 Sep 2011 17:22:08 -0500 Subject: [PATCH 6/9] [Bug 358925] adjust some code and add license block --- .../jetty/rewrite/handler/ProxyRule.java | 40 +++++++++++++++++-- .../jetty/rewrite/handler/ProxyRuleTest.java | 31 +++++++------- 2 files changed, 51 insertions(+), 20 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 index 65efebc72a3..1eef5bc4470 100644 --- 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 @@ -1,5 +1,18 @@ package org.eclipse.jetty.rewrite.handler; +//======================================================================== +//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. +//======================================================================== + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -48,7 +61,6 @@ public class ProxyRule extends PatternRule { _handling = true; _terminating = true; - } /* ------------------------------------------------------------ */ @@ -201,20 +213,25 @@ public class ProxyRule extends PatternRule exchange.setVersion(request.getProtocol()); if (debug != 0) + { _log.debug(debug + " " + request.getMethod() + " " + url + " " + request.getProtocol()); - + } + boolean hasContent = createHeaders(request,debug,exchange); 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 + * we need to set the timeout on the exchange to take into account the timeout of the HttpClient and the HttpExchange */ long ctimeout = (_client.getTimeout() > exchange.getTimeout())?_client.getTimeout():exchange.getTimeout(); exchange.setTimeout(ctimeout); _client.send(exchange); + try { exchange.waitForDone(); @@ -230,15 +247,26 @@ public class ProxyRule extends PatternRule private HttpURI createUrl(HttpServletRequest request, final int debug) throws MalformedURLException { String uri = request.getRequestURI(); + if (request.getQueryString() != null) + { uri += "?" + request.getQueryString(); + } + uri = PathMap.pathInfo(_pattern,uri); + if(uri==null) + { uri = "/"; + } + HttpURI url = proxyHttpURI(uri); if (debug != 0) + { _log.debug(debug + " proxy " + uri + "-->" + url); + } + return url; } @@ -251,12 +279,16 @@ public class ProxyRule extends PatternRule { 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; 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 index d4c90bee069..9cb9def596a 100644 --- 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 @@ -1,17 +1,18 @@ -// ======================================================================== -// 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; +//======================================================================== +//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. +//======================================================================== + import static org.junit.Assert.assertEquals; import java.io.IOException; @@ -50,8 +51,7 @@ public class ProxyRuleTest _targetServer.addConnector(_targetServerConnector); _targetServer.setHandler(new AbstractHandler() { - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, - ServletException + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { baseRequest.setHandled(true); String responseString = "uri: " + request.getRequestURI() + " some content"; @@ -66,8 +66,7 @@ public class ProxyRuleTest _rule.setProxyTo("http://localhost:" + _targetServerConnector.getLocalPort()); _handler = new RewriteHandler(); _handler.setRewriteRequestURI(true); - _handler.setRules(new Rule[] - { _rule }); + _handler.setRules(new Rule[] { _rule }); _proxyServer.addConnector(_proxyServerConnector); _proxyServer.setHandler(_handler); From 7bc092bf8bcece75d8ec1c1bfef0c4032dc53898 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Mon, 26 Sep 2011 17:47:03 -0500 Subject: [PATCH 7/9] [Bug 358925] add common jetty-client proxy configuration setttings --- .../jetty/rewrite/handler/ProxyRule.java | 129 +++++++++++++++++- 1 file changed, 127 insertions(+), 2 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 index 1eef5bc4470..be6d8ad0f5e 100644 --- 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 @@ -35,6 +35,10 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; +/** + * This rule allows the user to configure a particular rewrite rule that will proxy out + * to a configured location. This rule uses the jetty http client. + */ public class ProxyRule extends PatternRule { private static final Logger _log = Log.getLogger(ProxyRule.class); @@ -42,6 +46,16 @@ public class ProxyRule extends PatternRule private HttpClient _client; private String _hostHeader; private String _proxyTo; + + private int _connectorType = 2; + private String _maxThreads; + private String _maxConnections; + private String _timeout; + private String _idleTimeout; + private String _requestHeaderSize; + private String _requestBufferSize; + private String _responseHeaderSize; + private String _responseBufferSize; private HashSet _DontProxyHeaders = new HashSet(); { @@ -67,8 +81,52 @@ public class ProxyRule extends PatternRule private void initializeClient() throws Exception { _client = new HttpClient(); - _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); - _client.setThreadPool(new QueuedThreadPool()); + _client.setConnectorType(_connectorType); + + if ( _maxThreads != null ) + { + _client.setThreadPool(new QueuedThreadPool(Integer.parseInt(_maxThreads))); + } + else + { + _client.setThreadPool(new QueuedThreadPool()); + } + + if ( _maxConnections != null ) + { + _client.setMaxConnectionsPerAddress(Integer.parseInt(_maxConnections)); + } + + if ( _timeout != null ) + { + _client.setTimeout(Long.parseLong(_timeout)); + } + + if ( _idleTimeout != null ) + { + _client.setIdleTimeout(Long.parseLong(_idleTimeout)); + } + + if ( _requestBufferSize != null ) + { + _client.setRequestBufferSize(Integer.parseInt(_requestBufferSize)); + } + + if ( _requestHeaderSize != null ) + { + _client.setRequestHeaderSize(Integer.parseInt(_requestHeaderSize)); + } + + if ( _responseBufferSize != null ) + { + _client.setResponseBufferSize(Integer.parseInt(_responseBufferSize)); + } + + if ( _responseHeaderSize != null ) + { + _client.setResponseHeaderSize(Integer.parseInt(_responseHeaderSize)); + } + _client.start(); } @@ -351,4 +409,71 @@ public class ProxyRule extends PatternRule { this._proxyTo = proxyTo; } + + /* ------------------------------------------------------------ */ + public void setMaxThreads(String maxThreads) + { + this._maxThreads = maxThreads; + } + + /* ------------------------------------------------------------ */ + public void setMaxConnections(String maxConnections) + { + _maxConnections = maxConnections; + } + + /* ------------------------------------------------------------ */ + public void setTimeout(String timeout) + { + _timeout = timeout; + } + + /* ------------------------------------------------------------ */ + public void setIdleTimeout(String idleTimeout) + { + _idleTimeout = idleTimeout; + } + + /* ------------------------------------------------------------ */ + public void setRequestHeaderSize(String requestHeaderSize) + { + _requestHeaderSize = requestHeaderSize; + } + + /* ------------------------------------------------------------ */ + public void setRequestBufferSize(String requestBufferSize) + { + _requestBufferSize = requestBufferSize; + } + + /* ------------------------------------------------------------ */ + public void setResponseHeaderSize(String responseHeaderSize) + { + _responseHeaderSize = responseHeaderSize; + } + + /* ------------------------------------------------------------ */ + public void setResponseBufferSize(String responseBufferSize) + { + _responseBufferSize = responseBufferSize; + } + + /* ------------------------------------------------------------ */ + public void addDontProxyHeaders(String dontProxyHeader) + { + _DontProxyHeaders.add(dontProxyHeader); + } + + /* ------------------------------------------------------------ */ + /** + * CONNECTOR_SOCKET = 0; + * CONNECTOR_SELECT_CHANNEL = 2; (default) + * + * @param connectorType + */ + public void setConnectorType( int connectorType ) + { + _connectorType = connectorType; + } + } From ba0ee9f216df2341f18d5c801f6069b48e1dbcb3 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Mon, 26 Sep 2011 17:50:12 -0500 Subject: [PATCH 8/9] [Bug 358925] bit more javadoc on usage --- .../java/org/eclipse/jetty/rewrite/handler/ProxyRule.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 index be6d8ad0f5e..99c6877e52b 100644 --- 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 @@ -38,6 +38,14 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool; /** * This rule allows the user to configure a particular rewrite rule that will proxy out * to a configured location. This rule uses the jetty http client. + * + * Rule rule = new ProxyRule(); + * rule.setPattern("/foo/*"); + * rule.setProxyTo("http://url.com"); + * + * see api for other configuration options which influence the configuration of the jetty + * client instance + * */ public class ProxyRule extends PatternRule { From 90af3cc35974538df01684a2af928bcb25190cc2 Mon Sep 17 00:00:00 2001 From: Jesse McConnell Date: Mon, 26 Sep 2011 20:57:58 -0500 Subject: [PATCH 9/9] update jetty-version-maven-plugin version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9bbf848c240..92439b310e3 100644 --- a/pom.xml +++ b/pom.xml @@ -185,7 +185,7 @@ org.eclipse.jetty.toolchain jetty-version-maven-plugin - 1.0.3 + 1.0.6 org.apache.maven.plugins