Coverage Summary for Class: InternetDomainName (com.google.common.net)
| Class | Class, % | Method, % | Line, % |
|---|---|---|---|
| InternetDomainName | 0% (0/1) | 0% (0/29) | 0% (0/91) |
1 /* 2 * Copyright (C) 2009 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package com.google.common.net; 16 17 import static com.google.common.base.Preconditions.checkArgument; 18 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkState; 20 21 import com.google.common.annotations.Beta; 22 import com.google.common.annotations.GwtCompatible; 23 import com.google.common.base.Ascii; 24 import com.google.common.base.CharMatcher; 25 import com.google.common.base.Joiner; 26 import com.google.common.base.Optional; 27 import com.google.common.base.Splitter; 28 import com.google.common.collect.ImmutableList; 29 import com.google.errorprone.annotations.Immutable; 30 import com.google.thirdparty.publicsuffix.PublicSuffixPatterns; 31 import com.google.thirdparty.publicsuffix.PublicSuffixType; 32 import java.util.List; 33 import javax.annotation.CheckForNull; 34 35 /** 36 * An immutable well-formed internet domain name, such as {@code com} or {@code foo.co.uk}. Only 37 * syntactic analysis is performed; no DNS lookups or other network interactions take place. Thus 38 * there is no guarantee that the domain actually exists on the internet. 39 * 40 * <p>One common use of this class is to determine whether a given string is likely to represent an 41 * addressable domain on the web -- that is, for a candidate string {@code "xxx"}, might browsing to 42 * {@code "http://xxx/"} result in a webpage being displayed? In the past, this test was frequently 43 * done by determining whether the domain ended with a {@linkplain #isPublicSuffix() public suffix} 44 * but was not itself a public suffix. However, this test is no longer accurate. There are many 45 * domains which are both public suffixes and addressable as hosts; {@code "uk.com"} is one example. 46 * Using the subset of public suffixes that are {@linkplain #isRegistrySuffix() registry suffixes}, 47 * one can get a better result, as only a few registry suffixes are addressable. However, the most 48 * useful test to determine if a domain is a plausible web host is {@link #hasPublicSuffix()}. This 49 * will return {@code true} for many domains which (currently) are not hosts, such as {@code "com"}, 50 * but given that any public suffix may become a host without warning, it is better to err on the 51 * side of permissiveness and thus avoid spurious rejection of valid sites. Of course, to actually 52 * determine addressability of any host, clients of this class will need to perform their own DNS 53 * lookups. 54 * 55 * <p>During construction, names are normalized in two ways: 56 * 57 * <ol> 58 * <li>ASCII uppercase characters are converted to lowercase. 59 * <li>Unicode dot separators other than the ASCII period ({@code '.'}) are converted to the ASCII 60 * period. 61 * </ol> 62 * 63 * <p>The normalized values will be returned from {@link #toString()} and {@link #parts()}, and will 64 * be reflected in the result of {@link #equals(Object)}. 65 * 66 * <p><a href="http://en.wikipedia.org/wiki/Internationalized_domain_name">Internationalized domain 67 * names</a> such as {@code ??.cn} are supported, as are the equivalent <a 68 * href="http://en.wikipedia.org/wiki/Internationalized_domain_name">IDNA Punycode-encoded</a> 69 * versions. 70 * 71 * @author Catherine Berry 72 * @since 5.0 73 */ 74 @Beta 75 @GwtCompatible(emulated = true) 76 @Immutable 77 // TODO(b/147136275): After adding @CheckForNull below, add @ElementTypesAreNonnullByDefault. 78 public final class InternetDomainName { 79 80 private static final CharMatcher DOTS_MATCHER = CharMatcher.anyOf(".\u3002\uFF0E\uFF61"); 81 private static final Splitter DOT_SPLITTER = Splitter.on('.'); 82 private static final Joiner DOT_JOINER = Joiner.on('.'); 83 84 /** 85 * Value of {@link #publicSuffixIndex} or {@link #registrySuffixIndex} which indicates that no 86 * relevant suffix was found. 87 */ 88 private static final int NO_SUFFIX_FOUND = -1; 89 90 /** 91 * Maximum parts (labels) in a domain name. This value arises from the 255-octet limit described 92 * in <a href="http://www.ietf.org/rfc/rfc2181.txt">RFC 2181</a> part 11 with the fact that the 93 * encoding of each part occupies at least two bytes (dot plus label externally, length byte plus 94 * label internally). Thus, if all labels have the minimum size of one byte, 127 of them will fit. 95 */ 96 private static final int MAX_PARTS = 127; 97 98 /** 99 * Maximum length of a full domain name, including separators, and leaving room for the root 100 * label. See <a href="http://www.ietf.org/rfc/rfc2181.txt">RFC 2181</a> part 11. 101 */ 102 private static final int MAX_LENGTH = 253; 103 104 /** 105 * Maximum size of a single part of a domain name. See <a 106 * href="http://www.ietf.org/rfc/rfc2181.txt">RFC 2181</a> part 11. 107 */ 108 private static final int MAX_DOMAIN_PART_LENGTH = 63; 109 110 /** The full domain name, converted to lower case. */ 111 private final String name; 112 113 /** The parts of the domain name, converted to lower case. */ 114 private final ImmutableList<String> parts; 115 116 /** 117 * The index in the {@link #parts()} list at which the public suffix begins. For example, for the 118 * domain name {@code myblog.blogspot.co.uk}, the value would be 1 (the index of the {@code 119 * blogspot} part). The value is negative (specifically, {@link #NO_SUFFIX_FOUND}) if no public 120 * suffix was found. 121 */ 122 private final int publicSuffixIndex; 123 124 /** 125 * The index in the {@link #parts()} list at which the registry suffix begins. For example, for 126 * the domain name {@code myblog.blogspot.co.uk}, the value would be 2 (the index of the {@code 127 * co} part). The value is negative (specifically, {@link #NO_SUFFIX_FOUND}) if no registry suffix 128 * was found. 129 */ 130 private final int registrySuffixIndex; 131 132 /** Constructor used to implement {@link #from(String)}, and from subclasses. */ 133 InternetDomainName(String name) { 134 // Normalize: 135 // * ASCII characters to lowercase 136 // * All dot-like characters to '.' 137 // * Strip trailing '.' 138 139 name = Ascii.toLowerCase(DOTS_MATCHER.replaceFrom(name, '.')); 140 141 if (name.endsWith(".")) { 142 name = name.substring(0, name.length() - 1); 143 } 144 145 checkArgument(name.length() <= MAX_LENGTH, "Domain name too long: '%s':", name); 146 this.name = name; 147 148 this.parts = ImmutableList.copyOf(DOT_SPLITTER.split(name)); 149 checkArgument(parts.size() <= MAX_PARTS, "Domain has too many parts: '%s'", name); 150 checkArgument(validateSyntax(parts), "Not a valid domain name: '%s'", name); 151 152 this.publicSuffixIndex = findSuffixOfType(Optional.<PublicSuffixType>absent()); 153 this.registrySuffixIndex = findSuffixOfType(Optional.of(PublicSuffixType.REGISTRY)); 154 } 155 156 /** 157 * Returns the index of the leftmost part of the suffix, or -1 if not found. Note that the value 158 * defined as a suffix may not produce {@code true} results from {@link #isPublicSuffix()} or 159 * {@link #isRegistrySuffix()} if the domain ends with an excluded domain pattern such as {@code 160 * "nhs.uk"}. 161 * 162 * <p>If a {@code desiredType} is specified, this method only finds suffixes of the given type. 163 * Otherwise, it finds the first suffix of any type. 164 */ 165 private int findSuffixOfType(Optional<PublicSuffixType> desiredType) { 166 final int partsSize = parts.size(); 167 168 for (int i = 0; i < partsSize; i++) { 169 String ancestorName = DOT_JOINER.join(parts.subList(i, partsSize)); 170 171 if (matchesType( 172 desiredType, Optional.fromNullable(PublicSuffixPatterns.EXACT.get(ancestorName)))) { 173 return i; 174 } 175 176 // Excluded domains (e.g. !nhs.uk) use the next highest 177 // domain as the effective public suffix (e.g. uk). 178 179 if (PublicSuffixPatterns.EXCLUDED.containsKey(ancestorName)) { 180 return i + 1; 181 } 182 183 if (matchesWildcardSuffixType(desiredType, ancestorName)) { 184 return i; 185 } 186 } 187 188 return NO_SUFFIX_FOUND; 189 } 190 191 /** 192 * Returns an instance of {@link InternetDomainName} after lenient validation. Specifically, 193 * validation against <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a> 194 * ("Internationalizing Domain Names in Applications") is skipped, while validation against <a 195 * href="http://www.ietf.org/rfc/rfc1035.txt">RFC 1035</a> is relaxed in the following ways: 196 * 197 * <ul> 198 * <li>Any part containing non-ASCII characters is considered valid. 199 * <li>Underscores ('_') are permitted wherever dashes ('-') are permitted. 200 * <li>Parts other than the final part may start with a digit, as mandated by <a 201 * href="https://tools.ietf.org/html/rfc1123#section-2">RFC 1123</a>. 202 * </ul> 203 * 204 * @param domain A domain name (not IP address) 205 * @throws IllegalArgumentException if {@code domain} is not syntactically valid according to 206 * {@link #isValid} 207 * @since 10.0 (previously named {@code fromLenient}) 208 */ 209 public static InternetDomainName from(String domain) { 210 return new InternetDomainName(checkNotNull(domain)); 211 } 212 213 /** 214 * Validation method used by {@code from} to ensure that the domain name is syntactically valid 215 * according to RFC 1035. 216 * 217 * @return Is the domain name syntactically valid? 218 */ 219 private static boolean validateSyntax(List<String> parts) { 220 final int lastIndex = parts.size() - 1; 221 222 // Validate the last part specially, as it has different syntax rules. 223 224 if (!validatePart(parts.get(lastIndex), true)) { 225 return false; 226 } 227 228 for (int i = 0; i < lastIndex; i++) { 229 String part = parts.get(i); 230 if (!validatePart(part, false)) { 231 return false; 232 } 233 } 234 235 return true; 236 } 237 238 private static final CharMatcher DASH_MATCHER = CharMatcher.anyOf("-_"); 239 240 private static final CharMatcher DIGIT_MATCHER = CharMatcher.inRange('0', '9'); 241 242 private static final CharMatcher LETTER_MATCHER = 243 CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('A', 'Z')); 244 245 private static final CharMatcher PART_CHAR_MATCHER = 246 DIGIT_MATCHER.or(LETTER_MATCHER).or(DASH_MATCHER); 247 248 /** 249 * Helper method for {@link #validateSyntax(List)}. Validates that one part of a domain name is 250 * valid. 251 * 252 * @param part The domain name part to be validated 253 * @param isFinalPart Is this the final (rightmost) domain part? 254 * @return Whether the part is valid 255 */ 256 private static boolean validatePart(String part, boolean isFinalPart) { 257 258 // These tests could be collapsed into one big boolean expression, but 259 // they have been left as independent tests for clarity. 260 261 if (part.length() < 1 || part.length() > MAX_DOMAIN_PART_LENGTH) { 262 return false; 263 } 264 265 /* 266 * GWT claims to support java.lang.Character's char-classification methods, but it actually only 267 * works for ASCII. So for now, assume any non-ASCII characters are valid. The only place this 268 * seems to be documented is here: 269 * https://groups.google.com/d/topic/google-web-toolkit-contributors/1UEzsryq1XI 270 * 271 * <p>ASCII characters in the part are expected to be valid per RFC 1035, with underscore also 272 * being allowed due to widespread practice. 273 */ 274 275 String asciiChars = CharMatcher.ascii().retainFrom(part); 276 277 if (!PART_CHAR_MATCHER.matchesAllOf(asciiChars)) { 278 return false; 279 } 280 281 // No initial or final dashes or underscores. 282 283 if (DASH_MATCHER.matches(part.charAt(0)) 284 || DASH_MATCHER.matches(part.charAt(part.length() - 1))) { 285 return false; 286 } 287 288 /* 289 * Note that we allow (in contravention of a strict interpretation of the relevant RFCs) domain 290 * parts other than the last may begin with a digit (for example, "3com.com"). It's important to 291 * disallow an initial digit in the last part; it's the only thing that stops an IPv4 numeric 292 * address like 127.0.0.1 from looking like a valid domain name. 293 */ 294 295 if (isFinalPart && DIGIT_MATCHER.matches(part.charAt(0))) { 296 return false; 297 } 298 299 return true; 300 } 301 302 /** 303 * Returns the individual components of this domain name, normalized to all lower case. For 304 * example, for the domain name {@code mail.google.com}, this method returns the list {@code 305 * ["mail", "google", "com"]}. 306 */ 307 public ImmutableList<String> parts() { 308 return parts; 309 } 310 311 /** 312 * Indicates whether this domain name represents a <i>public suffix</i>, as defined by the Mozilla 313 * Foundation's <a href="http://publicsuffix.org/">Public Suffix List</a> (PSL). A public suffix 314 * is one under which Internet users can directly register names, such as {@code com}, {@code 315 * co.uk} or {@code pvt.k12.wy.us}. Examples of domain names that are <i>not</i> public suffixes 316 * include {@code google.com}, {@code foo.co.uk}, and {@code myblog.blogspot.com}. 317 * 318 * <p>Public suffixes are a proper superset of {@linkplain #isRegistrySuffix() registry suffixes}. 319 * The list of public suffixes additionally contains privately owned domain names under which 320 * Internet users can register subdomains. An example of a public suffix that is not a registry 321 * suffix is {@code blogspot.com}. Note that it is true that all public suffixes <i>have</i> 322 * registry suffixes, since domain name registries collectively control all internet domain names. 323 * 324 * <p>For considerations on whether the public suffix or registry suffix designation is more 325 * suitable for your application, see <a 326 * href="https://github.com/google/guava/wiki/InternetDomainNameExplained">this article</a>. 327 * 328 * @return {@code true} if this domain name appears exactly on the public suffix list 329 * @since 6.0 330 */ 331 public boolean isPublicSuffix() { 332 return publicSuffixIndex == 0; 333 } 334 335 /** 336 * Indicates whether this domain name ends in a {@linkplain #isPublicSuffix() public suffix}, 337 * including if it is a public suffix itself. For example, returns {@code true} for {@code 338 * www.google.com}, {@code foo.co.uk} and {@code com}, but not for {@code invalid} or {@code 339 * google.invalid}. This is the recommended method for determining whether a domain is potentially 340 * an addressable host. 341 * 342 * <p>Note that this method is equivalent to {@link #hasRegistrySuffix()} because all registry 343 * suffixes are public suffixes <i>and</i> all public suffixes have registry suffixes. 344 * 345 * @since 6.0 346 */ 347 public boolean hasPublicSuffix() { 348 return publicSuffixIndex != NO_SUFFIX_FOUND; 349 } 350 351 /** 352 * Returns the {@linkplain #isPublicSuffix() public suffix} portion of the domain name, or {@code 353 * null} if no public suffix is present. 354 * 355 * @since 6.0 356 */ 357 // TODO(b/147136275): After updating callers, add @CheckForNull, and remove @SuppressWarnings. 358 @SuppressWarnings("nullness") 359 public InternetDomainName publicSuffix() { 360 return hasPublicSuffix() ? ancestor(publicSuffixIndex) : null; 361 } 362 363 /** 364 * Indicates whether this domain name ends in a {@linkplain #isPublicSuffix() public suffix}, 365 * while not being a public suffix itself. For example, returns {@code true} for {@code 366 * www.google.com}, {@code foo.co.uk} and {@code myblog.blogspot.com}, but not for {@code com}, 367 * {@code co.uk}, {@code google.invalid}, or {@code blogspot.com}. 368 * 369 * <p>This method can be used to determine whether it will probably be possible to set cookies on 370 * the domain, though even that depends on individual browsers' implementations of cookie 371 * controls. See <a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a> for details. 372 * 373 * @since 6.0 374 */ 375 public boolean isUnderPublicSuffix() { 376 return publicSuffixIndex > 0; 377 } 378 379 /** 380 * Indicates whether this domain name is composed of exactly one subdomain component followed by a 381 * {@linkplain #isPublicSuffix() public suffix}. For example, returns {@code true} for {@code 382 * google.com} {@code foo.co.uk}, and {@code myblog.blogspot.com}, but not for {@code 383 * www.google.com}, {@code co.uk}, or {@code blogspot.com}. 384 * 385 * <p>This method can be used to determine whether a domain is probably the highest level for 386 * which cookies may be set, though even that depends on individual browsers' implementations of 387 * cookie controls. See <a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a> for details. 388 * 389 * @since 6.0 390 */ 391 public boolean isTopPrivateDomain() { 392 return publicSuffixIndex == 1; 393 } 394 395 /** 396 * Returns the portion of this domain name that is one level beneath the {@linkplain 397 * #isPublicSuffix() public suffix}. For example, for {@code x.adwords.google.co.uk} it returns 398 * {@code google.co.uk}, since {@code co.uk} is a public suffix. Similarly, for {@code 399 * myblog.blogspot.com} it returns the same domain, {@code myblog.blogspot.com}, since {@code 400 * blogspot.com} is a public suffix. 401 * 402 * <p>If {@link #isTopPrivateDomain()} is true, the current domain name instance is returned. 403 * 404 * <p>This method can be used to determine the probable highest level parent domain for which 405 * cookies may be set, though even that depends on individual browsers' implementations of cookie 406 * controls. 407 * 408 * @throws IllegalStateException if this domain does not end with a public suffix 409 * @since 6.0 410 */ 411 public InternetDomainName topPrivateDomain() { 412 if (isTopPrivateDomain()) { 413 return this; 414 } 415 checkState(isUnderPublicSuffix(), "Not under a public suffix: %s", name); 416 return ancestor(publicSuffixIndex - 1); 417 } 418 419 /** 420 * Indicates whether this domain name represents a <i>registry suffix</i>, as defined by a subset 421 * of the Mozilla Foundation's <a href="http://publicsuffix.org/">Public Suffix List</a> (PSL). A 422 * registry suffix is one under which Internet users can directly register names via a domain name 423 * registrar, and have such registrations lawfully protected by internet-governing bodies such as 424 * ICANN. Examples of registry suffixes include {@code com}, {@code co.uk}, and {@code 425 * pvt.k12.wy.us}. Examples of domain names that are <i>not</i> registry suffixes include {@code 426 * google.com} and {@code foo.co.uk}. 427 * 428 * <p>Registry suffixes are a proper subset of {@linkplain #isPublicSuffix() public suffixes}. The 429 * list of public suffixes additionally contains privately owned domain names under which Internet 430 * users can register subdomains. An example of a public suffix that is not a registry suffix is 431 * {@code blogspot.com}. Note that it is true that all public suffixes <i>have</i> registry 432 * suffixes, since domain name registries collectively control all internet domain names. 433 * 434 * <p>For considerations on whether the public suffix or registry suffix designation is more 435 * suitable for your application, see <a 436 * href="https://github.com/google/guava/wiki/InternetDomainNameExplained">this article</a>. 437 * 438 * @return {@code true} if this domain name appears exactly on the public suffix list as part of 439 * the registry suffix section (labelled "ICANN"). 440 * @since 23.3 441 */ 442 public boolean isRegistrySuffix() { 443 return registrySuffixIndex == 0; 444 } 445 446 /** 447 * Indicates whether this domain name ends in a {@linkplain #isRegistrySuffix() registry suffix}, 448 * including if it is a registry suffix itself. For example, returns {@code true} for {@code 449 * www.google.com}, {@code foo.co.uk} and {@code com}, but not for {@code invalid} or {@code 450 * google.invalid}. 451 * 452 * <p>Note that this method is equivalent to {@link #hasPublicSuffix()} because all registry 453 * suffixes are public suffixes <i>and</i> all public suffixes have registry suffixes. 454 * 455 * @since 23.3 456 */ 457 public boolean hasRegistrySuffix() { 458 return registrySuffixIndex != NO_SUFFIX_FOUND; 459 } 460 461 /** 462 * Returns the {@linkplain #isRegistrySuffix() registry suffix} portion of the domain name, or 463 * {@code null} if no registry suffix is present. 464 * 465 * @since 23.3 466 */ 467 // TODO(b/147136275): After updating callers, add @CheckForNull, and remove @SuppressWarnings. 468 @SuppressWarnings("nullness") 469 public InternetDomainName registrySuffix() { 470 return hasRegistrySuffix() ? ancestor(registrySuffixIndex) : null; 471 } 472 473 /** 474 * Indicates whether this domain name ends in a {@linkplain #isRegistrySuffix() registry suffix}, 475 * while not being a registry suffix itself. For example, returns {@code true} for {@code 476 * www.google.com}, {@code foo.co.uk} and {@code blogspot.com}, but not for {@code com}, {@code 477 * co.uk}, or {@code google.invalid}. 478 * 479 * @since 23.3 480 */ 481 public boolean isUnderRegistrySuffix() { 482 return registrySuffixIndex > 0; 483 } 484 485 /** 486 * Indicates whether this domain name is composed of exactly one subdomain component followed by a 487 * {@linkplain #isRegistrySuffix() registry suffix}. For example, returns {@code true} for {@code 488 * google.com}, {@code foo.co.uk}, and {@code blogspot.com}, but not for {@code www.google.com}, 489 * {@code co.uk}, or {@code myblog.blogspot.com}. 490 * 491 * <p><b>Warning:</b> This method should not be used to determine the probable highest level 492 * parent domain for which cookies may be set. Use {@link #topPrivateDomain()} for that purpose. 493 * 494 * @since 23.3 495 */ 496 public boolean isTopDomainUnderRegistrySuffix() { 497 return registrySuffixIndex == 1; 498 } 499 500 /** 501 * Returns the portion of this domain name that is one level beneath the {@linkplain 502 * #isRegistrySuffix() registry suffix}. For example, for {@code x.adwords.google.co.uk} it 503 * returns {@code google.co.uk}, since {@code co.uk} is a registry suffix. Similarly, for {@code 504 * myblog.blogspot.com} it returns {@code blogspot.com}, since {@code com} is a registry suffix. 505 * 506 * <p>If {@link #isTopDomainUnderRegistrySuffix()} is true, the current domain name instance is 507 * returned. 508 * 509 * <p><b>Warning:</b> This method should not be used to determine whether a domain is probably the 510 * highest level for which cookies may be set. Use {@link #isTopPrivateDomain()} for that purpose. 511 * 512 * @throws IllegalStateException if this domain does not end with a registry suffix 513 * @since 23.3 514 */ 515 public InternetDomainName topDomainUnderRegistrySuffix() { 516 if (isTopDomainUnderRegistrySuffix()) { 517 return this; 518 } 519 checkState(isUnderRegistrySuffix(), "Not under a registry suffix: %s", name); 520 return ancestor(registrySuffixIndex - 1); 521 } 522 523 /** Indicates whether this domain is composed of two or more parts. */ 524 public boolean hasParent() { 525 return parts.size() > 1; 526 } 527 528 /** 529 * Returns an {@code InternetDomainName} that is the immediate ancestor of this one; that is, the 530 * current domain with the leftmost part removed. For example, the parent of {@code 531 * www.google.com} is {@code google.com}. 532 * 533 * @throws IllegalStateException if the domain has no parent, as determined by {@link #hasParent} 534 */ 535 public InternetDomainName parent() { 536 checkState(hasParent(), "Domain '%s' has no parent", name); 537 return ancestor(1); 538 } 539 540 /** 541 * Returns the ancestor of the current domain at the given number of levels "higher" (rightward) 542 * in the subdomain list. The number of levels must be non-negative, and less than {@code N-1}, 543 * where {@code N} is the number of parts in the domain. 544 * 545 * <p>TODO: Reasonable candidate for addition to public API. 546 */ 547 private InternetDomainName ancestor(int levels) { 548 return from(DOT_JOINER.join(parts.subList(levels, parts.size()))); 549 } 550 551 /** 552 * Creates and returns a new {@code InternetDomainName} by prepending the argument and a dot to 553 * the current name. For example, {@code InternetDomainName.from("foo.com").child("www.bar")} 554 * returns a new {@code InternetDomainName} with the value {@code www.bar.foo.com}. Only lenient 555 * validation is performed, as described {@link #from(String) here}. 556 * 557 * @throws NullPointerException if leftParts is null 558 * @throws IllegalArgumentException if the resulting name is not valid 559 */ 560 public InternetDomainName child(String leftParts) { 561 return from(checkNotNull(leftParts) + "." + name); 562 } 563 564 /** 565 * Indicates whether the argument is a syntactically valid domain name using lenient validation. 566 * Specifically, validation against <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a> 567 * ("Internationalizing Domain Names in Applications") is skipped. 568 * 569 * <p>The following two code snippets are equivalent: 570 * 571 * <pre>{@code 572 * domainName = InternetDomainName.isValid(name) 573 * ? InternetDomainName.from(name) 574 * : DEFAULT_DOMAIN; 575 * }</pre> 576 * 577 * <pre>{@code 578 * try { 579 * domainName = InternetDomainName.from(name); 580 * } catch (IllegalArgumentException e) { 581 * domainName = DEFAULT_DOMAIN; 582 * } 583 * }</pre> 584 * 585 * @since 8.0 (previously named {@code isValidLenient}) 586 */ 587 public static boolean isValid(String name) { 588 try { 589 from(name); 590 return true; 591 } catch (IllegalArgumentException e) { 592 return false; 593 } 594 } 595 596 /** 597 * Does the domain name match one of the "wildcard" patterns (e.g. {@code "*.ar"})? If a {@code 598 * desiredType} is specified, the wildcard pattern must also match that type. 599 */ 600 private static boolean matchesWildcardSuffixType( 601 Optional<PublicSuffixType> desiredType, String domain) { 602 List<String> pieces = DOT_SPLITTER.limit(2).splitToList(domain); 603 return pieces.size() == 2 604 && matchesType( 605 desiredType, Optional.fromNullable(PublicSuffixPatterns.UNDER.get(pieces.get(1)))); 606 } 607 608 /** 609 * If a {@code desiredType} is specified, returns true only if the {@code actualType} is 610 * identical. Otherwise, returns true as long as {@code actualType} is present. 611 */ 612 private static boolean matchesType( 613 Optional<PublicSuffixType> desiredType, Optional<PublicSuffixType> actualType) { 614 return desiredType.isPresent() ? desiredType.equals(actualType) : actualType.isPresent(); 615 } 616 617 /** Returns the domain name, normalized to all lower case. */ 618 @Override 619 public String toString() { 620 return name; 621 } 622 623 /** 624 * Equality testing is based on the text supplied by the caller, after normalization as described 625 * in the class documentation. For example, a non-ASCII Unicode domain name and the Punycode 626 * version of the same domain name would not be considered equal. 627 */ 628 @Override 629 public boolean equals(@CheckForNull Object object) { 630 if (object == this) { 631 return true; 632 } 633 634 if (object instanceof InternetDomainName) { 635 InternetDomainName that = (InternetDomainName) object; 636 return this.name.equals(that.name); 637 } 638 639 return false; 640 } 641 642 @Override 643 public int hashCode() { 644 return name.hashCode(); 645 } 646 }