Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Gorovoy2010-05-21 15:59:18 -0400
committerMichael Gorovoy2010-05-21 15:59:18 -0400
commit222e11ded77ef3089e91fce6673ff9e357c6d93b (patch)
treed0392f08ffd670bcd44355e09ae33a2f85bf47b1
parente272654e9458591bc84a18477cb7c09ed297df9a (diff)
downloadorg.eclipse.jetty.project-222e11ded77ef3089e91fce6673ff9e357c6d93b.tar.gz
org.eclipse.jetty.project-222e11ded77ef3089e91fce6673ff9e357c6d93b.tar.xz
org.eclipse.jetty.project-222e11ded77ef3089e91fce6673ff9e357c6d93b.zip
313278 Implement octet ranges in IPAccessHandler
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1834 7e9141cc-0065-0410-87d8-b60c137991c4
-rw-r--r--VERSION.txt1
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java345
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java392
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java362
-rw-r--r--jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java172
5 files changed, 1185 insertions, 87 deletions
diff --git a/VERSION.txt b/VERSION.txt
index 910cf5b822..ca678aceb8 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -2,6 +2,7 @@ jetty-SNAPSHOT
+ 308866 Update test suite to JUnit4 - Module jetty-util
+ 312948 Recycle SSL crypto buffers
+ 313196 randomly allocate ports for session test.
+ + 313278 Implement octet ranges in IPAccessHandler
+ 313336 secure websockets
+ Update links to jetty website and wiki on test webapp
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java
index 6ed3d15fdd..f77efc65c4 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IPAccessHandler.java
@@ -14,10 +14,9 @@
package org.eclipse.jetty.server.handler;
import java.io.IOException;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -28,78 +27,150 @@ import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.util.IPAddressMap;
+import org.eclipse.jetty.util.log.Log;
/**
* IP Access Handler
* <p>
- * Control access to the wrapped handler by the real remote IP.
- * The real IP of the connection is used (not the IP reported in the forwarded for headers),
- * as this cannot be as easily forged.
+ * Controls access to the wrapped handler by the real remote IP. Control is provided
+ * by white/black lists that include both internet addresses and URIs. This handler
+ * uses the real internet address of the connection, not one reported in the forwarded
+ * for headers, as this cannot be as easily forged.
* <p>
- * Control is provided by white/black lists of both internet addresses and URIs.
- * Internet addresses may be absolute (eg 10.1.2.3) or a prefix pattern (eg 10.1.3. ).
- * URI patterns follow the servlet specification for simple prefix and suffix wild cards.
+ * Typically, the black/white lists will be used in one of three modes:
+ * <ul>
+ * <li>Blocking a few specific IPs/URLs by specifying several black list entries.
+ * <li>Allowing only some specific IPs/URLs by specifying several white lists entries.
+ * <li>Allowing a general range of IPs/URLs by specifying several general white list
+ * entries, that are then further refined by several specific black list exceptions
+ * </ul>
+ * <p>
+ * An empty white list is treated as match all. If there is at least one entry in
+ * the white list, then a request must match a white list entry. Black list entries
+ * are always applied, so that even if an entry matches the white list, a black list
+ * entry will override it.
* <p>
- * An empty white list is treated as match all. If there is at least one entry in the
- * white list, then a request must match a white list entry. Black list entries are always
- * appied, so that even if an entry matches the white list, a black list entry will override.
+ * Internet addresses may be specified as absolute address or as a combination of
+ * four octet wildcard specifications (a.b.c.d) that are defined as follows.
* </p>
+ * <pre>
+ * nnn - an absolute value (0-255)
+ * mmm-nnn - an inclusive range of absolute values,
+ * with following shorthand notations:
+ * nnn- => nnn-255
+ * -nnn => 0-nnn
+ * - => 0-255
+ * a,b,... - a list of wildcard specifications
+ * </pre>
+ * <p>
+ * Internet address specification is separated from the URI pattern using the "|" (pipe)
+ * character. URI patterns follow the servlet specification for simple * prefix and
+ * suffix wild cards (e.g. /, /foo, /foo/bar, /foo/bar/*, *.baz).
* <p>
- * Examples of match specifications are:
+ * Earlier versions of the handler used internet address prefix wildcard specification
+ * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.).
+ * They also used the first "/" character of the URI pattern to separate it from the
+ * internet address. Both of these features have been deprecated in the current version.
+ * <p>
+ * Examples of the entry specifications are:
* <ul>
- * <li>10.1.2.3 - all requests from IP 10.1.2.3
- * <li>10.1.2.3/foo/bar - all requests from IP 10.1.2.3 to URI /foo/bar
- * <li>10.1.2.3/foo/* - all requests from IP 10.1.2.3 to URIs starting with /foo/
- * <li>10.1.2.3/*.html - all requests from IP 10.1.2.3 to URIs ending with .html
- * <li>10.1. - all requests from IPs starting with 10.1.
- * <li>10.1./foo/bar - all requests from IPs starting with 10.1. to URI /foo/bar
- * <li>10.1./foo/* - all requests from IPs starting with 10.1. to URIs starting with /foo/
+ * <li>10.10.1.2 - all requests from IP 10.10.1.2
+ * <li>10.10.1.2|/foo/bar - all requests from IP 10.10.1.2 to URI /foo/bar
+ * <li>10.10.1.2|/foo/* - all requests from IP 10.10.1.2 to URIs starting with /foo/
+ * <li>10.10.1.2|*.html - all requests from IP 10.10.1.2 to URIs ending with .html
+ * <li>10.10.0-255.0-255 - all requests from IPs within 10.10.0.0/16 subnet
+ * <li>10.10.0-.-255|/foo/bar - all requests from IPs within 10.10.0.0/16 subnet to URI /foo/bar
+ * <li>10.10.0-3,1,3,7,15|/foo/* - all requests from IPs addresses with last octet equal
+ * to 1,3,7,15 in subnet 10.10.0.0/22 to URIs starting with /foo/
* </ul>
* <p>
- * Typically, the black/white lists will be used in one of three modes:
- * <nl>
- * <li>Blocking a few specific IPs/URLs by specifying several black list entries.
- * <li>Allowing only some specific IPs/URLs by specifying several white lists entries.
- * <li>Allowing a general range of IPs/URLs by specifying serveral general white list
- * entries, that are then further refined by several specific black list exceptions
- * </ul>
- *
+ * Earlier versions of the handler used internet address prefix wildcard specification
+ * to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.).
+ * They also used the first "/" character of the URI pattern to separate it from the
+ * internet address. Both of these features have been deprecated in the current version.
*/
public class IPAccessHandler extends HandlerWrapper
{
- Map<String,PathMap> _whiteAddr = new HashMap<String, PathMap>();
- List<String> _whitePattern = new CopyOnWriteArrayList<String>();
- Map<String,PathMap> _blackAddr = new HashMap<String, PathMap>();
- List<String> _blackPattern = new CopyOnWriteArrayList<String>();
-
+ IPAddressMap<PathMap> _white = new IPAddressMap<PathMap>();
+ IPAddressMap<PathMap> _black = new IPAddressMap<PathMap>();
+
+ /* ------------------------------------------------------------ */
/**
+ * Creates new handler object
*/
public IPAccessHandler()
{
+ super();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Creates new handler object and initializes white- and black-list
+ *
+ * @param white array of whitelist entries
+ * @param black array of blacklist entries
+ */
+ public IPAccessHandler(String[] white, String []black)
+ {
+ super();
+
+ if (white != null && white.length > 0)
+ setWhite(white);
+ if (black != null && black.length > 0)
+ setBlack(black);
}
- public void addBlack(String addrPath)
+ /* ------------------------------------------------------------ */
+ /**
+ * Add a whitelist entry to an existing handler configuration
+ *
+ * @param entry new whitelist entry
+ */
+ public void addWhite(String entry)
{
- add(addrPath, _blackAddr, _blackPattern);
+ add(entry, _white);
}
- public void addWhite(String addrPath)
+ /* ------------------------------------------------------------ */
+ /**
+ * Add a blacklist entry to an existing handler configuration
+ *
+ * @param entry new blacklist entry
+ */
+ public void addBlack(String entry)
{
- add(addrPath, _whiteAddr, _whitePattern);
+ add(entry, _black);
}
- public void setBlack(String[] addrPaths)
+ /* ------------------------------------------------------------ */
+ /**
+ * Re-initialize the whitelist of existing handler object
+ *
+ * @param entries array of whitelist entries
+ */
+ public void setWhite(String[] entries)
{
- set(addrPaths, _blackAddr, _blackPattern);
+ set(entries, _white);
}
- public void setWhite(String[] addrPaths)
+ /* ------------------------------------------------------------ */
+ /**
+ * Re-initialize the blacklist of existing handler object
+ *
+ * @param entries array of blacklist entries
+ */
+ public void setBlack(String[] entries)
{
- set(addrPaths, _whiteAddr, _whitePattern);
+ set(entries, _black);
}
+ /* ------------------------------------------------------------ */
/**
+ * Checks the incoming request against the whitelist and blacklist
+ *
+ * @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
@@ -123,78 +194,178 @@ public class IPAccessHandler extends HandlerWrapper
getHandler().handle(target,baseRequest, request, response);
}
+
- protected void add(String addrPath, Map<String,PathMap> addrMap, List<String> patternList)
+ /* ------------------------------------------------------------ */
+ /**
+ * Helper method to parse the new entry and add it to
+ * the specified address pattern map.
+ *
+ * @param entry new entry
+ * @param patternMap target address pattern map
+ */
+ protected void add(String entry, IPAddressMap<PathMap> patternMap)
{
- int idx = addrPath.indexOf('/');
- String addr = idx > 0 ? addrPath.substring(0,idx) : addrPath;
- String path = idx > 0 ? addrPath.substring(idx) : null;
- if (path!=null && path.length()>1 && path.charAt(1)=='*')
- path=path.substring(1);
-
- PathMap map = addrMap.get(addr);
- if (map==null)
+ if (entry != null && entry.length() > 0)
{
- map = new PathMap(true);
- addrMap.put(addr,map);
+ boolean deprecated = false;
+ int idx;
+ if (entry.indexOf('|') > 0 )
+ {
+ idx = entry.indexOf('|');
+ }
+ else
+ {
+ idx = entry.indexOf('/');
+ deprecated = (idx >= 0);
+ }
+
+ String addr = idx > 0 ? entry.substring(0,idx) : entry;
+ String path = idx > 0 ? entry.substring(idx) : "/*";
+
if (addr.endsWith("."))
- patternList.add(addr);
+ deprecated = true;
+ if (path!=null && (path.startsWith("|") || path.startsWith("/*.")))
+ path=path.substring(1);
+
+ PathMap pathMap = patternMap.get(addr);
+ if (pathMap == null)
+ {
+ pathMap = new PathMap(true);
+ patternMap.put(addr,pathMap);
+ }
+ if (path != null)
+ pathMap.put(path,path);
+
+ if (deprecated)
+ Log.debug(toString() +" - deprecated specification syntax: "+entry);
}
-
- if (path != null)
- map.put(path,path);
}
- protected void set(String[] addrPaths, Map<String,PathMap> addrMap, List<String> patternList)
+ /* ------------------------------------------------------------ */
+ /**
+ * Helper method to process a list of new entries and replace
+ * the content of the specified address pattern map
+ *
+ * @param entries new entries
+ * @param patternMap target address pattern map
+ */
+ protected void set(String[] entries, IPAddressMap<PathMap> patternMap)
{
- addrMap.clear();
- patternList.clear();
- for (String addrPath:addrPaths)
- add(addrPath, addrMap, patternList);
+ patternMap.clear();
+
+ for (String addrPath:entries)
+ {
+ add(addrPath, patternMap);
+ }
}
+ /* ------------------------------------------------------------ */
+ /**
+ * Check if specified request is allowed by current IPAccess rules.
+ *
+ * @param addr internet address
+ * @param path context path
+ * @return true if request is allowed
+ *
+ */
protected boolean isAddrUriAllowed(String addr, String path)
{
- if (_whiteAddr.size()>0)
+ if (_white.size()>0)
{
- PathMap white=_whiteAddr.get(addr);
+ boolean match = false;
- if (white==null || (white.size()>0 && white.match(path)==null))
+ Object whiteObj = _white.getLazyMatches(addr);
+ if (whiteObj != null)
{
- boolean match=false;
- for (String pattern:_whitePattern)
+ List whiteList = (whiteObj instanceof List) ? (List)whiteObj : Collections.singletonList(whiteObj);
+
+ for (Object entry: whiteList)
{
- if (addr.startsWith(pattern))
- {
- white=_whiteAddr.get(pattern);
- if (white!=null && white.size()>0 && white.match(path)!=null)
- {
- match=true;
- break;
- }
- }
+ PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue();
+ if (match = (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null)));
+ break;
}
- if (!match)
- return false;
}
+
+ if (!match)
+ return false;
}
- PathMap black=_blackAddr.get(addr);
- if (black!=null && (black.size()==0 || black.match(path)!=null))
- return false;
-
- for (String pattern:_blackPattern)
+ if (_black.size() > 0)
{
- if (addr.startsWith(pattern))
+ Object blackObj = _black.getLazyMatches(addr);
+ if (blackObj != null)
{
- black=_blackAddr.get(pattern);
- if (black!=null && black.match(path)!=null)
- return false;
- break;
+ List blackList = (blackObj instanceof List) ? (List)blackObj : Collections.singletonList(blackObj);
+
+ for (Object entry: blackList)
+ {
+ PathMap pathMap = ((Map.Entry<String,PathMap>)entry).getValue();
+ if (pathMap!=null && (pathMap.size()==0 || pathMap.match(path)!=null))
+ return false;
+ }
}
}
return true;
}
-}
+ /* ------------------------------------------------------------ */
+ /**
+ * Dump the white- and black-list configurations when started
+ *
+ * @see org.eclipse.jetty.server.handler.HandlerWrapper#doStart()
+ */
+ @Override
+ protected void doStart()
+ throws Exception
+ {
+ super.doStart();
+
+ if (Log.isDebugEnabled())
+ {
+ System.err.println(dump());
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Dump the handler configuration
+ */
+ public String dump()
+ {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append(toString());
+ buf.append(" WHITELIST:\n");
+ dump(buf, _white);
+ buf.append(toString());
+ buf.append(" BLACKLIST:\n");
+ dump(buf, _black);
+
+ return buf.toString();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Dump a pattern map into a StringBuilder buffer
+ *
+ * @param buf buffer
+ * @param patternMap pattern map to dump
+ */
+ protected void dump(StringBuilder buf, IPAddressMap<PathMap> patternMap)
+ {
+ for (String addr: patternMap.keySet())
+ {
+ for (Object path: ((PathMap)patternMap.get(addr)).values())
+ {
+ buf.append("# ");
+ buf.append(addr);
+ buf.append("|");
+ buf.append(path);
+ buf.append("\n");
+ }
+ }
+ }
+ }
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java
new file mode 100644
index 0000000000..b168e3ecb0
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/IPAccessHandlerTest.java
@@ -0,0 +1,392 @@
+// ========================================================================
+// Copyright (c) 2010 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.server.handler;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.bio.SocketConnector;
+import org.eclipse.jetty.util.log.Log;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class IPAccessHandlerTest
+{
+ private static Server _server;
+ private static Connector _connector;
+ private static IPAccessHandler _handler;
+
+ private String _white;
+ private String _black;
+ private String _host;
+ private String _uri;
+ private String _code;
+
+ @BeforeClass
+ public static void setUp()
+ throws Exception
+ {
+ _server = new Server();
+ _connector = new SocketConnector();
+ _server.setConnectors(new Connector[] { _connector });
+
+ _handler = new IPAccessHandler();
+ _handler.setHandler(new AbstractHandler()
+ {
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ {
+ baseRequest.setHandled(true);
+ response.setStatus(HttpStatus.OK_200);
+ }
+ });
+ _server.setHandler(_handler);
+ Log.getLog().setDebugEnabled(true);
+ _server.start();
+ }
+
+ /* ------------------------------------------------------------ */
+ @AfterClass
+ public static void tearDown()
+ throws Exception
+ {
+ _server.stop();
+ }
+
+ /* ------------------------------------------------------------ */
+ public IPAccessHandlerTest(String white, String black, String host, String uri, String code)
+ {
+ _white = white;
+ _black = black;
+ _host = host;
+ _uri = uri;
+ _code = code;
+ }
+
+ /* ------------------------------------------------------------ */
+ @Test
+ public void testHandler()
+ throws Exception
+ {
+ _handler.setWhite(_white.split(";",-1));
+ _handler.setBlack(_black.split(";",-1));
+
+ String request = "GET " + _uri + " HTTP/1.1\n" + "Host: "+ _host + "\n\n";
+ Socket socket = new Socket("localhost", _connector.getLocalPort());
+ socket.setSoTimeout(5000);
+ try
+ {
+ OutputStream output = socket.getOutputStream();
+ BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+
+ output.write(request.getBytes("UTF-8"));
+ output.flush();
+
+ Response response = readResponse(input);
+ assertEquals(_code, response.getCode());
+ }
+ finally
+ {
+ socket.close();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ protected Response readResponse(BufferedReader reader)
+ throws IOException
+ {
+ // Simplified parser for HTTP responses
+ String line = reader.readLine();
+ if (line == null)
+ throw new EOFException();
+ Matcher responseLine = Pattern.compile("HTTP/1\\.1\\s+(\\d+)").matcher(line);
+ assertTrue(responseLine.lookingAt());
+ String code = responseLine.group(1);
+
+ Map<String, String> headers = new LinkedHashMap<String, String>();
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.trim().length() == 0)
+ break;
+
+ Matcher header = Pattern.compile("([^:]+):\\s*(.*)").matcher(line);
+ assertTrue(header.lookingAt());
+ String headerName = header.group(1);
+ String headerValue = header.group(2);
+ headers.put(headerName.toLowerCase(), headerValue.toLowerCase());
+ }
+
+ StringBuilder body = new StringBuilder();
+ if (headers.containsKey("content-length"))
+ {
+ int length = Integer.parseInt(headers.get("content-length"));
+ for (int i = 0; i < length; ++i)
+ {
+ char c = (char)reader.read();
+ body.append(c);
+ }
+ }
+ else if ("chunked".equals(headers.get("transfer-encoding")))
+ {
+ while ((line = reader.readLine()) != null)
+ {
+ if ("0".equals(line))
+ {
+ line = reader.readLine();
+ assertEquals("", line);
+ break;
+ }
+
+ int length = Integer.parseInt(line, 16);
+ for (int i = 0; i < length; ++i)
+ {
+ char c = (char)reader.read();
+ body.append(c);
+ }
+ line = reader.readLine();
+ assertEquals("", line);
+ }
+ }
+
+ return new Response(code, headers, body.toString().trim());
+ }
+
+ /* ------------------------------------------------------------ */
+ protected class Response
+ {
+ private final String code;
+ private final Map<String, String> headers;
+ private final String body;
+
+ /* ------------------------------------------------------------ */
+ private Response(String code, Map<String, String> headers, String body)
+ {
+ this.code = code;
+ this.headers = headers;
+ this.body = body;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getCode()
+ {
+ return code;
+ }
+
+ /* ------------------------------------------------------------ */
+ public Map<String, String> getHeaders()
+ {
+ return headers;
+ }
+
+ /* ------------------------------------------------------------ */
+ public String getBody()
+ {
+ return body;
+ }
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append(code).append("\r\n");
+ for (Map.Entry<String, String> entry : headers.entrySet())
+ builder.append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
+ builder.append("\r\n");
+ builder.append(body);
+ return builder.toString();
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ @Parameters
+ public static Collection<Object[]> data() {
+ Object[][] data = new Object[][] {
+ // Empty lists
+ {"", "", "127.0.0.1", "/", "200"},
+ {"", "", "127.0.0.1", "/dump/info", "200"},
+
+ // White list
+ {"127.0.0.1", "", "127.0.0.1", "/", "200"},
+ {"127.0.0.1", "", "127.0.0.1", "/dispatch", "200"},
+ {"127.0.0.1", "", "127.0.0.1", "/dump/info", "200"},
+
+ {"127.0.0.1|/", "", "127.0.0.1", "/", "200"},
+ {"127.0.0.1|/", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.1|/", "", "127.0.0.1", "/dump/info", "403"},
+
+ {"127.0.0.1|/*", "", "127.0.0.1", "/", "200"},
+ {"127.0.0.1|/*", "", "127.0.0.1", "/dispatch", "200"},
+ {"127.0.0.1|/*", "", "127.0.0.1", "/dump/info", "200"},
+
+ {"127.0.0.1|/dump/*", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.1|/dump/*", "", "127.0.0.1", "/dump/test", "200"},
+
+ {"127.0.0.1|/dump/info", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.1|/dump/info", "", "127.0.0.1", "/dump/test", "403"},
+
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/test", "200"},
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "", "127.0.0.1", "/dump/fail", "403"},
+
+ {"127.0.0.0-2|", "", "127.0.0.1", "/", "200"},
+ {"127.0.0.0-2|", "", "127.0.0.1", "/dump/info", "200"},
+
+ {"127.0.0.0-2|/", "", "127.0.0.1", "/", "200"},
+ {"127.0.0.0-2|/", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.0-2|/", "", "127.0.0.1", "/dump/info", "403"},
+
+ {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.0-2|/dump/*", "", "127.0.0.1", "/dump/info", "200"},
+
+ {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.0-2|/dump/info", "", "127.0.0.1", "/dump/test", "403"},
+
+ {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/test", "200"},
+ {"127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "", "127.0.0.1", "/dump/fail", "403"},
+
+ // Black list
+ {"", "127.0.0.1", "127.0.0.1", "/", "403"},
+ {"", "127.0.0.1", "127.0.0.1", "/dispatch", "403"},
+ {"", "127.0.0.1", "127.0.0.1", "/dump/info", "403"},
+
+ {"", "127.0.0.1|/", "127.0.0.1", "/", "403"},
+ {"", "127.0.0.1|/", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.1|/", "127.0.0.1", "/dump/info", "200"},
+
+ {"", "127.0.0.1|/*", "127.0.0.1", "/", "403"},
+ {"", "127.0.0.1|/*", "127.0.0.1", "/dispatch", "403"},
+ {"", "127.0.0.1|/*", "127.0.0.1", "/dump/info", "403"},
+
+ {"", "127.0.0.1|/dump/*", "127.0.0.1", "/", "200"},
+ {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dump/info", "403"},
+ {"", "127.0.0.1|/dump/*", "127.0.0.1", "/dump/test", "403"},
+
+ {"", "127.0.0.1|/dump/info", "127.0.0.1", "/", "200"},
+ {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dump/info", "403"},
+ {"", "127.0.0.1|/dump/info", "127.0.0.1", "/dump/test", "200"},
+
+ {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/", "200"},
+ {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/info", "403"},
+ {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/test", "403"},
+ {"", "127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1", "/dump/fail", "200"},
+
+ {"", "127.0.0.0-2|", "127.0.0.1", "/", "403"},
+ {"", "127.0.0.0-2|", "127.0.0.1", "/dump/info", "403"},
+
+ {"", "127.0.0.0-2|/", "127.0.0.1", "/", "403"},
+ {"", "127.0.0.0-2|/", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.0-2|/", "127.0.0.1", "/dump/info", "200"},
+
+ {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/", "200"},
+ {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.0-2|/dump/*", "127.0.0.1", "/dump/info", "403"},
+
+ {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/", "200"},
+ {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dump/info", "403"},
+ {"", "127.0.0.0-2|/dump/info", "127.0.0.1", "/dump/test", "200"},
+
+ {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/", "200"},
+ {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dispatch", "200"},
+ {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/info", "403"},
+ {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/test", "403"},
+ {"", "127.0.0.0-2|/dump/info;127.0.0.0-2|/dump/test", "127.0.0.1", "/dump/fail", "200"},
+
+ // Both lists
+ {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"},
+ {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "403"},
+ {"127.0.0.1|/dump", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"},
+
+ {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"},
+ {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.1|/dump/*", "127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"},
+
+ {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump", "200"},
+ {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/test", "403"},
+ {"127.0.0.1|/dump/*", "127.0.0.1|/dump/test;127.0.0.1|/dump/fail", "127.0.0.1", "/dump/fail", "403"},
+
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump", "403"},
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/test", "403"},
+ {"127.0.0.1|/dump/info;127.0.0.1|/dump/test", "127.0.0.1|/dump/test", "127.0.0.1", "/dump/fail", "403"},
+
+ // Different address
+ {"127.0.0.2", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.2", "", "127.0.0.1", "/dump/info", "403"},
+
+ {"127.0.0.2|/dump/*", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.2|/dump/*", "", "127.0.0.1", "/dump/info", "403"},
+
+ {"127.0.0.2|/dump/info", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.2|/dump/info", "", "127.0.0.1", "/dump/info", "403"},
+ {"127.0.0.2|/dump/info", "", "127.0.0.1", "/dump/test", "403"},
+
+ {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/", "403"},
+ {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dispatch", "403"},
+ {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/info", "200"},
+ {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/test", "403"},
+ {"127.0.0.1|/dump/info;127.0.0.2|/dump/test", "", "127.0.0.1", "/dump/fail", "403"},
+
+ {"172.0.0.0-255", "", "127.0.0.1", "/", "403"},
+ {"172.0.0.0-255", "", "127.0.0.1", "/dump/info", "403"},
+
+ {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/", "403"},
+ {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/dispatch", "403"},
+ {"172.0.0.0-255|/dump/*;127.0.0.0-255|/dump/*", "", "127.0.0.1", "/dump/info", "200"},
+ };
+ return Arrays.asList(data);
+ };
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java
new file mode 100644
index 0000000000..79f7039fd5
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/IPAddressMap.java
@@ -0,0 +1,362 @@
+// ========================================================================
+// Copyright (c) 2010 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.BitSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+
+/* ------------------------------------------------------------ */
+/**
+ * Internet address map to object
+ * <p>
+ * Internet addresses may be specified as absolute address or as a combination of
+ * four octet wildcard specifications (a.b.c.d) that are defined as follows.
+ * </p>
+ * <pre>
+ * nnn - an absolute value (0-255)
+ * mmm-nnn - an inclusive range of absolute values,
+ * with following shorthand notations:
+ * nnn- => nnn-255
+ * -nnn => 0-nnn
+ * - => 0-255
+ * a,b,... - a list of wildcard specifications
+ * </pre>
+ */
+public class IPAddressMap<TYPE> extends HashMap<String, TYPE>
+{
+ private final HashMap<String,IPAddrPattern> _patterns = new HashMap<String,IPAddrPattern>();
+
+ /* --------------------------------------------------------------- */
+ /** Construct empty AddrPatternMap.
+ */
+ public IPAddressMap()
+ {
+ super(11);
+ }
+
+ /* --------------------------------------------------------------- */
+ /** Construct empty AddrPatternMap.
+ *
+ * @param capacity initial capacity
+ */
+ public IPAddressMap(int capacity)
+ {
+ super (capacity);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Insert a new internet address into map
+ *
+ * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public TYPE put(String addrSpec, TYPE object)
+ throws IllegalArgumentException
+ {
+ if (addrSpec == null || addrSpec.trim().length() == 0)
+ throw new IllegalArgumentException("Invalid IP address pattern: "+addrSpec);
+
+ String spec = addrSpec.trim();
+ if (_patterns.get(spec) == null)
+ _patterns.put(spec,new IPAddrPattern(spec));
+
+ return super.put(spec, object);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Retrieve the object mapped to the specified internet address literal
+ *
+ * @see java.util.HashMap#get(java.lang.Object)
+ */
+ /* ------------------------------------------------------------ */
+ /**
+ * @see java.util.HashMap#get(java.lang.Object)
+ */
+ @Override
+ public TYPE get(Object key)
+ {
+ return super.get(key);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Retrieve the first object that is associated with the specified
+ * internet address by taking into account the wildcard specifications.
+ *
+ * @param addr internet address
+ * @return associated object
+ */
+ public TYPE match(String addr)
+ {
+ Map.Entry<String, TYPE> entry = getMatch(addr);
+ return entry==null ? null : entry.getValue();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Retrieve the first map entry that is associated with the specified
+ * internet address by taking into account the wildcard specifications.
+ *
+ * @param addr internet address
+ * @return map entry associated
+ */
+ public Map.Entry<String, TYPE> getMatch(String addr)
+ {
+ if (addr != null)
+ {
+ for(Map.Entry<String, TYPE> entry: super.entrySet())
+ {
+ if (_patterns.get(entry.getKey()).match(addr))
+ {
+ return entry;
+ }
+ }
+ }
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Retrieve a lazy list of map entries associated with specified
+ * internet address by taking into account the wildcard specifications.
+ *
+ * @param addr internet address
+ * @return lazy list of map entries
+ */
+ public Object getLazyMatches(String addr)
+ {
+ if (addr == null)
+ return LazyList.getList(super.entrySet());
+
+ Object entries = null;
+ for(Map.Entry<String, TYPE> entry: super.entrySet())
+ {
+ if (_patterns.get(entry.getKey()).match(addr))
+ {
+ entries = LazyList.add(entries,entry);
+ }
+ }
+ return entries;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * IPAddrPattern
+ *
+ * Represents internet address wildcard.
+ * Matches the wildcard to provided internet address.
+ */
+ private static class IPAddrPattern
+ {
+ private final OctetPattern[] _octets = new OctetPattern[4];
+ /* ------------------------------------------------------------ */
+ /**
+ * Create new IPAddrPattern
+ *
+ * @param value internet address wildcard specification
+ * @throws IllegalArgumentException if wildcard specification is invalid
+ */
+ public IPAddrPattern(String value)
+ throws IllegalArgumentException
+ {
+ if (value == null || value.trim().length() == 0)
+ throw new IllegalArgumentException("Invalid IP address pattern: "+value);
+
+ try
+ {
+ StringTokenizer parts = new StringTokenizer(value, ".");
+
+ String part;
+ for (int idx=0; idx<4; idx++)
+ {
+ part = parts.hasMoreTokens() ? parts.nextToken().trim() : "0-255";
+
+ int len = part.length();
+ if (len == 0 && parts.hasMoreTokens())
+ throw new IllegalArgumentException("Invalid IP address pattern: "+value);
+
+ _octets[idx] = new OctetPattern(len==0 ? "0-255" : part);
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new IllegalArgumentException("Invalid IP address pattern: "+value, ex);
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Match the specified internet address against the wildcard
+ *
+ * @param value internet address
+ * @return true if specified internet address matches wildcard specification
+ *
+ * @throws IllegalArgumentException if specified internet address is invalid
+ */
+ public boolean match(String value)
+ throws IllegalArgumentException
+ {
+ if (value == null || value.trim().length() == 0)
+ throw new IllegalArgumentException("Invalid IP address: "+value);
+
+ try
+ {
+ StringTokenizer parts = new StringTokenizer(value, ".");
+
+ boolean result = true;
+ for (int idx=0; idx<4; idx++)
+ {
+ if (!parts.hasMoreTokens())
+ throw new IllegalArgumentException("Invalid IP address: "+value);
+
+ if (!(result &= _octets[idx].match(parts.nextToken())))
+ break;
+ }
+ return result;
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new IllegalArgumentException("Invalid IP address: "+value, ex);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * OctetPattern
+ *
+ * Represents a single octet wildcard.
+ * Matches the wildcard to the specified octet value.
+ */
+ private static class OctetPattern extends BitSet
+ {
+ private final BitSet _mask = new BitSet(256);
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Create new OctetPattern
+ *
+ * @param octetSpec octet wildcard specification
+ * @throws IllegalArgumentException if wildcard specification is invalid
+ */
+ public OctetPattern(String octetSpec)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ if (octetSpec != null)
+ {
+ String spec = octetSpec.trim();
+ if(spec.length() == 0)
+ {
+ _mask.set(0,255);
+ }
+ else
+ {
+ StringTokenizer parts = new StringTokenizer(spec,",");
+ while (parts.hasMoreTokens())
+ {
+ String part = parts.nextToken().trim();
+ if (part.length() > 0)
+ {
+ if (part.indexOf('-') < 0)
+ {
+ Integer value = Integer.valueOf(part);
+ _mask.set(value);
+ }
+ else
+ {
+ int low = 0, high = 255;
+
+ String[] bounds = part.split("-",-2);
+ if (bounds.length != 2)
+ {
+ throw new IllegalArgumentException("Invalid octet spec: "+octetSpec);
+ }
+
+ if (bounds[0].length() > 0)
+ {
+ low = Integer.parseInt(bounds[0]);
+ }
+ if (bounds[1].length() > 0)
+ {
+ high = Integer.parseInt(bounds[1]);
+ }
+
+ if (low > high)
+ {
+ throw new IllegalArgumentException("Invalid octet spec: "+octetSpec);
+ }
+
+ _mask.set(low, high+1);
+ }
+ }
+ }
+ }
+ }
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new IllegalArgumentException("Invalid octet spec: "+octetSpec, ex);
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Match specified octet value against the wildcard
+ *
+ * @param value octet value
+ * @return true if specified octet value matches the wildcard
+ * @throws IllegalArgumentException if specified octet value is invalid
+ */
+ public boolean match(String value)
+ throws IllegalArgumentException
+ {
+ if (value == null || value.trim().length() == 0)
+ throw new IllegalArgumentException("Invalid octet: "+value);
+
+ try
+ {
+ int number = Integer.parseInt(value);
+ return match(number);
+ }
+ catch (NumberFormatException ex)
+ {
+ throw new IllegalArgumentException("Invalid octet: "+value);
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Match specified octet value against the wildcard
+ *
+ * @param value octet value
+ * @return true if specified octet value matches the wildcard
+ * @throws IllegalArgumentException if specified octet value is invalid
+ */
+ public boolean match(int number)
+ throws IllegalArgumentException
+ {
+ if (number < 0 || number > 255)
+ throw new IllegalArgumentException("Invalid octet: "+number);
+
+ return _mask.get(number);
+ }
+ }
+} \ No newline at end of file
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java
new file mode 100644
index 0000000000..f1ade99091
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/IPAddressMapTest.java
@@ -0,0 +1,172 @@
+// ========================================================================
+// Copyright (c) 2010 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+
+public class IPAddressMapTest
+{
+ @Test
+ public void testOneAddress()
+ {
+ IPAddressMap<String> map = new IPAddressMap();
+
+ map.put("10.5.2.1","1");
+
+ assertNotNull(map.match("10.5.2.1"));
+
+ assertNull(map.match("101.5.2.1"));
+ assertNull(map.match("10.15.2.1"));
+ assertNull(map.match("10.5.22.1"));
+ assertNull(map.match("10.5.2.0"));
+ }
+
+ /* ------------------------------------------------------------ */
+ @Test
+ public void testOneRange()
+ {
+ IPAddressMap<String> map = new IPAddressMap();
+
+ map.put("1-15.16-31.32-63.64-127","1");
+
+ assertNotNull(map.match("7.23.39.71"));
+ assertNotNull(map.match("1.16.32.64"));
+ assertNotNull(map.match("15.31.63.127"));
+
+ assertNull(map.match("16.32.64.128"));
+ assertNull(map.match("1.16.32.63"));
+ assertNull(map.match("1.16.31.64"));
+ assertNull(map.match("1.15.32.64"));
+ assertNull(map.match("0.16.32.64"));
+ }
+
+ /* ------------------------------------------------------------ */
+ @Test
+ public void testOneMissing()
+ {
+ IPAddressMap<String> map = new IPAddressMap();
+
+ map.put("10.5.2.","1");
+
+ assertNotNull(map.match("10.5.2.0"));
+ assertNotNull(map.match("10.5.2.128"));
+ assertNotNull(map.match("10.5.2.255"));
+ }
+
+ /* ------------------------------------------------------------ */
+ @Test
+ public void testTwoMissing()
+ {
+ IPAddressMap<String> map = new IPAddressMap();
+
+ map.put("10.5.","1");
+
+ assertNotNull(map.match("10.5.2.0"));
+ assertNotNull(map.match("10.5.2.128"));
+ assertNotNull(map.match("10.5.2.255"));
+ assertNotNull(map.match("10.5.0.1"));
+ assertNotNull(map.match("10.5.128.1"));
+ assertNotNull(map.match("10.5.255.1"));
+ }
+
+ /* ------------------------------------------------------------ */
+ @Test
+ public void testThreeMissing()
+ {
+ IPAddressMap<String> map = new IPAddressMap();
+
+ map.put("10.","1");
+
+ assertNotNull(map.match("10.5.2.0"));
+ assertNotNull(map.match("10.5.2.128"));
+ assertNotNull(map.match("10.5.2.255"));
+ assertNotNull(map.match("10.5.0.1"));
+ assertNotNull(map.match("10.5.128.1"));
+ assertNotNull(map.match("10.5.255.1"));
+ assertNotNull(map.match("10.0.1.1"));
+ assertNotNull(map.match("10.128.1.1"));
+ assertNotNull(map.match("10.255.1.1"));
+ }
+
+ /* ------------------------------------------------------------ */
+ @Test
+ public void testOneMixed()
+ {
+ IPAddressMap<String> map = new IPAddressMap();
+
+ map.put("0-15,21.10,16-31.0-15,32-63.-95,128-","1");
+
+ assertNotNull(map.match("7.23.39.46"));
+ assertNotNull(map.match("10.20.10.150"));
+ assertNotNull(map.match("21.10.32.255"));
+ assertNotNull(map.match("21.10.15.0"));
+
+ assertNull(map.match("16.15.20.100"));
+ assertNull(map.match("15.10.63.100"));
+ assertNull(map.match("15.10.64.128"));
+ assertNull(map.match("15.11.32.95"));
+ assertNull(map.match("16.31.63.128"));
+ }
+
+ /* ------------------------------------------------------------ */
+ @Test
+ public void testManyMixed()
+ {
+ IPAddressMap<String> map = new IPAddressMap();
+
+ map.put("10.5.2.1","1");
+ map.put("1-15.16-31.32-63.64-127","2");
+ map.put("1-15,21.10,16-31.0-15,32-63.-55,195-","3");
+ map.put("44.99.99.","4");
+ map.put("55.99.","5");
+ map.put("66.","6");
+
+ assertEquals("1", map.match("10.5.2.1"));
+
+ assertEquals("2", map.match("7.23.39.71"));
+ assertEquals("2", map.match("1.16.32.64"));
+ assertEquals("2", map.match("15.31.63.127"));
+
+ assertEquals("3", map.match("7.23.39.46"));
+ assertEquals("3", map.match("10.20.10.200"));
+ assertEquals("3", map.match("21.10.32.255"));
+ assertEquals("3", map.match("21.10.15.0"));
+
+ assertEquals("4", map.match("44.99.99.0"));
+ assertEquals("5", map.match("55.99.128.1"));
+ assertEquals("6", map.match("66.255.1.1"));
+
+ assertNull(map.match("101.5.2.1"));
+ assertNull(map.match("10.15.2.1"));
+ assertNull(map.match("10.5.22.1"));
+ assertNull(map.match("10.5.2.0"));
+
+ assertNull(map.match("16.32.64.96"));
+ assertNull(map.match("1.16.32.194"));
+ assertNull(map.match("1.16.31.64"));
+ assertNull(map.match("1.15.32.64"));
+ assertNull(map.match("0.16.32.64"));
+
+ assertNull(map.match("16.15.20.100"));
+ assertNull(map.match("15.10.63.100"));
+ assertNull(map.match("15.10.64.128"));
+ assertNull(map.match("15.11.32.95"));
+ assertNull(map.match("16.31.63.128"));
+ }
+}

Back to the top