Created
September 23, 2019 01:53
-
-
Save swankjesse/28341b3e3f6c357c5fde12c4e1327fd7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2009 The Guava Authors | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package okhttp3; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.LinkedHashSet; | |
import java.util.List; | |
import java.util.Set; | |
import java.util.regex.Pattern; | |
import junit.framework.TestCase; | |
import okio.ByteString; | |
import org.junit.AssumptionViolatedException; | |
/** | |
* Guava's InternetDomainNameTest, adapted to exercise OkHttp's HttpUrl class. | |
* | |
* @author Craig Berry | |
*/ | |
public final class InternetDomainNameTest extends TestCase { | |
private static final InternetDomainName UNICODE_EXAMPLE = | |
InternetDomainName.from("j\u00f8rpeland.no"); | |
private static final InternetDomainName PUNYCODE_EXAMPLE = | |
InternetDomainName.from("xn--jrpeland-54a.no"); | |
/** The Greek letter delta, used in unicode testing. */ | |
private static final String DELTA = "\u0394"; | |
/** A domain part which is valid under lenient validation, but invalid under strict validation. */ | |
static final String LOTS_OF_DELTAS = TestUtil.repeat(DELTA, 62); | |
private static final String ALMOST_TOO_MANY_LEVELS = TestUtil.repeat("a.", 127); | |
private static final String ALMOST_TOO_LONG = TestUtil.repeat("aaaaa.", 40) + "1234567890.c"; | |
private static final Set<String> VALID_NAME = | |
setOf( | |
"foo.com", | |
"f-_-o.cOM", | |
"f--1.com", | |
"f11-1.com", | |
"www", | |
"abc.a23", | |
"biz.com.ua", | |
"x", | |
"fOo", | |
"f--o", | |
"f_a", | |
"foo.net.us\uFF61ocm", | |
"woo.com.", | |
"8server.shop", | |
"123.cn", | |
"a" + DELTA + "b.com", | |
ALMOST_TOO_MANY_LEVELS, | |
ALMOST_TOO_LONG); | |
private static final Set<String> INVALID_NAME = | |
setOf( | |
"", | |
" ", | |
"127.0.0.1", | |
"::1", | |
"13", | |
"abc.12c", | |
"foo-.com", | |
"_bar.quux", | |
"foo+bar.com", | |
"foo!bar.com", | |
".foo.com", | |
"..bar.com", | |
"baz..com", | |
"..quiffle.com", | |
"fleeb.com..", | |
".", | |
"..", | |
"...", | |
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com", | |
"a" + DELTA + " .com", | |
ALMOST_TOO_MANY_LEVELS + "com", | |
ALMOST_TOO_LONG + ".c"); | |
private static final Set<String> RS = | |
setOf( | |
"com", | |
"co.uk", | |
"foo.bd", | |
"xxxxxx.bd", | |
"org.mK", | |
"us", | |
//"co.uk.", // Trailing dot | |
"co\uFF61uk", // Alternate dot character | |
"\u7f51\u7edc.Cn", // "网络.Cn" | |
"j\u00f8rpeland.no", // "jorpeland.no" (first o slashed) | |
"xn--jrpeland-54a.no"); // IDNA (punycode) encoding of above | |
private static final Set<String> PS_NOT_RS = | |
setOf("blogspot.com", "blogspot.co.uk", "uk.com"); | |
private static final Set<String> PS; | |
static { | |
Set<String> set = new LinkedHashSet<>(); | |
set.addAll(RS); | |
set.addAll(PS_NOT_RS); | |
PS = set; | |
} | |
private static final Set<String> NO_PS = | |
setOf("www", "foo.ihopethiswillneverbeapublicsuffix", "x.y.z"); | |
/** | |
* Having a public suffix is equivalent to having a registry suffix, because all registry suffixes | |
* are public suffixes, and all public suffixes have registry suffixes. | |
*/ | |
private static final Set<String> NO_RS = NO_PS; | |
private static final Set<String> NON_PS = | |
setOf( | |
"foo.bar.com", | |
"foo.ca", | |
"foo.bar.ca", | |
"foo.blogspot.com", | |
"foo.blogspot.co.uk", | |
"foo.uk.com", | |
"foo.bar.co.il", | |
"state.CA.us", | |
"www.state.pa.us", | |
"pvt.k12.ca.us", | |
"www.google.com", | |
"www4.yahoo.co.uk", | |
"home.netscape.com", | |
"web.MIT.edu", | |
"foo.eDu.au", | |
"utenti.blah.IT", | |
"dominio.com.co"); | |
private static final Set<String> NON_RS; | |
static { | |
Set<String> set = new LinkedHashSet<>(); | |
set.addAll(NON_PS); | |
set.addAll(PS_NOT_RS); | |
NON_RS = set; | |
} | |
private static final Set<String> TOP_UNDER_REGISTRY_SUFFIX = | |
setOf("google.com", "foo.Co.uk", "foo.ca.us."); | |
private static final Set<String> TOP_PRIVATE_DOMAIN = | |
setOf("google.com", "foo.Co.uk", "foo.ca.us.", "foo.blogspot.com"); | |
private static final Set<String> UNDER_TOP_UNDER_REGISTRY_SUFFIX = | |
setOf("foo.bar.google.com", "a.b.co.uk", "x.y.ca.us"); | |
private static final Set<String> UNDER_PRIVATE_DOMAIN = | |
setOf("foo.bar.google.com", "a.b.co.uk", "x.y.ca.us", "a.b.blogspot.com"); | |
private static final Set<String> VALID_IP_ADDRS = | |
setOf("1.2.3.4", "127.0.0.1", "::1", "2001:db8::1"); | |
private static final Set<String> INVALID_IP_ADDRS = | |
setOf( | |
"", "1", "1.2.3", "...", "1.2.3.4.5", "400.500.600.700", ":", ":::1", "2001:db8:"); | |
private static final Set<String> SOMEWHERE_UNDER_PS = | |
setOf( | |
"foo.bar.google.com", | |
"a.b.c.1.2.3.ca.us", | |
"site.jp", | |
"uomi-online.kir.jp", | |
"jprs.co.jp", | |
"site.quick.jp", | |
"site.tenki.jp", | |
"site.or.jp", | |
"site.gr.jp", | |
"site.ne.jp", | |
"site.ac.jp", | |
"site.ad.jp", | |
"site.ed.jp", | |
"site.geo.jp", | |
"site.go.jp", | |
"site.lg.jp", | |
"1.fm", | |
"site.cc", | |
"site.ee", | |
"site.fi", | |
"site.fm", | |
"site.gr", | |
"www.leguide.ma", | |
"site.ma", | |
"some.org.mk", | |
"site.mk", | |
"site.tv", | |
"site.us", | |
"www.odev.us", | |
"www.GOOGLE.com", | |
"www.com", | |
"google.com", | |
"www7.google.co.uk", | |
"google.Co.uK", | |
"jobs.kt.com.", | |
"home.netscape.com", | |
"web.stanford.edu", | |
"stanford.edu", | |
"state.ca.us", | |
"www.state.ca.us", | |
"state.ca.us", | |
"pvt.k12.ca.us", | |
"www.rave.ca.", | |
"cnn.ca", | |
"ledger-enquirer.com", | |
"it-trace.ch", | |
"cool.dk", | |
"cool.co.uk", | |
"cool.de", | |
"cool.es", | |
"cool\uFF61fr", // Alternate dot character | |
"cool.nl", | |
"members.blah.nl.", | |
"cool.se", | |
"utenti.blah.it", | |
"kt.co", | |
"a\u7f51\u7edcA.\u7f51\u7edc.Cn" // "a网络A.网络.Cn" | |
); | |
private static final Set<String> SOMEWHERE_UNDER_RS; | |
static { | |
Set<String> set = new LinkedHashSet<>(); | |
set.addAll(SOMEWHERE_UNDER_PS); | |
set.addAll(PS_NOT_RS); | |
SOMEWHERE_UNDER_RS = set; | |
} | |
public void testValid() { | |
for (String name : VALID_NAME) { | |
InternetDomainName.from(name); | |
} | |
} | |
public void testInvalid() { | |
for (String name : INVALID_NAME) { | |
try { | |
InternetDomainName.from(name); | |
System.out.println("Should have been invalid: '" + name + "'"); | |
} catch (IllegalArgumentException expected) { | |
} | |
} | |
} | |
public void testPublicSuffix() { | |
for (String name : PS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertTrue(name, domain.isPublicSuffix()); | |
assertTrue(name, domain.hasPublicSuffix()); | |
assertFalse(name, domain.isUnderPublicSuffix()); | |
assertFalse(name, domain.isTopPrivateDomain()); | |
assertEquals(domain, domain.publicSuffix()); | |
} | |
for (String name : NO_PS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isPublicSuffix()); | |
assertFalse(name, domain.hasPublicSuffix()); | |
assertFalse(name, domain.isUnderPublicSuffix()); | |
assertFalse(name, domain.isTopPrivateDomain()); | |
assertNull(domain.publicSuffix()); | |
} | |
for (String name : NON_PS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isPublicSuffix()); | |
assertTrue(name, domain.hasPublicSuffix()); | |
assertTrue(name, domain.isUnderPublicSuffix()); | |
} | |
} | |
public void testUnderPublicSuffix() { | |
for (String name : SOMEWHERE_UNDER_PS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isPublicSuffix()); | |
assertTrue(name, domain.hasPublicSuffix()); | |
assertTrue(name, domain.isUnderPublicSuffix()); | |
} | |
} | |
public void testTopPrivateDomain() { | |
for (String name : TOP_PRIVATE_DOMAIN) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isPublicSuffix()); | |
assertTrue(name, domain.hasPublicSuffix()); | |
assertTrue(name, domain.isUnderPublicSuffix()); | |
assertTrue(name, domain.isTopPrivateDomain()); | |
assertEquals(domain.parent(), domain.publicSuffix()); | |
} | |
} | |
public void testUnderPrivateDomain() { | |
for (String name : UNDER_PRIVATE_DOMAIN) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isPublicSuffix()); | |
assertTrue(name, domain.hasPublicSuffix()); | |
assertTrue(name, domain.isUnderPublicSuffix()); | |
assertFalse(name, domain.isTopPrivateDomain()); | |
} | |
} | |
public void testRegistrySuffix() { | |
for (String name : RS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertTrue(name, domain.isRegistrySuffix()); | |
assertTrue(name, domain.hasRegistrySuffix()); | |
assertFalse(name, domain.isUnderRegistrySuffix()); | |
assertFalse(name, domain.isTopDomainUnderRegistrySuffix()); | |
assertEquals(domain, domain.registrySuffix()); | |
} | |
for (String name : NO_RS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isRegistrySuffix()); | |
assertFalse(name, domain.hasRegistrySuffix()); | |
assertFalse(name, domain.isUnderRegistrySuffix()); | |
assertFalse(name, domain.isTopDomainUnderRegistrySuffix()); | |
assertNull(domain.registrySuffix()); | |
} | |
for (String name : NON_RS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isRegistrySuffix()); | |
assertTrue(name, domain.hasRegistrySuffix()); | |
assertTrue(name, domain.isUnderRegistrySuffix()); | |
} | |
} | |
public void testUnderRegistrySuffix() { | |
for (String name : SOMEWHERE_UNDER_RS) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isRegistrySuffix()); | |
assertTrue(name, domain.hasRegistrySuffix()); | |
assertTrue(name, domain.isUnderRegistrySuffix()); | |
} | |
} | |
public void testTopDomainUnderRegistrySuffix() { | |
for (String name : TOP_UNDER_REGISTRY_SUFFIX) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isRegistrySuffix()); | |
assertTrue(name, domain.hasRegistrySuffix()); | |
assertTrue(name, domain.isUnderRegistrySuffix()); | |
assertTrue(name, domain.isTopDomainUnderRegistrySuffix()); | |
assertEquals(domain.parent(), domain.registrySuffix()); | |
} | |
} | |
public void testUnderTopDomainUnderRegistrySuffix() { | |
for (String name : UNDER_TOP_UNDER_REGISTRY_SUFFIX) { | |
final InternetDomainName domain = InternetDomainName.from(name); | |
assertFalse(name, domain.isRegistrySuffix()); | |
assertTrue(name, domain.hasRegistrySuffix()); | |
assertTrue(name, domain.isUnderRegistrySuffix()); | |
assertFalse(name, domain.isTopDomainUnderRegistrySuffix()); | |
} | |
} | |
public void testParent() { | |
assertEquals("com", InternetDomainName.from("google.com").parent().toString()); | |
assertEquals("uk", InternetDomainName.from("co.uk").parent().toString()); | |
assertEquals("google.com", InternetDomainName.from("www.google.com").parent().toString()); | |
try { | |
InternetDomainName.from("com").parent(); | |
fail("'com' should throw ISE on .parent() call"); | |
} catch (IllegalStateException expected) { | |
} | |
} | |
public void testChild() { | |
InternetDomainName domain = InternetDomainName.from("foo.com"); | |
assertEquals("www.foo.com", domain.child("www").toString()); | |
try { | |
domain.child("www."); | |
fail("www..google.com should have been invalid"); | |
} catch (IllegalArgumentException expected) { | |
} | |
} | |
public void testParentChild() { | |
InternetDomainName origin = InternetDomainName.from("foo.com"); | |
InternetDomainName parent = origin.parent(); | |
assertEquals("com", parent.toString()); | |
// These would throw an exception if leniency were not preserved during parent() and child() | |
// calls. | |
InternetDomainName child = parent.child(LOTS_OF_DELTAS); | |
child.child(LOTS_OF_DELTAS); | |
} | |
public void testValidTopPrivateDomain() { | |
InternetDomainName googleDomain = InternetDomainName.from("google.com"); | |
assertEquals(googleDomain, googleDomain.topPrivateDomain()); | |
assertEquals(googleDomain, googleDomain.child("mail").topPrivateDomain()); | |
assertEquals(googleDomain, googleDomain.child("foo.bar").topPrivateDomain()); | |
} | |
public void testInvalidTopPrivateDomain() { | |
Set<String> badCookieDomains = setOf("co.uk", "foo", "com"); | |
for (String domain : badCookieDomains) { | |
try { | |
InternetDomainName.from(domain).topPrivateDomain(); | |
fail(domain); | |
} catch (IllegalStateException expected) { | |
} | |
} | |
} | |
public void testIsValid() { | |
final Iterable<String> validCases = concat(VALID_NAME, PS, NO_PS, NON_PS); | |
final Iterable<String> invalidCases = | |
concat(INVALID_NAME, VALID_IP_ADDRS, INVALID_IP_ADDRS); | |
for (String valid : validCases) { | |
assertTrue(valid, InternetDomainName.isValid(valid)); | |
} | |
for (String invalid : invalidCases) { | |
assertFalse(invalid, InternetDomainName.isValid(invalid)); | |
} | |
} | |
public void testToString() { | |
for (String inputName : SOMEWHERE_UNDER_PS) { | |
InternetDomainName domain = InternetDomainName.from(inputName); | |
/* | |
* We would ordinarily use constants for the expected results, but | |
* doing it by derivation allows us to reuse the test case definitions | |
* used in other tests. | |
*/ | |
String expectedName = ByteString.encodeUtf8(inputName).toAsciiLowercase().utf8(); | |
expectedName = expectedName.replaceAll("[\u3002\uFF0E\uFF61]", "."); | |
if (expectedName.endsWith(".")) { | |
expectedName = expectedName.substring(0, expectedName.length() - 1); | |
} | |
assertEquals(expectedName, domain.toString()); | |
} | |
} | |
public void testPublicSuffixExclusion() { | |
InternetDomainName domain = InternetDomainName.from("foo.city.yokohama.jp"); | |
assertTrue(domain.hasPublicSuffix()); | |
assertEquals("yokohama.jp", domain.publicSuffix().toString()); | |
// Behold the weirdness! | |
assertFalse(domain.publicSuffix().isPublicSuffix()); | |
} | |
public void testPublicSuffixMultipleUnders() { | |
// PSL has both *.uk and *.sch.uk; the latter should win. | |
// See http://code.google.com/p/guava-libraries/issues/detail?id=1176 | |
InternetDomainName domain = InternetDomainName.from("www.essex.sch.uk"); | |
assertTrue(domain.hasPublicSuffix()); | |
assertEquals("essex.sch.uk", domain.publicSuffix().toString()); | |
assertEquals("www.essex.sch.uk", domain.topPrivateDomain().toString()); | |
} | |
public void testRegistrySuffixExclusion() { | |
InternetDomainName domain = InternetDomainName.from("foo.city.yokohama.jp"); | |
assertTrue(domain.hasRegistrySuffix()); | |
assertEquals("yokohama.jp", domain.registrySuffix().toString()); | |
// Behold the weirdness! | |
assertFalse(domain.registrySuffix().isRegistrySuffix()); | |
} | |
public void testName() { | |
assertNull(HttpUrl.parse("https://foo.www/").topPrivateDomain()); | |
} | |
public void testRegistrySuffixMultipleUnders() { | |
// PSL has both *.uk and *.sch.uk; the latter should win. | |
// See http://code.google.com/p/guava-libraries/issues/detail?id=1176 | |
InternetDomainName domain = InternetDomainName.from("www.essex.sch.uk"); | |
assertTrue(domain.hasRegistrySuffix()); | |
assertEquals("essex.sch.uk", domain.registrySuffix().toString()); | |
assertEquals("www.essex.sch.uk", domain.topDomainUnderRegistrySuffix().toString()); | |
} | |
private static InternetDomainName idn(String domain) { | |
return InternetDomainName.from(domain); | |
} | |
static Set<String> setOf(String... elements) { | |
return new LinkedHashSet<>(Arrays.asList(elements)); | |
} | |
static <T> Collection<T> concat(Collection<T>... collections) { | |
List<T> result = new ArrayList<>(); | |
for (Collection<T> set : collections) { | |
result.addAll(set); | |
} | |
return result; | |
} | |
static class InternetDomainName { | |
private static final Pattern VERIFY_AS_IP_ADDRESS = | |
Pattern.compile("([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)"); | |
private final HttpUrl httpUrl; | |
public InternetDomainName(HttpUrl httpUrl) { | |
this.httpUrl = httpUrl; | |
} | |
public static InternetDomainName from(String name) { | |
if (VERIFY_AS_IP_ADDRESS.matcher(name).matches()) { | |
throw new IllegalArgumentException(); | |
} | |
HttpUrl httpUrl = new HttpUrl.Builder() | |
.scheme("https") | |
.host(name) | |
.build(); | |
return new InternetDomainName(httpUrl); | |
} | |
public static boolean isValid(String name) { | |
try { | |
from(name); | |
return true; | |
} catch (IllegalArgumentException e) { | |
return false; | |
} | |
} | |
public boolean isPublicSuffix() { | |
return child("foo").isTopPrivateDomain(); | |
} | |
public boolean hasPublicSuffix() { | |
return isUnderPublicSuffix() || isPublicSuffix(); | |
} | |
public boolean isUnderPublicSuffix() { | |
return httpUrl.topPrivateDomain() != null; | |
} | |
public boolean isTopPrivateDomain() { | |
return httpUrl.host().equals(httpUrl.topPrivateDomain()); | |
} | |
public InternetDomainName publicSuffix() { | |
if (isPublicSuffix()) return from(httpUrl.host()); | |
String topPrivateDomain = httpUrl.topPrivateDomain(); | |
if (topPrivateDomain == null) return null; | |
int dot = topPrivateDomain.indexOf('.'); | |
if (dot == -1) return null; | |
return from(topPrivateDomain.substring(dot + 1)); | |
} | |
public InternetDomainName parent() { | |
String host = httpUrl.host(); | |
int dot = host.indexOf('.'); | |
if (dot == -1) throw new IllegalStateException(); | |
return from(host.substring(dot + 1)); | |
} | |
public InternetDomainName child(String leftParts) { | |
return from(leftParts + "." + httpUrl.host()); | |
} | |
public InternetDomainName topPrivateDomain() { | |
String topPrivateDomain = httpUrl.topPrivateDomain(); | |
if (topPrivateDomain == null) throw new IllegalStateException(); | |
return from(topPrivateDomain); | |
} | |
public boolean isRegistrySuffix() { | |
throw new AssumptionViolatedException("not implemented"); | |
} | |
public boolean hasRegistrySuffix() { | |
throw new AssumptionViolatedException("not implemented"); | |
} | |
public boolean isUnderRegistrySuffix() { | |
throw new AssumptionViolatedException("not implemented"); | |
} | |
public boolean isTopDomainUnderRegistrySuffix() { | |
throw new AssumptionViolatedException("not implemented"); | |
} | |
public InternetDomainName registrySuffix() { | |
throw new AssumptionViolatedException("not implemented"); | |
} | |
public InternetDomainName topDomainUnderRegistrySuffix() { | |
throw new AssumptionViolatedException("not implemented"); | |
} | |
@Override public boolean equals(Object o) { | |
return o instanceof InternetDomainName && ((InternetDomainName) o).httpUrl.equals(httpUrl); | |
} | |
@Override public int hashCode() { | |
return httpUrl.hashCode(); | |
} | |
@Override public String toString() { | |
return httpUrl.host(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment