From edc8bae5562ef0c8c6e5599cf6ac434315efe89e Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 17 Jul 2015 16:28:48 +1000 Subject: [PATCH] 472781 - GzipHandler isMimeTypeGzipable() bad logic Added utility classes: IncludeExclude - handles standard include exclude set RegexSet - A set of regular expressions that have a combined compiled pattern PathMap.PathSet - A set of standard path mappings --- .../java/org/eclipse/jetty/http/PathMap.java | 11 ++ .../server/handler/gzip/GzipHandler.java | 186 +++++++++--------- .../server/handler/gzip/GzipDefaultTest.java | 15 +- .../eclipse/jetty/util/IncludeExclude.java | 72 ++++--- .../java/org/eclipse/jetty/util/RegexSet.java | 106 ++++++++++ .../jetty/util/IncludeExcludeTest.java | 153 ++++++++++++++ .../org/eclipse/jetty/util/RegexSetTest.java | 86 ++++++++ 7 files changed, 509 insertions(+), 120 deletions(-) create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java create mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java create mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/RegexSetTest.java 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 c0a8aa7e217..bb30c3b4d15 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 @@ -26,8 +26,10 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; +import java.util.function.BiFunction; import org.eclipse.jetty.util.ArrayTernaryTrie; +import org.eclipse.jetty.util.RegexSet; import org.eclipse.jetty.util.Trie; import org.eclipse.jetty.util.URIUtil; @@ -592,6 +594,7 @@ public class PathMap extends HashMap public static class PathSet extends AbstractSet { + public static final BiFunction MATCHER=(s,e)->{return s.containsMatch(e);}; private final PathMap _map = new PathMap<>(); @Override @@ -623,5 +626,13 @@ public class PathMap extends HashMap { return _map.containsKey(o); } + + + public boolean containsMatch(String s) + { + return _map.containsMatch(s); + } + + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java index f53eafdfa48..0ce72da45b0 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java @@ -20,9 +20,7 @@ package org.eclipse.jetty.server.handler.gzip; import java.io.File; import java.io.IOException; -import java.util.HashSet; import java.util.Set; -import java.util.regex.Pattern; import java.util.zip.Deflater; import javax.servlet.ServletContext; @@ -39,8 +37,8 @@ import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.server.HttpOutput; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.HandlerWrapper; -import org.eclipse.jetty.util.ConcurrentHashSet; import org.eclipse.jetty.util.IncludeExclude; +import org.eclipse.jetty.util.RegexSet; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -73,15 +71,12 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory // non-static, as other GzipHandler instances may have different configurations private final ThreadLocal _deflater = new ThreadLocal(); - private final Set _excludedAgentPatterns=new HashSet<>(); + private final IncludeExclude _agentPatterns=new IncludeExclude<>(RegexSet.class,RegexSet.MATCHER); private final IncludeExclude _methods = new IncludeExclude<>(); - private final IncludeExclude _paths = new IncludeExclude<>(PathMap.PathSet.class); + private final IncludeExclude _paths = new IncludeExclude<>(PathMap.PathSet.class,PathMap.PathSet.MATCHER); private final IncludeExclude _mimeTypes = new IncludeExclude<>(); private HttpField _vary; - - private final Set _uaCache = new ConcurrentHashSet<>(); - private int _uaCacheSize = 1024; /* ------------------------------------------------------------ */ /** @@ -110,7 +105,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory _mimeTypes.exclude("application/x-rar-compressed"); LOG.debug("{} mime types {}",this,_mimeTypes); - _excludedAgentPatterns.add(Pattern.compile(".*MSIE 6.0.*")); + _agentPatterns.exclude(".*MSIE 6.0.*"); } /* ------------------------------------------------------------ */ @@ -119,8 +114,17 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory */ public void addExcludedAgentPatterns(String... patterns) { - for (String s : patterns) - _excludedAgentPatterns.add(Pattern.compile(s)); + _agentPatterns.exclude(patterns); + } + + /* ------------------------------------------------------------ */ + /** + * @param methods The methods to exclude in compression + */ + public void addExcludedMethods(String... methods) + { + for (String m : methods) + _methods.exclude(m); } /* ------------------------------------------------------------ */ @@ -144,6 +148,15 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory _paths.exclude(pathspecs); } + /* ------------------------------------------------------------ */ + /** + * @param patterns Regular expressions matching user agents to exclude + */ + public void addIncludedAgentPatterns(String... patterns) + { + _agentPatterns.include(patterns); + } + /* ------------------------------------------------------------ */ /** * @param methods The methods to include in compression @@ -153,16 +166,6 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory for (String m : methods) _methods.include(m); } - - /* ------------------------------------------------------------ */ - /** - * @param methods The methods to exclude in compression - */ - public void addExcludedMethods(String... methods) - { - for (String m : methods) - _methods.exclude(m); - } /* ------------------------------------------------------------ */ /** @@ -187,6 +190,14 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory _paths.include(pathspecs); } + /* ------------------------------------------------------------ */ + @Override + protected void doStart() throws Exception + { + _vary=(_agentPatterns.size()>0)?GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING_USER_AGENT:GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING; + super.doStart(); + } + /* ------------------------------------------------------------ */ public boolean getCheckGzExists() { @@ -198,13 +209,13 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory { return _compressionLevel; } - + /* ------------------------------------------------------------ */ @Override public Deflater getDeflater(Request request, long content_length) { String ua = request.getHttpFields().get(HttpHeader.USER_AGENT); - if (ua!=null && isExcludedAgent(ua)) + if (ua!=null && !isAgentGzipable(ua)) { LOG.debug("{} excluded user agent {}",this,request); return null; @@ -247,43 +258,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory /* ------------------------------------------------------------ */ public String[] getExcludedAgentPatterns() { - Pattern[] ps = _excludedAgentPatterns.toArray(new Pattern[_excludedAgentPatterns.size()]); - String[] s = new String[ps.length]; - - int i=0; - for (Pattern p: ps) - s[i++]=p.toString(); - return s; - } - - /* ------------------------------------------------------------ */ - public String[] getExcludedMimeTypes() - { - Set excluded=_mimeTypes.getExcluded(); + Set excluded=_agentPatterns.getExcluded(); return excluded.toArray(new String[excluded.size()]); } - /* ------------------------------------------------------------ */ - public String[] getIncludedMimeTypes() - { - Set includes=_mimeTypes.getIncluded(); - return includes.toArray(new String[includes.size()]); - } - - /* ------------------------------------------------------------ */ - public String[] getExcludedPaths() - { - Set excluded=_paths.getExcluded(); - return excluded.toArray(new String[excluded.size()]); - } - - /* ------------------------------------------------------------ */ - public String[] getIncludedPaths() - { - Set includes=_paths.getIncluded(); - return includes.toArray(new String[includes.size()]); - } - /* ------------------------------------------------------------ */ public String[] getExcludedMethods() { @@ -291,6 +269,28 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory return excluded.toArray(new String[excluded.size()]); } + /* ------------------------------------------------------------ */ + public String[] getExcludedMimeTypes() + { + Set excluded=_mimeTypes.getExcluded(); + return excluded.toArray(new String[excluded.size()]); + } + + /* ------------------------------------------------------------ */ + public String[] getExcludedPaths() + { + Set excluded=_paths.getExcluded(); + return excluded.toArray(new String[excluded.size()]); + } + + + /* ------------------------------------------------------------ */ + public String[] getIncludedAgentPatterns() + { + Set includes=_agentPatterns.getIncluded(); + return includes.toArray(new String[includes.size()]); + } + /* ------------------------------------------------------------ */ public String[] getIncludedMethods() { @@ -298,6 +298,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory return includes.toArray(new String[includes.size()]); } + /* ------------------------------------------------------------ */ + public String[] getIncludedMimeTypes() + { + Set includes=_mimeTypes.getIncluded(); + return includes.toArray(new String[includes.size()]); + } + + /* ------------------------------------------------------------ */ + public String[] getIncludedPaths() + { + Set includes=_paths.getIncluded(); + return includes.toArray(new String[includes.size()]); + } + /* ------------------------------------------------------------ */ @Deprecated public String[] getMethods() @@ -316,14 +330,6 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory return _minGzipSize; } - /* ------------------------------------------------------------ */ - @Override - protected void doStart() throws Exception - { - _vary=(_excludedAgentPatterns.size()>0)?GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING_USER_AGENT:GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING; - super.doStart(); - } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) @@ -350,7 +356,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory } // If not a supported method - no Vary because no matter what client, this URI is always excluded - if (!_methods.contains(baseRequest.getMethod())) + if (!_methods.matches(baseRequest.getMethod())) { LOG.debug("{} excluded by method {}",this,request); _handler.handle(target,baseRequest, request, response); @@ -418,37 +424,19 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory * @param ua the user agent * @return boolean true if excluded */ - protected boolean isExcludedAgent(String ua) + protected boolean isAgentGzipable(String ua) { if (ua == null) return false; - if (_excludedAgentPatterns != null) - { - - if (_uaCache.contains(ua)) - return true; - - for (Pattern pattern : _excludedAgentPatterns) - { - if (pattern.matcher(ua).matches()) - { - if (_uaCache.size()>_uaCacheSize) - _uaCache.clear(); - _uaCache.add(ua); - return true; - } - } - } - - return false; + return _agentPatterns.matches(ua); } /* ------------------------------------------------------------ */ @Override public boolean isMimeTypeGzipable(String mimetype) { - return _mimeTypes.contains(mimetype); + return _mimeTypes.matches(mimetype); } /* ------------------------------------------------------------ */ @@ -464,7 +452,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory if (requestURI == null) return true; - return _paths.contains(requestURI); + return _paths.matches(requestURI); } /* ------------------------------------------------------------ */ @@ -502,10 +490,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory */ public void setExcludedAgentPatterns(String... patterns) { - _excludedAgentPatterns.clear(); + _agentPatterns.getExcluded().clear(); addExcludedAgentPatterns(patterns); } + /* ------------------------------------------------------------ */ + /** + * @param method to exclude + */ + public void setExcludedMethods(String... method) + { + _methods.getExcluded().clear(); + _methods.exclude(method); + } + /* ------------------------------------------------------------ */ /** * Set the mime types. @@ -531,14 +529,14 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory /* ------------------------------------------------------------ */ /** - * @param method to exclude + * @param patterns Regular expressions matching user agents to include */ - public void setExcludedMethods(String... method) + public void setIncludedAgentPatterns(String... patterns) { - _methods.getExcluded().clear(); - _methods.exclude(method); + _agentPatterns.getIncluded().clear(); + addIncludedAgentPatterns(patterns); } - + /* ------------------------------------------------------------ */ /** * @param methods The methods to include in compression diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultTest.java index c926bd4c296..96dbf03cbce 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/server/handler/gzip/GzipDefaultTest.java @@ -674,12 +674,13 @@ public class GzipDefaultTest GzipTester tester = new GzipTester(testingdir,compressionType); // Configure Gzip Handler - tester.getGzipHandler().setExcludedPaths("*.txt"); - tester.getGzipHandler().setIncludedPaths("/file.txt"); + tester.getGzipHandler().setExcludedPaths("/bad.txt"); + tester.getGzipHandler().setIncludedPaths("*.txt"); // Prepare server file int filesize = tester.getOutputBufferSize() * 4; tester.prepareServerFile("file.txt",filesize); + tester.prepareServerFile("bad.txt",filesize); // Set content servlet tester.setContentServlet(DefaultServlet.class); @@ -693,6 +694,16 @@ public class GzipDefaultTest { tester.stop(); } + + try + { + tester.start(); + assertIsResponseNotGzipCompressed(tester,"GET","bad.txt",filesize,HttpStatus.OK_200); + } + finally + { + tester.stop(); + } } public HttpTester.Response assertIsResponseNotGzipCompressed(GzipTester tester, String method, String filename, int expectedFilesize, int status) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java index 36354a6bd43..fd20040cab8 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IncludeExclude.java @@ -20,78 +20,97 @@ package org.eclipse.jetty.util; import java.util.HashSet; import java.util.Set; +import java.util.function.BiFunction; /** Utility class to maintain a set of inclusions and exclusions. + *

Maintains a set of included and excluded elements. The method {@link #matches(Object)} + * will return true IFF the passed object is not in the excluded set AND ( either the + * included set is empty OR the object is in the included set) *

The type of the underlying {@link Set} used may be passed into the * constructor, so special sets like Servlet PathMap may be used. - * @param + *

+ * @param The type of element */ -public class IncludeExclude +public class IncludeExclude { - private final Set _includes; - private final Set _excludes; + private final Set _includes; + private final Set _excludes; + private final BiFunction,ITEM, Boolean> _matcher; + /** + * Default constructor over {@link HashSet} + */ public IncludeExclude() { - _includes = new HashSet<>(); - _excludes = new HashSet<>(); + this(HashSet.class,null); } - public IncludeExclude(Class> setClass) + /** + * Construct an IncludeExclude + * @param setClass The type of {@link Set} to using internally + * @param matcher A function to test if a passed ITEM is matched by the passed SET, or null to use {@link Set#contains(Object)} + */ + public > IncludeExclude(Class setClass, BiFunction matcher) { try { _includes = setClass.newInstance(); _excludes = setClass.newInstance(); + _matcher = (BiFunction,ITEM, Boolean>)matcher; } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } - - public IncludeExclude(Set includes, Set excludes) - { - _includes = includes; - _excludes = excludes; - } - public void include(E element) + public void include(ITEM element) { _includes.add(element); } - public void include(E... element) + public void include(ITEM... element) { - for (E e: element) + for (ITEM e: element) _includes.add(e); } - public void exclude(E element) + public void exclude(ITEM element) { _excludes.add(element); } - public void exclude(E... element) + public void exclude(ITEM... element) { - for (E e: element) + for (ITEM e: element) _excludes.add(e); } - public boolean contains(E e) + public boolean matches(ITEM e) { - if (_includes.size()>0 && !_includes.contains(e)) + if (_matcher==null) + { + if (_includes.size()>0 && !_includes.contains(e)) + return false; + return !_excludes.contains(e); + } + if (_includes.size()>0 && !_matcher.apply(_includes,e)) return false; - return !_excludes.contains(e); + return !_matcher.apply(_excludes,e); } - public Set getIncluded() + public int size() + { + return _includes.size()+_excludes.size(); + } + + public Set getIncluded() { return _includes; } - public Set getExcluded() + public Set getExcluded() { return _excludes; } @@ -102,4 +121,9 @@ public class IncludeExclude _excludes.clear(); } + @Override + public String toString() + { + return String.format("%s@%x{i=%s,e=%s,m=%s}",this.getClass().getSimpleName(),hashCode(),_includes,_excludes,_matcher); + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java b/jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java new file mode 100644 index 00000000000..ff72b039a43 --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/RegexSet.java @@ -0,0 +1,106 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 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.util; + +import java.util.AbstractSet; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.regex.Pattern; + + +/** + * A Set of Regular expressions strings. + *

+ * Provides the efficient {@link #matches(String)} method to check for a match against all the combined Regex's + */ +public class RegexSet extends AbstractSet +{ + public static final BiFunction MATCHER=(rs,p)->{return rs.matches(p);}; + private final Set _patterns=new HashSet(); + private final Set _unmodifiable=Collections.unmodifiableSet(_patterns); + private Pattern _pattern; + + @Override + public Iterator iterator() + { + return _unmodifiable.iterator(); + } + + @Override + public int size() + { + return _patterns.size(); + } + + @Override + public boolean add(String pattern) + { + boolean added = _patterns.add(pattern); + if (added) + updatePattern(); + return added; + } + + @Override + public boolean remove(Object pattern) + { + boolean removed = _patterns.remove(pattern); + + if (removed) + updatePattern(); + return removed; + } + + @Override + public boolean isEmpty() + { + return _patterns.isEmpty(); + } + + @Override + public void clear() + { + _patterns.clear(); + _pattern=null; + } + + private void updatePattern() + { + StringBuilder builder = new StringBuilder(); + builder.append("^("); + for (String pattern: _patterns) + { + if (builder.length()>2) + builder.append('|'); + builder.append('('); + builder.append(pattern); + builder.append(')'); + } + builder.append(")$"); + _pattern = Pattern.compile(builder.toString()); + } + + public boolean matches(String s) + { + return _pattern!=null && _pattern.matcher(s).matches(); + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java new file mode 100644 index 00000000000..8da30fdb38a --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IncludeExcludeTest.java @@ -0,0 +1,153 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 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.util; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class IncludeExcludeTest +{ + @Test + public void testEmpty() + { + IncludeExclude ie = new IncludeExclude<>(); + + assertEquals(0,ie.size()); + assertEquals(true,ie.matches("foo")); + } + + @Test + public void testIncludeOnly() + { + IncludeExclude ie = new IncludeExclude<>(); + ie.include("foo"); + ie.include("bar"); + + assertEquals(2,ie.size()); + assertEquals(false,ie.matches("")); + assertEquals(true,ie.matches("foo")); + assertEquals(true,ie.matches("bar")); + assertEquals(false,ie.matches("foobar")); + } + + @Test + public void testExcludeOnly() + { + IncludeExclude ie = new IncludeExclude<>(); + ie.exclude("foo"); + ie.exclude("bar"); + + assertEquals(2,ie.size()); + + assertEquals(false,ie.matches("foo")); + assertEquals(false,ie.matches("bar")); + assertEquals(true,ie.matches("")); + assertEquals(true,ie.matches("foobar")); + assertEquals(true,ie.matches("wibble")); + } + + @Test + public void testIncludeExclude() + { + IncludeExclude ie = new IncludeExclude<>(); + ie.include("foo"); + ie.include("bar"); + ie.exclude("bar"); + ie.exclude("xxx"); + + assertEquals(4,ie.size()); + + assertEquals(true,ie.matches("foo")); + assertEquals(false,ie.matches("bar")); + assertEquals(false,ie.matches("")); + assertEquals(false,ie.matches("foobar")); + assertEquals(false,ie.matches("xxx")); + } + + + + @Test + public void testEmptyRegex() + { + IncludeExclude ie = new IncludeExclude<>(RegexSet.class,RegexSet.MATCHER); + + assertEquals(0,ie.size()); + assertEquals(true,ie.matches("foo")); + } + + @Test + public void testIncludeRegex() + { + IncludeExclude ie = new IncludeExclude<>(RegexSet.class,RegexSet.MATCHER); + ie.include("f.."); + ie.include("b((ar)|(oo))"); + + assertEquals(2,ie.size()); + assertEquals(false,ie.matches("")); + assertEquals(true,ie.matches("foo")); + assertEquals(true,ie.matches("far")); + assertEquals(true,ie.matches("bar")); + assertEquals(true,ie.matches("boo")); + assertEquals(false,ie.matches("foobar")); + assertEquals(false,ie.matches("xxx")); + } + + @Test + public void testExcludeRegex() + { + IncludeExclude ie = new IncludeExclude<>(RegexSet.class,RegexSet.MATCHER); + ie.exclude("f.."); + ie.exclude("b((ar)|(oo))"); + + assertEquals(2,ie.size()); + + assertEquals(false,ie.matches("foo")); + assertEquals(false,ie.matches("far")); + assertEquals(false,ie.matches("bar")); + assertEquals(false,ie.matches("boo")); + assertEquals(true,ie.matches("")); + assertEquals(true,ie.matches("foobar")); + assertEquals(true,ie.matches("xxx")); + } + + @Test + public void testIncludeExcludeRegex() + { + IncludeExclude ie = new IncludeExclude<>(RegexSet.class,RegexSet.MATCHER); + ie.include(".*[aeiou].*"); + ie.include("[AEIOU].*"); + ie.exclude("f.."); + ie.exclude("b((ar)|(oo))"); + + assertEquals(4,ie.size()); + assertEquals(false,ie.matches("foo")); + assertEquals(false,ie.matches("far")); + assertEquals(false,ie.matches("bar")); + assertEquals(false,ie.matches("boo")); + assertEquals(false,ie.matches("")); + assertEquals(false,ie.matches("xxx")); + + assertEquals(true,ie.matches("foobar")); + assertEquals(true,ie.matches("Ant")); + + } + + +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/RegexSetTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/RegexSetTest.java new file mode 100644 index 00000000000..f80c2eda5ca --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/RegexSetTest.java @@ -0,0 +1,86 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 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.util; + +import org.junit.Test; + +import org.junit.Assert; + +public class RegexSetTest +{ + + @Test + public void testEmpty() + { + RegexSet set = new RegexSet(); + + Assert.assertEquals(false,set.contains("foo")); + Assert.assertEquals(false,set.matches("foo")); + Assert.assertEquals(false,set.matches("")); + + } + + @Test + public void testSimple() + { + RegexSet set = new RegexSet(); + set.add("foo.*"); + + Assert.assertEquals(true,set.contains("foo.*")); + Assert.assertEquals(true,set.matches("foo")); + Assert.assertEquals(true,set.matches("foobar")); + Assert.assertEquals(false,set.matches("bar")); + Assert.assertEquals(false,set.matches("")); + + } + + @Test + public void testSimpleTerminated() + { + RegexSet set = new RegexSet(); + set.add("^foo.*$"); + + Assert.assertEquals(true,set.contains("^foo.*$")); + Assert.assertEquals(true,set.matches("foo")); + Assert.assertEquals(true,set.matches("foobar")); + Assert.assertEquals(false,set.matches("bar")); + Assert.assertEquals(false,set.matches("")); + } + + @Test + public void testCombined() + { + RegexSet set = new RegexSet(); + set.add("^foo.*$"); + set.add("bar"); + set.add("[a-z][0-9][a-z][0-9]"); + + Assert.assertEquals(true,set.contains("^foo.*$")); + Assert.assertEquals(true,set.matches("foo")); + Assert.assertEquals(true,set.matches("foobar")); + Assert.assertEquals(true,set.matches("bar")); + Assert.assertEquals(true,set.matches("c3p0")); + Assert.assertEquals(true,set.matches("r2d2")); + + Assert.assertEquals(false,set.matches("wibble")); + Assert.assertEquals(false,set.matches("barfoo")); + Assert.assertEquals(false,set.matches("2b!b")); + Assert.assertEquals(false,set.matches("")); + } +}