/*
* The contents of this file are subject to the terms of the Common Development and
* Distribution License (the License). You may not use this file except in compliance with the
* License.
*
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
* specific language governing permission and limitations under the License.
*
* When distributing Covered Software, include this CDDL Header Notice in each file and include
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2014-2015 ForgeRock AS.
*/
package com.sun.identity.shared.whitelist;
import static org.testng.AssertJUnit.*;
import java.net.MalformedURLException;
import java.util.Collections;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class URLPatternMatcherTest {
final URLPatternMatcher urlPatternMatcher = new URLPatternMatcher();
@Test(dataProvider = "testdata")
private void performTestAndAssert(String pattern, String url, boolean result) throws MalformedURLException {
boolean answer = urlPatternMatcher.match(url, Collections.singleton(pattern), true); //wildcard always enabled
assertEquals(result, answer);
}
@DataProvider(name = "testdata")
public Object[][] testBasic() {
final String PATTERN_1 = "https://www.google.com/*";
final String PATTERN_2 = "http://www.good.com";
final String PATTERN_3 = "http://www.good.com/hello.html";
final String PATTERN_4 = "*";
final String PATTERN_5 = "http://*";
final String PATTERN_6 = "http://www.*:*";
final String PATTERN_7 = "http://www.*/*";
final String PATTERN_8 = "http://www.*:*/";
final String PATTERN_9 = "http://www.*.good.com";
final String PATTERN_10 = "http://www.*.good.com/";
final String PATTERN_11 = "http://www.*.good.com/*";
final String PATTERN_12 = "https://www.*.good.com:*/*";
final String PATTERN_13 = "https://www.*.good.com:*/-*-/blah";
final String PATTERN_14 = "*?*";
final String PATTERN_15 = "http://*.good.com*/*?*";
final String PATTERN_16 = "/abc*";
final String PATTERN_17 = "http://www.good.com:80*";
final String PATTERN_18 = "https://www.*.good.com:443/*";
final String PATTERN_19 = "https://www.good.com:443/asdf*/blah";
final String PATTERN_20 = "https://www.good.com:443/asdf-*-/blah";
final String PATTERN_21 = "http://www.good.com:80/*/hello?*";
final String PATTERN_22 = "http://www.good.com:80/-*-/-*-/-*-?*";
final String PATTERN_23 = "http://www.good.com:80/*/*/*?*";
return new Object[][]{
//basic test one
{PATTERN_1, "https://www.google.com:443/hello/there/dance/for/me", true},
{PATTERN_1, "https://www.google.com:443/hello/there", true},
{PATTERN_1, "https://www.google.com:443/hello/there/", true},
{PATTERN_1, "https://www.google.com:443/", true},
{PATTERN_1, "https://www.google.com:443", true},
//basic test two
{PATTERN_2, "http://www.good.com", true},
{PATTERN_2, "http://www.good.com/", true},
{PATTERN_2, "http://www.good.com:80", true},
{PATTERN_2, "http://www.good.com:80/", true},
{PATTERN_2, "http://www.good.com:80/hello/world", false},
{PATTERN_2, "https://www.hello.good.com", false},
{PATTERN_2, "https://www.hello.good.com:443", false},
{PATTERN_2, "https://www.hello.good.com:443/hello/world", false},
{PATTERN_2, "http://www.hello.good.com/hello/world", false},
{PATTERN_2, "http://www.hello.good.com/hello/world?key=value", false},
{PATTERN_2, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_2, "http://www.hello.good.com:80/hello/world", false},
{PATTERN_2, "http://www.hello.good.com:80/hello/world?key=value", false},
{PATTERN_2, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_2, "http://www.hello.bad.com/hello/world/.good.com:80", false},
{PATTERN_2, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
{PATTERN_2, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_2, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},
// tests basic matching with path
{PATTERN_3, "http://www.good.com", false},
{PATTERN_3, "http://www.good.com/", false},
{PATTERN_3, "http://www.good.com:80", false},
{PATTERN_3, "http://www.good.com:80/", false},
{PATTERN_3, "http://www.good.com/hello.html", true},
{PATTERN_3, "http://www.good.com/hello.html/", false},
{PATTERN_3, "http://www.good.com:80/hello.html", true},
{PATTERN_3, "http://www.good.com:80/hello.html/", false},
{PATTERN_3, "http://www.good.com:80/hello/world", false},
{PATTERN_3, "https://www.hello.good.com", false},
{PATTERN_3, "https://www.hello.good.com:443", false},
{PATTERN_3, "https://www.hello.good.com:443/hello/world", false},
{PATTERN_3, "http://www.hello.good.com/hello/world", false},
{PATTERN_3, "http://www.hello.good.com/hello/world?key=value", false},
{PATTERN_3, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_3, "http://www.hello.good.com:80/hello/world", false},
{PATTERN_3, "http://www.hello.good.com:80/hello/world?key=value", false},
{PATTERN_3, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_3, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
{PATTERN_3, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
{PATTERN_3, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_3, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},
// tests basic wildcards, should match everything except URLs with question marks in path
{PATTERN_4, "http://www.good.com", true},
{PATTERN_4, "http://www.good.com/", true},
{PATTERN_4, "http://www.good.com:80", true},
{PATTERN_4, "http://www.good.com:80/", true},
{PATTERN_4, "http://www.good.com:80/hello/world", true},
{PATTERN_4, "https://www.good.com", true},
{PATTERN_4, "https://www.good.com/", true},
{PATTERN_4, "https://www.good.com:443", true},
{PATTERN_4, "https://www.good.com:443/", true},
{PATTERN_4, "https://www.good.com:443/hello/world", true},
{PATTERN_4, "http://www.good.com/hello/world", true},
{PATTERN_4, "http://www.good.com/hello/world?key=value", false},
{PATTERN_4, "http://www.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_4, "http://www.good.com:80/hello/world", true},
{PATTERN_4, "http://www.good.com:80/hello/world?key=value", false},
{PATTERN_4, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_4, "http://www.bad.com:80/hello/world/.good.com:80", true},
{PATTERN_4, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", true},
//testing wildcard in-location. Should only match domain, and default port (with or without trailing slash)
{PATTERN_5, "http://www.good.com", true},
{PATTERN_5, "http://www.good.com:80", true},
{PATTERN_5, "http://www.good.com:80/hello/world", false},
{PATTERN_5, "https://www.good.com", false},
{PATTERN_5, "https://www.good.com:443", false},
{PATTERN_5, "https://www.good.com:443/hello/world", false},
{PATTERN_5, "http://www.good.com/hello/world", false},
{PATTERN_5, "http://www.good.com/hello/world?key=value", false},
{PATTERN_5, "http://www.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_5, "http://www.good.com:80/hello/world", false},
{PATTERN_5, "http://www.good.com:80/hello/world?key=value", false},
{PATTERN_5, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_5, "http://www.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_5, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
//as above, but allows the port to be anything other than 80
{PATTERN_6, "http://www.good.com", true},
{PATTERN_6, "http://www.good.com:80", true},
{PATTERN_6, "http://www.good.com:80/hello/world", false},
{PATTERN_6, "https://www.good.com", false},
{PATTERN_6, "https://www.good.com:443", false},
{PATTERN_6, "https://www.good.com:443/hello/world", false},
{PATTERN_6, "http://www.good.com/hello/world", false},
{PATTERN_6, "http://www.good.com/hello/world?key=value", false},
{PATTERN_6, "http://www.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_6, "http://www.good.com:80/hello/world", false},
{PATTERN_6, "http://www.good.com:80/hello/world?key=value", false},
{PATTERN_6, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_6, "http://www.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_6, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
{PATTERN_6, "http://bad.com:80/hello/world/.good.com:80", false},
{PATTERN_6, "http://bad.com:80/hello/world/.good.com:80/hello/world", false},
//default port, random host and random path of indeterminable length (excluding question mark)
{PATTERN_7, "http://www.good.com", true},
{PATTERN_7, "http://www.good.com:80", true},
{PATTERN_7, "http://www.good.com:80/hello/world", true},
{PATTERN_7, "https://www.good.com", false},
{PATTERN_7, "https://www.good.com:443", false},
{PATTERN_7, "https://www.good.com:443/hello/world", false},
{PATTERN_7, "http://www.good.com/hello/world", true},
{PATTERN_7, "http://www.good.com/hello/world?key=value", false},
{PATTERN_7, "http://www.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_7, "http://www.good.com:80/hello/world", true},
{PATTERN_7, "http://www.good.com:80/hello/world?key=value", false},
{PATTERN_7, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_7, "http://www.bad.com:80/hello/world", true},
{PATTERN_7, "http://www.bad.com", true},
{PATTERN_7, "http://www.bad.com:80", true},
{PATTERN_7, "http://www.bad.com:80/hello/world/.good.com:80", true},
{PATTERN_7, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", true},
//random domain, random port, no path but allowed to have optional trailing slash
{PATTERN_8, "http://www.good.com", true},
{PATTERN_8, "http://www.good.com/", true},
{PATTERN_8, "http://www.good.com:80", true},
{PATTERN_8, "http://www.good.com:80/", true},
{PATTERN_8, "http://www.good.com:80/hello/world", false},
{PATTERN_8, "https://www.good.com", false},
{PATTERN_8, "https://www.good.com:443", false},
{PATTERN_8, "https://www.good.com:443/hello/world", false},
{PATTERN_8, "http://www.good.com/hello/world", false},
{PATTERN_8, "http://www.good.com/hello/world?key=value", false},
{PATTERN_8, "http://www.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_8, "http://www.good.com:80/hello/world", false},
{PATTERN_8, "http://www.good.com:80/hello/world?key=value", false},
{PATTERN_8, "http://www.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_8, "http://www.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_8, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
//random subdomain (but only so long as it's actually a subdomain and not part of the path)
{PATTERN_9, "http://www.good.com", false},
{PATTERN_9, "http://www.good.com:80", false},
{PATTERN_9, "http://www.good.com:80/hello/world", false},
{PATTERN_9, "http://www.hello.good.com", true},
{PATTERN_9, "http://www.hello.good.com/", true},
{PATTERN_9, "http://www.hello.good.com:80", true},
{PATTERN_9, "http://www.hello.good.com:80/", true},
{PATTERN_9, "http://www.hello.good.com:80/hello/world", false},
{PATTERN_9, "https://www.hello.good.com", false},
{PATTERN_9, "https://www.hello.good.com:443", false},
{PATTERN_9, "https://www.hello.good.com:443/hello/world", false},
{PATTERN_9, "http://www.hello.good.com/hello/world", false},
{PATTERN_9, "http://www.hello.good.com/hello/world?key=value", false},
{PATTERN_9, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_9, "http://www.hello.good.com:80/hello/world", false},
{PATTERN_9, "http://www.hello.good.com:80/hello/world?key=value", false},
{PATTERN_9, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_9, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
{PATTERN_9, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
{PATTERN_9, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_9, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},
//random subdomain with trailing slash, same as previous in different format
{PATTERN_10, "http://www.hello.good.com", true},
{PATTERN_10, "http://www.hello.good.com/", true},
{PATTERN_10, "http://www.hello.good.com:80", true},
{PATTERN_10, "http://www.hello.good.com:80/", true},
{PATTERN_10, "http://www.hello.good.com:80/hello/world", false},
{PATTERN_10, "https://www.hello.good.com", false},
{PATTERN_10, "https://www.hello.good.com:443", false},
{PATTERN_10, "https://www.hello.good.com:443/hello/world", false},
{PATTERN_10, "http://www.hello.good.com/hello/world", false},
{PATTERN_10, "http://www.hello.good.com/hello/world?key=value", false},
{PATTERN_10, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_10, "http://www.hello.good.com:80/hello/world", false},
{PATTERN_10, "http://www.hello.good.com:80/hello/world?key=value", false},
{PATTERN_10, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_10, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
{PATTERN_10, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
{PATTERN_10, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_10, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},
//random subdomain, default port, indeterminable length path, no question marks
{PATTERN_11, "http://www.hello.good.com", true},
{PATTERN_11, "http://www.hello.good.com:80", true},
{PATTERN_11, "http://www.hello.good.com:80/hello/world", true},
{PATTERN_11, "https://www.hello.good.com", false},
{PATTERN_11, "https://www.hello.good.com:443", false},
{PATTERN_11, "https://www.hello.good.com:443/hello/world", false},
{PATTERN_11, "http://www.hello.good.com/hello/world", true},
{PATTERN_11, "http://www.hello.good.com/hello/world?key=value", false},
{PATTERN_11, "http://www.hello.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_11, "http://www.hello.good.com:80/hello/world", true},
{PATTERN_11, "http://www.hello.good.com:80/hello/world?key=value", false},
{PATTERN_11, "http://www.hello.good.com:80/hello/world?key=value&key2=value2", false},
{PATTERN_11, "http://www.hello.bad.com:/hello/world/.good.com:80", false},
{PATTERN_11, "http://www.hello.bad.com/hello/world/.good.com:80/hello/world", false},
{PATTERN_11, "http://www.hello.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_11, "http://www.hello.bad.com:80/hello/world/.good.com:80/hello/world", false},
//random subdomain, random port random path of indeterminable length, no question marks
{PATTERN_12, "https://www.good.com", false},
{PATTERN_12, "https://www.good.com/", false},
{PATTERN_12, "https://www.good.com:443", false},
{PATTERN_12, "https://www.good.com:443/", false},
{PATTERN_12, "http://www.hello.good.com/path/", false},
{PATTERN_12, "https://www.hello.good.com/path/", true},
{PATTERN_12, "https://www.hello.good.com/", true},
{PATTERN_12, "https://www.hello.good.com", true},
{PATTERN_12, "https://www.good.com:443/path/", false},
{PATTERN_12, "https://www.subdomain.good.com:443/path/", true},
{PATTERN_12, "https://www.bad.com/.good.com:443/evil", false},
{PATTERN_12, "https://www.hello.good.com:80/path/", true},
{PATTERN_12, "https://www.bad.com:443/.good.com:443/evil", false},
//testing single-level wildcards. After the (random) port, should have a single level before blah
{PATTERN_13, "https://www.one.good.com", false},
{PATTERN_13, "https://www.one.good.com:80", false},
{PATTERN_13, "https://www.good.com/bad", false},
{PATTERN_13, "https://www.bad.com/.good.com", false},
{PATTERN_13, "https://www.one.good.com/hello/blah", true},
{PATTERN_13, "https://www.one.good.com/hello/world/blah", false},
{PATTERN_13, "https://www.one.good.com/hello/world/also/more/blah", false},
//allows for anything which contains a question mark in it, regardless of scheme, host or port
{PATTERN_14, "http://www.good.com", false},
{PATTERN_14, "http://www.good.com:80", false},
{PATTERN_14, "http://www.good.com:80/hello/world", false},
{PATTERN_14, "https://www.good.com", false},
{PATTERN_14, "https://www.good.com:443", false},
{PATTERN_14, "https://www.good.com:443/hello/world", false},
{PATTERN_14, "http://www.good.com/hello/world", false},
{PATTERN_14, "http://www.good.com/hello/world?key=value", true},
{PATTERN_14, "http://www.good.com/hello/world?key=value&key2=value2", true},
{PATTERN_14, "http://www.good.com:80/hello/world", false},
{PATTERN_14, "http://www.good.com:80/hello/world?", true},
{PATTERN_14, "http://www.good.com:80/hello/world?key=value", true},
{PATTERN_14, "http://www.good.com:80/hello/world?key=value&key2=value2", true},
{PATTERN_14, "http://www.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_14, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
//random subdomain, default port, any length path with question mark
{PATTERN_15, "http://www.good.com", false},
{PATTERN_15, "http://www.good.com:80", false},
{PATTERN_15, "http://www.good.com:80/hello/world", false},
{PATTERN_15, "https://www.good.com", false},
{PATTERN_15, "https://www.good.com:443", false},
{PATTERN_15, "https://www.good.com:443/hello/world", false},
{PATTERN_15, "http://www.good.com/hello/world", false},
{PATTERN_15, "http://www.good.com/hello/world?key=value", true},
{PATTERN_15, "http://www.good.com/hello/world?key=value&key2=value2", true},
{PATTERN_15, "http://www.good.com:80/hello/world", false},
{PATTERN_15, "http://www.good.com:80/hello/world?key=value", true},
{PATTERN_15, "http://www.good.com:80/hello/world?key=value&key2=value2", true},
{PATTERN_15, "http://www.good.com:80/hello/good/bye/world?key=value&key2=value2", true},
{PATTERN_15, "http://www.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_15, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
{PATTERN_16, "http://www.good.com", false},
{PATTERN_16, "http://www.good.com:80", false},
{PATTERN_16, "http://www.good.com:80/hello/world", false},
{PATTERN_16, "http://www.good.com:80/abc/world", false},
{PATTERN_16, "http://www.good.com:80/abc", false},
{PATTERN_16, "http://www.good.com/abc", false},
{PATTERN_16, "https://www.good.com", false},
{PATTERN_16, "https://www.good.com:443", false},
{PATTERN_16, "http://www.good.com/hello/world", false},
{PATTERN_16, "http://www.good.com/hello/world?key=value", false},
{PATTERN_16, "http://www.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_16, "http://www.good.com:80/hello/world", false},
{PATTERN_16, "http://www.good.com:80/hello/world?key=value", false},
{PATTERN_16, "http://www.good.com:80/abc/world?key=value&key2=value2", false},
{PATTERN_16, "http://www.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_16, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
{PATTERN_16, "/abc", true},
{PATTERN_16, "/acb/def/blah", false},
{PATTERN_16, "/abc/def/blah", true},
//wildcard after port
{PATTERN_17, "http://www.good.com", true},
{PATTERN_17, "http://www.good.com:80", true},
{PATTERN_17, "http://www.good.com:808", true},
{PATTERN_17, "http://www.good.com:808/", true},
{PATTERN_17, "http://www.good.com:808/asdf", false},
{PATTERN_17, "http://www.good.com:80/hello/world", false},
{PATTERN_17, "http://www.good.com:80/abc/world", false},
{PATTERN_17, "http://www.good.com:80/abc", false},
{PATTERN_17, "http://www.good.com/abc", false},
{PATTERN_17, "https://www.good.com", false},
{PATTERN_17, "https://www.good.com:443", false},
{PATTERN_17, "http://www.good.com/hello/world", false},
{PATTERN_17, "http://www.good.com/hello/world?key=value", false},
{PATTERN_17, "http://www.good.com/hello/world?key=value&key2=value2", false},
{PATTERN_17, "http://www.good.com:80/hello/world?key=value", false},
{PATTERN_17, "http://www.good.com:80/abc/world?key=value&key2=value2", false},
{PATTERN_17, "http://www.bad.com:80/hello/world/.good.com:80", false},
{PATTERN_17, "http://www.bad.com:80/hello/world/.good.com:80/hello/world", false},
//any subdomain, any path
{PATTERN_18, "https://www.good.com", false},
{PATTERN_18, "https://www.good.com/", false},
{PATTERN_18, "https://www.bad.good.com/", true},
{PATTERN_18, "https://www.good.com:443", false},
{PATTERN_18, "https://www.good.com:443/", false},
{PATTERN_18, "http://www.hello.good.com/path/", false},
{PATTERN_18, "https://www.hello.good.com/path/", true},
{PATTERN_18, "https://www.good.com:443/path/", false},
{PATTERN_18, "https://www.subdomain.good.com:443/path/", true},
{PATTERN_18, "https://www.bad.com/.good.com:443/evil", false},
{PATTERN_18, "https://www.hello.good.com:80/path/", false},
{PATTERN_18, "https://www.bad.com:443/.good.com:443/evil", false},
//continuation after "asdf"
{PATTERN_19, "https://www.good.com", false},
{PATTERN_19, "https://www.good.com/", false},
{PATTERN_19, "https://www.bad.good.com/", false},
{PATTERN_19, "https://www.good.com:443", false},
{PATTERN_19, "https://www.good.com:443/", false},
{PATTERN_19, "http://www.hello.good.com/path/", false},
{PATTERN_19, "https://www.hello.good.com/path/", false},
{PATTERN_19, "https://www.good.com:443/path/", false},
{PATTERN_19, "https://www.subdomain.good.com:443/path/", false},
{PATTERN_19, "https://www.bad.com/.good.com:443/evil", false},
{PATTERN_19, "http://www.hello.good.com:80/asdf123/path/blah", false},
{PATTERN_19, "https://www.good.com:443/asdf123/blah", true},
{PATTERN_19, "https://www.good.com:443/asdf123/456/blah", true},
{PATTERN_19, "https://www.bad.com:443/.good.com:443/evil", false},
//continuation after "asdf" stops at first slash
{PATTERN_20, "https://www.good.com:443/asdf123/blah", true},
{PATTERN_20, "https://www.good.com:443/asdf123/456/blah", false},
//any levels before hello, with query params
{PATTERN_21, "http://www.good.com", false},
{PATTERN_21, "http://www.good.com:80", false},
{PATTERN_21, "http://www.good.com:80/hello/bob/hello/?bob=bob", false},
{PATTERN_21, "http://www.good.com:80/hello/bob/hello?bob=bob", true},
{PATTERN_21, "http://www.good.com:80/hello/hello?bob=bob", true},
{PATTERN_21, "http://www.good.com:80/hello/bob?bob=bob", false},
{PATTERN_21, "http://www.good.com:80/hello/world/", false},
{PATTERN_21, "http://www.good.com:80/hello/world", false},
{PATTERN_21, "http://www.good.com:80/hello/?bob=bob", false},
//optional path-element before question mark, exactly two levels before that
{PATTERN_22, "http://www.good.com", false},
{PATTERN_22, "http://www.good.com:80", false},
{PATTERN_22, "http://www.good.com:80/hello/bob/hello?bob=bob", true},
{PATTERN_22, "http://www.good.com:80/hello/bob/hello/?bob=bob", true},
{PATTERN_22, "http://www.good.com:80/hello/bob/hello/again?bob=bob", false},
{PATTERN_22, "http://www.good.com:80/hello/bob/hello/again/and/again?bob=bob", false},
{PATTERN_22, "http://www.good.com:80/hello/bob/?bob=bob", true},
{PATTERN_22, "http://www.good.com:80/hello/bob?bob=bob", true},
{PATTERN_22, "http://www.good.com:80/hello?bob=bob", false},
{PATTERN_22, "http://www.good.com:80/hello/world/", false},
{PATTERN_22, "http://www.good.com:80/hello/world", false},
{PATTERN_22, "http://www.good.com:80/hello/?bob=bob", false},
//optional path-element before question mark, two (or more) levels before that (but not fewer)
{PATTERN_23, "http://www.good.com", false},
{PATTERN_23, "http://www.good.com:80", false},
{PATTERN_23, "http://www.good.com:80/hello/bob/hello?bob=bob", true},
{PATTERN_23, "http://www.good.com:80/hello/bob/hello/?bob=bob", true},
{PATTERN_23, "http://www.good.com:80/hello/bob/hello/again?bob=bob", true},
{PATTERN_23, "http://www.good.com:80/hello/bob/hello/again/and/again?bob=bob", true},
{PATTERN_23, "http://www.good.com:80/hello/bob/?bob=bob", true},
{PATTERN_23, "http://www.good.com:80/hello/bob?bob=bob", false},
{PATTERN_23, "http://www.good.com:80/hello?bob=bob", false},
{PATTERN_23, "http://www.good.com:80/hello/world/", false},
{PATTERN_23, "http://www.good.com:80/hello/world", false},
{PATTERN_23, "http://www.good.com:80/hello/?bob=bob", false}
};
}
}