1 /*
   2  * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.net;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.io.InvalidObjectException;
  31 import java.io.ObjectInputStream;
  32 import java.io.ObjectOutputStream;
  33 import java.io.Serializable;
  34 import java.nio.ByteBuffer;
  35 import java.nio.CharBuffer;
  36 import java.nio.charset.CharsetDecoder;
  37 import java.nio.charset.CharsetEncoder;
  38 import java.nio.charset.CoderResult;
  39 import java.nio.charset.CodingErrorAction;
  40 import java.nio.charset.CharacterCodingException;
  41 import java.nio.file.Path;
  42 import java.text.Normalizer;
  43 import jdk.internal.access.JavaNetUriAccess;
  44 import jdk.internal.access.SharedSecrets;
  45 import sun.nio.cs.UTF_8;
  46 
  47 /**
  48  * Represents a Uniform Resource Identifier (URI) reference.
  49  *
  50  * <p> Aside from some minor deviations noted below, an instance of this
  51  * class represents a URI reference as defined by
  52  * <a href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
  53  * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
  54  * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
  55  * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
  56  * also supports scope_ids. The syntax and usage of scope_ids is described
  57  * <a href="Inet6Address.html#scoped">here</a>.
  58  * This class provides constructors for creating URI instances from
  59  * their components or by parsing their string forms, methods for accessing the
  60  * various components of an instance, and methods for normalizing, resolving,
  61  * and relativizing URI instances.  Instances of this class are immutable.
  62  *
  63  *
  64  * <h2> URI syntax and components </h2>
  65  *
  66  * At the highest level a URI reference (hereinafter simply "URI") in string
  67  * form has the syntax
  68  *
  69  * <blockquote>
  70  * [<i>scheme</i><b>{@code :}</b>]<i>scheme-specific-part</i>[<b>{@code #}</b><i>fragment</i>]
  71  * </blockquote>
  72  *
  73  * where square brackets [...] delineate optional components and the characters
  74  * <b>{@code :}</b> and <b>{@code #}</b> stand for themselves.
  75  *
  76  * <p> An <i>absolute</i> URI specifies a scheme; a URI that is not absolute is
  77  * said to be <i>relative</i>.  URIs are also classified according to whether
  78  * they are <i>opaque</i> or <i>hierarchical</i>.
  79  *
  80  * <p> An <i>opaque</i> URI is an absolute URI whose scheme-specific part does
  81  * not begin with a slash character ({@code '/'}).  Opaque URIs are not
  82  * subject to further parsing.  Some examples of opaque URIs are:
  83  *
  84  * <blockquote><ul style="list-style-type:none">
  85  * <li>{@code mailto:java-net@www.example.com}</li>
  86  * <li>{@code news:comp.lang.java}</li>
  87  * <li>{@code urn:isbn:096139210x}</li>
  88  * </ul></blockquote>
  89  *
  90  * <p> A <i>hierarchical</i> URI is either an absolute URI whose
  91  * scheme-specific part begins with a slash character, or a relative URI, that
  92  * is, a URI that does not specify a scheme.  Some examples of hierarchical
  93  * URIs are:
  94  *
  95  * <blockquote>
  96  * {@code http://example.com/languages/java/}<br>
  97  * {@code sample/a/index.html#28}<br>
  98  * {@code ../../demo/b/index.html}<br>
  99  * {@code file:///~/calendar}
 100  * </blockquote>
 101  *
 102  * <p> A hierarchical URI is subject to further parsing according to the syntax
 103  *
 104  * <blockquote>
 105  * [<i>scheme</i><b>{@code :}</b>][<b>{@code //}</b><i>authority</i>][<i>path</i>][<b>{@code ?}</b><i>query</i>][<b>{@code #}</b><i>fragment</i>]
 106  * </blockquote>
 107  *
 108  * where the characters <b>{@code :}</b>, <b>{@code /}</b>,
 109  * <b>{@code ?}</b>, and <b>{@code #}</b> stand for themselves.  The
 110  * scheme-specific part of a hierarchical URI consists of the characters
 111  * between the scheme and fragment components.
 112  *
 113  * <p> The authority component of a hierarchical URI is, if specified, either
 114  * <i>server-based</i> or <i>registry-based</i>.  A server-based authority
 115  * parses according to the familiar syntax
 116  *
 117  * <blockquote>
 118  * [<i>user-info</i><b>{@code @}</b>]<i>host</i>[<b>{@code :}</b><i>port</i>]
 119  * </blockquote>
 120  *
 121  * where the characters <b>{@code @}</b> and <b>{@code :}</b> stand for
 122  * themselves.  Nearly all URI schemes currently in use are server-based.  An
 123  * authority component that does not parse in this way is considered to be
 124  * registry-based.
 125  *
 126  * <p> The path component of a hierarchical URI is itself said to be absolute
 127  * if it begins with a slash character ({@code '/'}); otherwise it is
 128  * relative.  The path of a hierarchical URI that is either absolute or
 129  * specifies an authority is always absolute.
 130  *
 131  * <p> All told, then, a URI instance has the following nine components:
 132  *
 133  * <table class="striped" style="margin-left:2em">
 134  * <caption style="display:none">Describes the components of a URI:scheme,scheme-specific-part,authority,user-info,host,port,path,query,fragment</caption>
 135  * <thead>
 136  * <tr><th scope="col">Component</th><th scope="col">Type</th></tr>
 137  * </thead>
 138  * <tbody style="text-align:left">
 139  * <tr><th scope="row">scheme</th><td>{@code String}</td></tr>
 140  * <tr><th scope="row">scheme-specific-part</th><td>{@code String}</td></tr>
 141  * <tr><th scope="row">authority</th><td>{@code String}</td></tr>
 142  * <tr><th scope="row">user-info</th><td>{@code String}</td></tr>
 143  * <tr><th scope="row">host</th><td>{@code String}</td></tr>
 144  * <tr><th scope="row">port</th><td>{@code int}</td></tr>
 145  * <tr><th scope="row">path</th><td>{@code String}</td></tr>
 146  * <tr><th scope="row">query</th><td>{@code String}</td></tr>
 147  * <tr><th scope="row">fragment</th><td>{@code String}</td></tr>
 148  * </tbody>
 149  * </table>
 150  *
 151  * In a given instance any particular component is either <i>undefined</i> or
 152  * <i>defined</i> with a distinct value.  Undefined string components are
 153  * represented by {@code null}, while undefined integer components are
 154  * represented by {@code -1}.  A string component may be defined to have the
 155  * empty string as its value; this is not equivalent to that component being
 156  * undefined.
 157  *
 158  * <p> Whether a particular component is or is not defined in an instance
 159  * depends upon the type of the URI being represented.  An absolute URI has a
 160  * scheme component.  An opaque URI has a scheme, a scheme-specific part, and
 161  * possibly a fragment, but has no other components.  A hierarchical URI always
 162  * has a path (though it may be empty) and a scheme-specific-part (which at
 163  * least contains the path), and may have any of the other components.  If the
 164  * authority component is present and is server-based then the host component
 165  * will be defined and the user-information and port components may be defined.
 166  *
 167  *
 168  * <h3> Operations on URI instances </h3>
 169  *
 170  * The key operations supported by this class are those of
 171  * <i>normalization</i>, <i>resolution</i>, and <i>relativization</i>.
 172  *
 173  * <p> <i>Normalization</i> is the process of removing unnecessary {@code "."}
 174  * and {@code ".."} segments from the path component of a hierarchical URI.
 175  * Each {@code "."} segment is simply removed.  A {@code ".."} segment is
 176  * removed only if it is preceded by a non-{@code ".."} segment.
 177  * Normalization has no effect upon opaque URIs.
 178  *
 179  * <p> <i>Resolution</i> is the process of resolving one URI against another,
 180  * <i>base</i> URI.  The resulting URI is constructed from components of both
 181  * URIs in the manner specified by RFC&nbsp;2396, taking components from the
 182  * base URI for those not specified in the original.  For hierarchical URIs,
 183  * the path of the original is resolved against the path of the base and then
 184  * normalized.  The result, for example, of resolving
 185  *
 186  * <blockquote>
 187  * {@code sample/a/index.html#28}
 188  * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 189  * &nbsp;&nbsp;&nbsp;&nbsp;(1)
 190  * </blockquote>
 191  *
 192  * against the base URI {@code http://example.com/languages/java/} is the result
 193  * URI
 194  *
 195  * <blockquote>
 196  * {@code http://example.com/languages/java/sample/a/index.html#28}
 197  * </blockquote>
 198  *
 199  * Resolving the relative URI
 200  *
 201  * <blockquote>
 202  * {@code ../../demo/b/index.html}&nbsp;&nbsp;&nbsp;&nbsp;(2)
 203  * </blockquote>
 204  *
 205  * against this result yields, in turn,
 206  *
 207  * <blockquote>
 208  * {@code http://example.com/languages/java/demo/b/index.html}
 209  * </blockquote>
 210  *
 211  * Resolution of both absolute and relative URIs, and of both absolute and
 212  * relative paths in the case of hierarchical URIs, is supported.  Resolving
 213  * the URI {@code file:///~calendar} against any other URI simply yields the
 214  * original URI, since it is absolute.  Resolving the relative URI (2) above
 215  * against the relative base URI (1) yields the normalized, but still relative,
 216  * URI
 217  *
 218  * <blockquote>
 219  * {@code demo/b/index.html}
 220  * </blockquote>
 221  *
 222  * <p> <i>Relativization</i>, finally, can be regarded as the inverse of resolution.
 223  * Let <i>u</i> be any normalized absolute URI ending with a slash character ({@code '/'})
 224  * and <i>v</i> be any normalized relative URI not beginning with a period character ({@code '.'})
 225  * or slash character ({@code '/'}). Then, the following statement is true:
 226  *
 227  * <blockquote>
 228  *   <i>u</i>{@code .relativize(}<i>u</i>{@code .resolve(}<i>v</i>{@code )).equals(}<i>v</i>{@code )}
 229  * </blockquote>
 230  *
 231  * Let <i>u</i> be any normalized absolute URI ending with a slash character ({@code '/'})
 232  * and <i>v</i> be any normalized absolute URI. Then, the following statement is true:
 233  *
 234  * <blockquote>
 235  *   <i>u</i>{@code .resolve(}<i>u</i>{@code .relativize(}<i>v</i>{@code )).equals(}<i>v</i>{@code )}
 236  * </blockquote>
 237  *
 238  * This operation is often useful when constructing a document containing URIs
 239  * that must be made relative to the base URI of the document wherever
 240  * possible.  For example, relativizing the URI
 241  *
 242  * <blockquote>
 243  * {@code http://example.com/languages/java/sample/a/index.html#28}
 244  * </blockquote>
 245  *
 246  * against the base URI
 247  *
 248  * <blockquote>
 249  * {@code http://example.com/languages/java/}
 250  * </blockquote>
 251  *
 252  * yields the relative URI {@code sample/a/index.html#28}.
 253  *
 254  *
 255  * <h3> Character categories </h3>
 256  *
 257  * RFC&nbsp;2396 specifies precisely which characters are permitted in the
 258  * various components of a URI reference.  The following categories, most of
 259  * which are taken from that specification, are used below to describe these
 260  * constraints:
 261  *
 262  * <table class="striped" style="margin-left:2em">
 263  * <caption style="display:none">Describes categories alpha,digit,alphanum,unreserved,punct,reserved,escaped,and other</caption>
 264  *   <thead>
 265  *   <tr><th scope="col">Category</th><th scope="col">Description</th></tr>
 266  *   </thead>
 267  *   <tbody style="text-align:left">
 268  *   <tr><th scope="row" style="vertical-align:top">alpha</th>
 269  *       <td>The US-ASCII alphabetic characters,
 270  *        {@code 'A'}&nbsp;through&nbsp;{@code 'Z'}
 271  *        and {@code 'a'}&nbsp;through&nbsp;{@code 'z'}</td></tr>
 272  *   <tr><th scope="row" style="vertical-align:top">digit</th>
 273  *       <td>The US-ASCII decimal digit characters,
 274  *       {@code '0'}&nbsp;through&nbsp;{@code '9'}</td></tr>
 275  *   <tr><th scope="row" style="vertical-align:top">alphanum</th>
 276  *       <td>All <i>alpha</i> and <i>digit</i> characters</td></tr>
 277  *   <tr><th scope="row" style="vertical-align:top">unreserved</th>
 278  *       <td>All <i>alphanum</i> characters together with those in the string
 279  *        {@code "_-!.~'()*"}</td></tr>
 280  *   <tr><th scope="row" style="vertical-align:top">punct</th>
 281  *       <td>The characters in the string {@code ",;:$&+="}</td></tr>
 282  *   <tr><th scope="row" style="vertical-align:top">reserved</th>
 283  *       <td>All <i>punct</i> characters together with those in the string
 284  *        {@code "?/[]@"}</td></tr>
 285  *   <tr><th scope="row" style="vertical-align:top">escaped</th>
 286  *       <td>Escaped octets, that is, triplets consisting of the percent
 287  *           character ({@code '%'}) followed by two hexadecimal digits
 288  *           ({@code '0'}-{@code '9'}, {@code 'A'}-{@code 'F'}, and
 289  *           {@code 'a'}-{@code 'f'})</td></tr>
 290  *   <tr><th scope="row" style="vertical-align:top">other</th>
 291  *       <td>The Unicode characters that are not in the US-ASCII character set,
 292  *           are not control characters (according to the {@link
 293  *           java.lang.Character#isISOControl(char) Character.isISOControl}
 294  *           method), and are not space characters (according to the {@link
 295  *           java.lang.Character#isSpaceChar(char) Character.isSpaceChar}
 296  *           method)&nbsp;&nbsp;<i>(<b>Deviation from RFC 2396</b>, which is
 297  *           limited to US-ASCII)</i></td></tr>
 298  * </tbody>
 299  * </table>
 300  *
 301  * <p><a id="legal-chars"></a> The set of all legal URI characters consists of
 302  * the <i>unreserved</i>, <i>reserved</i>, <i>escaped</i>, and <i>other</i>
 303  * characters.
 304  *
 305  *
 306  * <h3> Escaped octets, quotation, encoding, and decoding </h3>
 307  *
 308  * RFC 2396 allows escaped octets to appear in the user-info, path, query, and
 309  * fragment components.  Escaping serves two purposes in URIs:
 310  *
 311  * <ul>
 312  *
 313  *   <li><p> To <i>encode</i> non-US-ASCII characters when a URI is required to
 314  *   conform strictly to RFC&nbsp;2396 by not containing any <i>other</i>
 315  *   characters.  </p></li>
 316  *
 317  *   <li><p> To <i>quote</i> characters that are otherwise illegal in a
 318  *   component.  The user-info, path, query, and fragment components differ
 319  *   slightly in terms of which characters are considered legal and illegal.
 320  *   </p></li>
 321  *
 322  * </ul>
 323  *
 324  * These purposes are served in this class by three related operations:
 325  *
 326  * <ul>
 327  *
 328  *   <li><p><a id="encode"></a> A character is <i>encoded</i> by replacing it
 329  *   with the sequence of escaped octets that represent that character in the
 330  *   UTF-8 character set.  The Euro currency symbol ({@code '\u005Cu20AC'}),
 331  *   for example, is encoded as {@code "%E2%82%AC"}.  <i>(<b>Deviation from
 332  *   RFC&nbsp;2396</b>, which does not specify any particular character
 333  *   set.)</i> </p></li>
 334  *
 335  *   <li><p><a id="quote"></a> An illegal character is <i>quoted</i> simply by
 336  *   encoding it.  The space character, for example, is quoted by replacing it
 337  *   with {@code "%20"}.  UTF-8 contains US-ASCII, hence for US-ASCII
 338  *   characters this transformation has exactly the effect required by
 339  *   RFC&nbsp;2396. </p></li>
 340  *
 341  *   <li><p><a id="decode"></a>
 342  *   A sequence of escaped octets is <i>decoded</i> by
 343  *   replacing it with the sequence of characters that it represents in the
 344  *   UTF-8 character set.  UTF-8 contains US-ASCII, hence decoding has the
 345  *   effect of de-quoting any quoted US-ASCII characters as well as that of
 346  *   decoding any encoded non-US-ASCII characters.  If a <a
 347  *   href="../nio/charset/CharsetDecoder.html#ce">decoding error</a> occurs
 348  *   when decoding the escaped octets then the erroneous octets are replaced by
 349  *   {@code '\u005CuFFFD'}, the Unicode replacement character.  </p></li>
 350  *
 351  * </ul>
 352  *
 353  * These operations are exposed in the constructors and methods of this class
 354  * as follows:
 355  *
 356  * <ul>
 357  *
 358  *   <li><p> The {@linkplain #URI(java.lang.String) single-argument
 359  *   constructor} requires any illegal characters in its argument to be
 360  *   quoted and preserves any escaped octets and <i>other</i> characters that
 361  *   are present.  </p></li>
 362  *
 363  *   <li><p> The {@linkplain
 364  *   #URI(java.lang.String,java.lang.String,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String)
 365  *   multi-argument constructors} quote illegal characters as
 366  *   required by the components in which they appear.  The percent character
 367  *   ({@code '%'}) is always quoted by these constructors.  Any <i>other</i>
 368  *   characters are preserved.  </p></li>
 369  *
 370  *   <li><p> The {@link #getRawUserInfo() getRawUserInfo}, {@link #getRawPath()
 371  *   getRawPath}, {@link #getRawQuery() getRawQuery}, {@link #getRawFragment()
 372  *   getRawFragment}, {@link #getRawAuthority() getRawAuthority}, and {@link
 373  *   #getRawSchemeSpecificPart() getRawSchemeSpecificPart} methods return the
 374  *   values of their corresponding components in raw form, without interpreting
 375  *   any escaped octets.  The strings returned by these methods may contain
 376  *   both escaped octets and <i>other</i> characters, and will not contain any
 377  *   illegal characters.  </p></li>
 378  *
 379  *   <li><p> The {@link #getUserInfo() getUserInfo}, {@link #getPath()
 380  *   getPath}, {@link #getQuery() getQuery}, {@link #getFragment()
 381  *   getFragment}, {@link #getAuthority() getAuthority}, and {@link
 382  *   #getSchemeSpecificPart() getSchemeSpecificPart} methods decode any escaped
 383  *   octets in their corresponding components.  The strings returned by these
 384  *   methods may contain both <i>other</i> characters and illegal characters,
 385  *   and will not contain any escaped octets.  </p></li>
 386  *
 387  *   <li><p> The {@link #toString() toString} method returns a URI string with
 388  *   all necessary quotation but which may contain <i>other</i> characters.
 389  *   </p></li>
 390  *
 391  *   <li><p> The {@link #toASCIIString() toASCIIString} method returns a fully
 392  *   quoted and encoded URI string that does not contain any <i>other</i>
 393  *   characters.  </p></li>
 394  *
 395  * </ul>
 396  *
 397  *
 398  * <h3> Identities </h3>
 399  *
 400  * For any URI <i>u</i>, it is always the case that
 401  *
 402  * <blockquote>
 403  * {@code new URI(}<i>u</i>{@code .toString()).equals(}<i>u</i>{@code )}&nbsp;.
 404  * </blockquote>
 405  *
 406  * For any URI <i>u</i> that does not contain redundant syntax such as two
 407  * slashes before an empty authority (as in {@code file:///tmp/}&nbsp;) or a
 408  * colon following a host name but no port (as in
 409  * {@code http://www.example.com:}&nbsp;), and that does not encode characters
 410  * except those that must be quoted, the following identities also hold:
 411  * <pre>
 412  *     new URI(<i>u</i>.getScheme(),
 413  *             <i>u</i>.getSchemeSpecificPart(),
 414  *             <i>u</i>.getFragment())
 415  *     .equals(<i>u</i>)</pre>
 416  * in all cases,
 417  * <pre>
 418  *     new URI(<i>u</i>.getScheme(),
 419  *             <i>u</i>.getAuthority(),
 420  *             <i>u</i>.getPath(), <i>u</i>.getQuery(),
 421  *             <i>u</i>.getFragment())
 422  *     .equals(<i>u</i>)</pre>
 423  * if <i>u</i> is hierarchical, and
 424  * <pre>
 425  *     new URI(<i>u</i>.getScheme(),
 426  *             <i>u</i>.getUserInfo(), <i>u</i>.getHost(), <i>u</i>.getPort(),
 427  *             <i>u</i>.getPath(), <i>u</i>.getQuery(),
 428  *             <i>u</i>.getFragment())
 429  *     .equals(<i>u</i>)</pre>
 430  * if <i>u</i> is hierarchical and has either no authority or a server-based
 431  * authority.
 432  *
 433  *
 434  * <h3> URIs, URLs, and URNs </h3>
 435  *
 436  * A URI is a uniform resource <i>identifier</i> while a URL is a uniform
 437  * resource <i>locator</i>.  Hence every URL is a URI, abstractly speaking, but
 438  * not every URI is a URL.  This is because there is another subcategory of
 439  * URIs, uniform resource <i>names</i> (URNs), which name resources but do not
 440  * specify how to locate them.  The {@code mailto}, {@code news}, and
 441  * {@code isbn} URIs shown above are examples of URNs.
 442  *
 443  * <p> The conceptual distinction between URIs and URLs is reflected in the
 444  * differences between this class and the {@link URL} class.
 445  *
 446  * <p> An instance of this class represents a URI reference in the syntactic
 447  * sense defined by RFC&nbsp;2396.  A URI may be either absolute or relative.
 448  * A URI string is parsed according to the generic syntax without regard to the
 449  * scheme, if any, that it specifies.  No lookup of the host, if any, is
 450  * performed, and no scheme-dependent stream handler is constructed.  Equality,
 451  * hashing, and comparison are defined strictly in terms of the character
 452  * content of the instance.  In other words, a URI instance is little more than
 453  * a structured string that supports the syntactic, scheme-independent
 454  * operations of comparison, normalization, resolution, and relativization.
 455  *
 456  * <p> An instance of the {@link URL} class, by contrast, represents the
 457  * syntactic components of a URL together with some of the information required
 458  * to access the resource that it describes.  A URL must be absolute, that is,
 459  * it must always specify a scheme.  A URL string is parsed according to its
 460  * scheme.  A stream handler is always established for a URL, and in fact it is
 461  * impossible to create a URL instance for a scheme for which no handler is
 462  * available.  Equality and hashing depend upon both the scheme and the
 463  * Internet address of the host, if any; comparison is not defined.  In other
 464  * words, a URL is a structured string that supports the syntactic operation of
 465  * resolution as well as the network I/O operations of looking up the host and
 466  * opening a connection to the specified resource.
 467  *
 468  * @apiNote
 469  *
 470  * Applications working with file paths and file URIs should take great
 471  * care to use the appropriate methods to convert between the two.
 472  * The {@link Path#of(URI)} factory method and the {@link File#File(URI)}
 473  * constructor can be used to create {@link Path} or {@link File}
 474  * objects from a file URI. {@link Path#toUri()} and {@link File#toURI()}
 475  * can be used to create a {@link URI} from a file path.
 476  * Applications should never try to {@linkplain
 477  * #URI(String, String, String, int, String, String, String)
 478  * construct}, {@linkplain #URI(String) parse}, or
 479  * {@linkplain #resolve(String) resolve} a {@code URI}
 480  * from the direct string representation of a {@code File} or {@code Path}
 481  * instance.
 482  * <p>
 483  * Some components of a URL or URI, such as <i>userinfo</i>, may
 484  * be abused to construct misleading URLs or URIs. Applications
 485  * that deal with URLs or URIs should take into account
 486  * the recommendations advised in <a
 487  * href="https://tools.ietf.org/html/rfc3986#section-7">RFC3986,
 488  * Section 7, Security Considerations</a>.
 489  *
 490  * @author Mark Reinhold
 491  * @since 1.4
 492  *
 493  * @spec https://www.rfc-editor.org/info/rfc2279
 494  *      RFC 2279: UTF-8, a transformation format of ISO 10646
 495  * @spec https://www.rfc-editor.org/info/rfc2373
 496  *      RFC 2373: IP Version 6 Addressing Architecture
 497  * @spec https://www.rfc-editor.org/info/rfc2396
 498  *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
 499  * @spec https://www.rfc-editor.org/info/rfc2732
 500  *      RFC 2732: Format for Literal IPv6 Addresses in URL's
 501  * @spec https://www.rfc-editor.org/info/rfc3986
 502  *      RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
 503  *
 504  * @see <a href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC&nbsp;2279: UTF-8, a
 505  * transformation format of ISO 10646</i></a>
 506  * @see <a href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IPv6 Addressing
 507  * Architecture</i></a>
 508  * @see <a href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
 509  * Resource Identifiers (URI): Generic Syntax</i></a>
 510  * @see <a href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
 511  * Literal IPv6 Addresses in URLs</i></a>
 512  * @see <a href="URISyntaxException.html">URISyntaxException</a>
 513  */
 514 
 515 public final class URI
 516     implements Comparable<URI>, Serializable
 517 {
 518 
 519     // Note: Comments containing the word "ASSERT" indicate places where a
 520     // throw of an InternalError should be replaced by an appropriate assertion
 521     // statement once asserts are enabled in the build.
 522     @java.io.Serial
 523     static final long serialVersionUID = -6052424284110960213L;
 524 
 525 
 526     // -- Properties and components of this instance --
 527 
 528     // Components of all URIs: [<scheme>:]<scheme-specific-part>[#<fragment>]
 529     private transient String scheme;            // null ==> relative URI
 530     private transient String fragment;
 531 
 532     // Hierarchical URI components: [//<authority>]<path>[?<query>]
 533     private transient String authority;         // Registry or server
 534 
 535     // Server-based authority: [<userInfo>@]<host>[:<port>]
 536     private transient String userInfo;
 537     private transient String host;              // null ==> registry-based
 538     private transient int port = -1;            // -1 ==> undefined
 539 
 540     // Remaining components of hierarchical URIs
 541     private transient String path;              // null ==> opaque
 542     private transient String query;
 543 
 544     // The remaining fields may be computed on demand, which is safe even in
 545     // the face of multiple threads racing to initialize them
 546     private transient String schemeSpecificPart;
 547     private transient int hash;        // Zero ==> undefined
 548 
 549     private transient String decodedUserInfo;
 550     private transient String decodedAuthority;
 551     private transient String decodedPath;
 552     private transient String decodedQuery;
 553     private transient String decodedFragment;
 554     private transient String decodedSchemeSpecificPart;
 555 
 556     /**
 557      * The string form of this URI.
 558      *
 559      * @serial
 560      */
 561     private volatile String string;             // The only serializable field
 562 
 563 
 564 
 565     // -- Constructors and factories --
 566 
 567     private URI() { }                           // Used internally
 568 
 569     /**
 570      * Constructs a URI by parsing the given string.
 571      *
 572      * <p> This constructor parses the given string exactly as specified by the
 573      * grammar in <a
 574      * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
 575      * Appendix&nbsp;A, <b><i>except for the following deviations:</i></b> </p>
 576      *
 577      * <ul>
 578      *
 579      *   <li><p> An empty authority component is permitted as long as it is
 580      *   followed by a non-empty path, a query component, or a fragment
 581      *   component.  This allows the parsing of URIs such as
 582      *   {@code "file:///foo/bar"}, which seems to be the intent of
 583      *   RFC&nbsp;2396 although the grammar does not permit it.  If the
 584      *   authority component is empty then the user-information, host, and port
 585      *   components are undefined. </p></li>
 586      *
 587      *   <li><p> Empty relative paths are permitted; this seems to be the
 588      *   intent of RFC&nbsp;2396 although the grammar does not permit it.  The
 589      *   primary consequence of this deviation is that a standalone fragment
 590      *   such as {@code "#foo"} parses as a relative URI with an empty path
 591      *   and the given fragment, and can be usefully <a
 592      *   href="#resolve-frag">resolved</a> against a base URI.
 593      *
 594      *   <li><p> IPv4 addresses in host components are parsed rigorously, as
 595      *   specified by <a
 596      *   href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>: Each
 597      *   element of a dotted-quad address must contain no more than three
 598      *   decimal digits.  Each element is further constrained to have a value
 599      *   no greater than 255. </p></li>
 600      *
 601      *   <li> <p> Hostnames in host components that comprise only a single
 602      *   domain label are permitted to start with an <i>alphanum</i>
 603      *   character. This seems to be the intent of <a
 604      *   href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>
 605      *   section&nbsp;3.2.2 although the grammar does not permit it. The
 606      *   consequence of this deviation is that the authority component of a
 607      *   hierarchical URI such as {@code s://123}, will parse as a server-based
 608      *   authority. </p></li>
 609      *
 610      *   <li><p> IPv6 addresses are permitted for the host component.  An IPv6
 611      *   address must be enclosed in square brackets ({@code '['} and
 612      *   {@code ']'}) as specified by <a
 613      *   href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>.  The
 614      *   IPv6 address itself must parse according to <a
 615      *   href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373</a>.  IPv6
 616      *   addresses are further constrained to describe no more than sixteen
 617      *   bytes of address information, a constraint implicit in RFC&nbsp;2373
 618      *   but not expressible in the grammar. </p></li>
 619      *
 620      *   <li><p> Characters in the <i>other</i> category are permitted wherever
 621      *   RFC&nbsp;2396 permits <i>escaped</i> octets, that is, in the
 622      *   user-information, path, query, and fragment components, as well as in
 623      *   the authority component if the authority is registry-based.  This
 624      *   allows URIs to contain Unicode characters beyond those in the US-ASCII
 625      *   character set. </p></li>
 626      *
 627      * </ul>
 628      *
 629      * @param  str   The string to be parsed into a URI
 630      *
 631      * @throws  NullPointerException
 632      *          If {@code str} is {@code null}
 633      *
 634      * @throws  URISyntaxException
 635      *          If the given string violates RFC&nbsp;2396, as augmented
 636      *          by the above deviations
 637      * @spec https://www.rfc-editor.org/info/rfc2373
 638      *      RFC 2373: IP Version 6 Addressing Architecture
 639      * @spec https://www.rfc-editor.org/info/rfc2396
 640      *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
 641      * @spec https://www.rfc-editor.org/info/rfc2732
 642      *      RFC 2732: Format for Literal IPv6 Addresses in URL's
 643      */
 644     public URI(String str) throws URISyntaxException {
 645         new Parser(str).parse(false);
 646     }
 647 
 648     /**
 649      * Constructs a hierarchical URI from the given components.
 650      *
 651      * <p> If a scheme is given then the path, if also given, must either be
 652      * empty or begin with a slash character ({@code '/'}).  Otherwise a
 653      * component of the new URI may be left undefined by passing {@code null}
 654      * for the corresponding parameter or, in the case of the {@code port}
 655      * parameter, by passing {@code -1}.
 656      *
 657      * <p> This constructor first builds a URI string from the given components
 658      * according to the rules specified in <a
 659      * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
 660      * section&nbsp;5.2, step&nbsp;7: </p>
 661      *
 662      * <ol>
 663      *
 664      *   <li><p> Initially, the result string is empty. </p></li>
 665      *
 666      *   <li><p> If a scheme is given then it is appended to the result,
 667      *   followed by a colon character ({@code ':'}).  </p></li>
 668      *
 669      *   <li><p> If user information, a host, or a port are given then the
 670      *   string {@code "//"} is appended.  </p></li>
 671      *
 672      *   <li><p> If user information is given then it is appended, followed by
 673      *   a commercial-at character ({@code '@'}).  Any character not in the
 674      *   <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
 675      *   categories is <a href="#quote">quoted</a>.  </p></li>
 676      *
 677      *   <li><p> If a host is given then it is appended.  If the host is a
 678      *   literal IPv6 address but is not enclosed in square brackets
 679      *   ({@code '['} and {@code ']'}) then the square brackets are added.
 680      *   </p></li>
 681      *
 682      *   <li><p> If a port number is given then a colon character
 683      *   ({@code ':'}) is appended, followed by the port number in decimal.
 684      *   </p></li>
 685      *
 686      *   <li><p> If a path is given then it is appended.  Any character not in
 687      *   the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
 688      *   categories, and not equal to the slash character ({@code '/'}) or the
 689      *   commercial-at character ({@code '@'}), is quoted.  </p></li>
 690      *
 691      *   <li><p> If a query is given then a question-mark character
 692      *   ({@code '?'}) is appended, followed by the query.  Any character that
 693      *   is not a <a href="#legal-chars">legal URI character</a> is quoted.
 694      *   </p></li>
 695      *
 696      *   <li><p> Finally, if a fragment is given then a hash character
 697      *   ({@code '#'}) is appended, followed by the fragment.  Any character
 698      *   that is not a legal URI character is quoted.  </p></li>
 699      *
 700      * </ol>
 701      *
 702      * <p> The resulting URI string is then parsed as if by invoking the {@link
 703      * #URI(String)} constructor and then invoking the {@link
 704      * #parseServerAuthority()} method upon the result; this may cause a {@link
 705      * URISyntaxException} to be thrown.  </p>
 706      *
 707      * @param   scheme    Scheme name
 708      * @param   userInfo  User name and authorization information
 709      * @param   host      Host name
 710      * @param   port      Port number
 711      * @param   path      Path
 712      * @param   query     Query
 713      * @param   fragment  Fragment
 714      *
 715      * @throws URISyntaxException
 716      *         If both a scheme and a path are given but the path is relative,
 717      *         if the URI string constructed from the given components violates
 718      *         RFC&nbsp;2396, or if the authority component of the string is
 719      *         present but cannot be parsed as a server-based authority
 720      * @spec https://www.rfc-editor.org/info/rfc2396
 721      *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
 722      */
 723     public URI(String scheme,
 724                String userInfo, String host, int port,
 725                String path, String query, String fragment)
 726         throws URISyntaxException
 727     {
 728         String s = toString(scheme, null,
 729                             null, userInfo, host, port,
 730                             path, query, fragment);
 731         checkPath(s, scheme, path);
 732         new Parser(s).parse(true);
 733     }
 734 
 735     /**
 736      * Constructs a hierarchical URI from the given components.
 737      *
 738      * <p> If a scheme is given then the path, if also given, must either be
 739      * empty or begin with a slash character ({@code '/'}).  Otherwise a
 740      * component of the new URI may be left undefined by passing {@code null}
 741      * for the corresponding parameter.
 742      *
 743      * <p> This constructor first builds a URI string from the given components
 744      * according to the rules specified in <a
 745      * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
 746      * section&nbsp;5.2, step&nbsp;7: </p>
 747      *
 748      * <ol>
 749      *
 750      *   <li><p> Initially, the result string is empty.  </p></li>
 751      *
 752      *   <li><p> If a scheme is given then it is appended to the result,
 753      *   followed by a colon character ({@code ':'}).  </p></li>
 754      *
 755      *   <li><p> If an authority is given then the string {@code "//"} is
 756      *   appended, followed by the authority.  If the authority contains a
 757      *   literal IPv6 address then the address must be enclosed in square
 758      *   brackets ({@code '['} and {@code ']'}).  Any character not in the
 759      *   <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
 760      *   categories, and not equal to the commercial-at character
 761      *   ({@code '@'}), is <a href="#quote">quoted</a>.  </p></li>
 762      *
 763      *   <li><p> If a path is given then it is appended.  Any character not in
 764      *   the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
 765      *   categories, and not equal to the slash character ({@code '/'}) or the
 766      *   commercial-at character ({@code '@'}), is quoted.  </p></li>
 767      *
 768      *   <li><p> If a query is given then a question-mark character
 769      *   ({@code '?'}) is appended, followed by the query.  Any character that
 770      *   is not a <a href="#legal-chars">legal URI character</a> is quoted.
 771      *   </p></li>
 772      *
 773      *   <li><p> Finally, if a fragment is given then a hash character
 774      *   ({@code '#'}) is appended, followed by the fragment.  Any character
 775      *   that is not a legal URI character is quoted.  </p></li>
 776      *
 777      * </ol>
 778      *
 779      * <p> The resulting URI string is then parsed as if by invoking the {@link
 780      * #URI(String)} constructor and then invoking the {@link
 781      * #parseServerAuthority()} method upon the result; this may cause a {@link
 782      * URISyntaxException} to be thrown.  </p>
 783      *
 784      * @param   scheme     Scheme name
 785      * @param   authority  Authority
 786      * @param   path       Path
 787      * @param   query      Query
 788      * @param   fragment   Fragment
 789      *
 790      * @throws URISyntaxException
 791      *         If both a scheme and a path are given but the path is relative,
 792      *         if the URI string constructed from the given components violates
 793      *         RFC&nbsp;2396, or if the authority component of the string is
 794      *         present but cannot be parsed as a server-based authority
 795      * @spec https://www.rfc-editor.org/info/rfc2396
 796      *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
 797      */
 798     public URI(String scheme,
 799                String authority,
 800                String path, String query, String fragment)
 801         throws URISyntaxException
 802     {
 803         String s = toString(scheme, null,
 804                             authority, null, null, -1,
 805                             path, query, fragment);
 806         checkPath(s, scheme, path);
 807         new Parser(s).parse(false);
 808     }
 809 
 810     /**
 811      * Constructs a hierarchical URI from the given components.
 812      *
 813      * <p> A component may be left undefined by passing {@code null}.
 814      *
 815      * <p> This convenience constructor works as if by invoking the
 816      * seven-argument constructor as follows:
 817      *
 818      * <blockquote>
 819      * {@code new} {@link #URI(String, String, String, int, String, String, String)
 820      * URI}{@code (scheme, null, host, -1, path, null, fragment);}
 821      * </blockquote>
 822      *
 823      * @param   scheme    Scheme name
 824      * @param   host      Host name
 825      * @param   path      Path
 826      * @param   fragment  Fragment
 827      *
 828      * @throws  URISyntaxException
 829      *          If the URI string constructed from the given components
 830      *          violates RFC&nbsp;2396
 831      */
 832     public URI(String scheme, String host, String path, String fragment)
 833         throws URISyntaxException
 834     {
 835         this(scheme, null, host, -1, path, null, fragment);
 836     }
 837 
 838     /**
 839      * Constructs a URI from the given components.
 840      *
 841      * <p> A component may be left undefined by passing {@code null}.
 842      *
 843      * <p> This constructor first builds a URI in string form using the given
 844      * components as follows:  </p>
 845      *
 846      * <ol>
 847      *
 848      *   <li><p> Initially, the result string is empty.  </p></li>
 849      *
 850      *   <li><p> If a scheme is given then it is appended to the result,
 851      *   followed by a colon character ({@code ':'}).  </p></li>
 852      *
 853      *   <li><p> If a scheme-specific part is given then it is appended.  Any
 854      *   character that is not a <a href="#legal-chars">legal URI character</a>
 855      *   is <a href="#quote">quoted</a>.  </p></li>
 856      *
 857      *   <li><p> Finally, if a fragment is given then a hash character
 858      *   ({@code '#'}) is appended to the string, followed by the fragment.
 859      *   Any character that is not a legal URI character is quoted.  </p></li>
 860      *
 861      * </ol>
 862      *
 863      * <p> The resulting URI string is then parsed in order to create the new
 864      * URI instance as if by invoking the {@link #URI(String)} constructor;
 865      * this may cause a {@link URISyntaxException} to be thrown.  </p>
 866      *
 867      * @param   scheme    Scheme name
 868      * @param   ssp       Scheme-specific part
 869      * @param   fragment  Fragment
 870      *
 871      * @throws  URISyntaxException
 872      *          If the URI string constructed from the given components
 873      *          violates RFC&nbsp;2396
 874      */
 875     public URI(String scheme, String ssp, String fragment)
 876         throws URISyntaxException
 877     {
 878         new Parser(toString(scheme, ssp,
 879                             null, null, null, -1,
 880                             null, null, fragment))
 881             .parse(false);
 882     }
 883 
 884     /**
 885      * Constructs a simple URI consisting of only a scheme and a pre-validated
 886      * path. Provides a fast-path for some internal cases.
 887      */
 888     URI(String scheme, String path) {
 889         assert validSchemeAndPath(scheme, path);
 890         this.scheme = scheme;
 891         this.path = path;
 892     }
 893 
 894     private static boolean validSchemeAndPath(String scheme, String path) {
 895         try {
 896             URI u = new URI(scheme + ':' + path);
 897             return scheme.equals(u.scheme) && path.equals(u.path);
 898         } catch (URISyntaxException e) {
 899             return false;
 900         }
 901     }
 902 
 903     /**
 904      * Creates a URI by parsing the given string.
 905      *
 906      * <p> This convenience factory method works as if by invoking the {@link
 907      * #URI(String)} constructor; any {@link URISyntaxException} thrown by the
 908      * constructor is caught and wrapped in a new {@link
 909      * IllegalArgumentException} object, which is then thrown.
 910      *
 911      * <p> This method is provided for use in situations where it is known that
 912      * the given string is a legal URI, for example for URI constants declared
 913      * within a program, and so it would be considered a programming error
 914      * for the string not to parse as such.  The constructors, which throw
 915      * {@link URISyntaxException} directly, should be used in situations where a
 916      * URI is being constructed from user input or from some other source that
 917      * may be prone to errors.  </p>
 918      *
 919      * @param  str   The string to be parsed into a URI
 920      * @return The new URI
 921      *
 922      * @throws  NullPointerException
 923      *          If {@code str} is {@code null}
 924      *
 925      * @throws  IllegalArgumentException
 926      *          If the given string violates RFC&nbsp;2396
 927      */
 928     public static URI create(String str) {
 929         try {
 930             return new URI(str);
 931         } catch (URISyntaxException x) {
 932             throw new IllegalArgumentException(x.getMessage(), x);
 933         }
 934     }
 935 
 936 
 937     // -- Operations --
 938 
 939     /**
 940      * Attempts to parse this URI's authority component, if defined, into
 941      * user-information, host, and port components.
 942      *
 943      * <p> If this URI's authority component has already been recognized as
 944      * being server-based then it will already have been parsed into
 945      * user-information, host, and port components.  In this case, or if this
 946      * URI has no authority component, this method simply returns this URI.
 947      *
 948      * <p> Otherwise this method attempts once more to parse the authority
 949      * component into user-information, host, and port components, and throws
 950      * an exception describing why the authority component could not be parsed
 951      * in that way.
 952      *
 953      * <p> This method is provided because the generic URI syntax specified in
 954      * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>
 955      * cannot always distinguish a malformed server-based authority from a
 956      * legitimate registry-based authority.  It must therefore treat some
 957      * instances of the former as instances of the latter.  The authority
 958      * component in the URI string {@code "//foo:bar"}, for example, is not a
 959      * legal server-based authority but it is legal as a registry-based
 960      * authority.
 961      *
 962      * <p> In many common situations, for example when working URIs that are
 963      * known to be either URNs or URLs, the hierarchical URIs being used will
 964      * always be server-based.  They therefore must either be parsed as such or
 965      * treated as an error.  In these cases a statement such as
 966      *
 967      * <blockquote>
 968      * {@code URI }<i>u</i>{@code  = new URI(str).parseServerAuthority();}
 969      * </blockquote>
 970      *
 971      * <p> can be used to ensure that <i>u</i> always refers to a URI that, if
 972      * it has an authority component, has a server-based authority with proper
 973      * user-information, host, and port components.  Invoking this method also
 974      * ensures that if the authority could not be parsed in that way then an
 975      * appropriate diagnostic message can be issued based upon the exception
 976      * that is thrown. </p>
 977      *
 978      * @return  A URI whose authority field has been parsed
 979      *          as a server-based authority
 980      *
 981      * @throws  URISyntaxException
 982      *          If the authority component of this URI is defined
 983      *          but cannot be parsed as a server-based authority
 984      *          according to RFC&nbsp;2396
 985      *
 986      * @spec https://www.rfc-editor.org/info/rfc2396
 987      *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
 988      */
 989     public URI parseServerAuthority()
 990         throws URISyntaxException
 991     {
 992         // We could be clever and cache the error message and index from the
 993         // exception thrown during the original parse, but that would require
 994         // either more fields or a more-obscure representation.
 995         if ((host != null) || (authority == null))
 996             return this;
 997         new Parser(toString()).parse(true);
 998         return this;
 999     }
1000 
1001     /**
1002      * Normalizes this URI's path.
1003      *
1004      * <p> If this URI is opaque, or if its path is already in normal form,
1005      * then this URI is returned.  Otherwise a new URI is constructed that is
1006      * identical to this URI except that its path is computed by normalizing
1007      * this URI's path in a manner consistent with <a
1008      * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
1009      * section&nbsp;5.2, step&nbsp;6, sub-steps&nbsp;c through&nbsp;f; that is:
1010      * </p>
1011      *
1012      * <ol>
1013      *
1014      *   <li><p> All {@code "."} segments are removed. </p></li>
1015      *
1016      *   <li><p> If a {@code ".."} segment is preceded by a non-{@code ".."}
1017      *   segment then both of these segments are removed.  This step is
1018      *   repeated until it is no longer applicable. </p></li>
1019      *
1020      *   <li><p> If the path is relative, and if its first segment contains a
1021      *   colon character ({@code ':'}), then a {@code "."} segment is
1022      *   prepended.  This prevents a relative URI with a path such as
1023      *   {@code "a:b/c/d"} from later being re-parsed as an opaque URI with a
1024      *   scheme of {@code "a"} and a scheme-specific part of {@code "b/c/d"}.
1025      *   <b><i>(Deviation from RFC&nbsp;2396)</i></b> </p></li>
1026      *
1027      * </ol>
1028      *
1029      * <p> A normalized path will begin with one or more {@code ".."} segments
1030      * if there were insufficient non-{@code ".."} segments preceding them to
1031      * allow their removal.  A normalized path will begin with a {@code "."}
1032      * segment if one was inserted by step 3 above.  Otherwise, a normalized
1033      * path will not contain any {@code "."} or {@code ".."} segments. </p>
1034      *
1035      * @return  A URI equivalent to this URI,
1036      *          but whose path is in normal form
1037      * @spec https://www.rfc-editor.org/info/rfc2396
1038      *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
1039      */
1040     public URI normalize() {
1041         return normalize(this);
1042     }
1043 
1044     /**
1045      * Resolves the given URI against this URI.
1046      *
1047      * <p> If the given URI is already absolute, or if this URI is opaque, then
1048      * the given URI is returned.
1049      *
1050      * <p><a id="resolve-frag"></a> If the given URI's fragment component is
1051      * defined, its path component is empty, and its scheme, authority, and
1052      * query components are undefined, then a URI with the given fragment but
1053      * with all other components equal to those of this URI is returned.  This
1054      * allows a URI representing a standalone fragment reference, such as
1055      * {@code "#foo"}, to be usefully resolved against a base URI.
1056      *
1057      * <p> Otherwise this method constructs a new hierarchical URI in a manner
1058      * consistent with <a
1059      * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
1060      * section&nbsp;5.2; that is: </p>
1061      *
1062      * <ol>
1063      *
1064      *   <li><p> A new URI is constructed with this URI's scheme and the given
1065      *   URI's query and fragment components. </p></li>
1066      *
1067      *   <li><p> If the given URI has an authority component then the new URI's
1068      *   authority and path are taken from the given URI. </p></li>
1069      *
1070      *   <li><p> Otherwise the new URI's authority component is copied from
1071      *   this URI, and its path is computed as follows: </p>
1072      *
1073      *   <ol>
1074      *
1075      *     <li><p> If the given URI's path is absolute then the new URI's path
1076      *     is taken from the given URI. </p></li>
1077      *
1078      *     <li><p> Otherwise the given URI's path is relative, and so the new
1079      *     URI's path is computed by resolving the path of the given URI
1080      *     against the path of this URI.  This is done by concatenating all but
1081      *     the last segment of this URI's path, if any, with the given URI's
1082      *     path and then normalizing the result as if by invoking the {@link
1083      *     #normalize() normalize} method. </p></li>
1084      *
1085      *   </ol></li>
1086      *
1087      * </ol>
1088      *
1089      * <p> The result of this method is absolute if, and only if, either this
1090      * URI is absolute or the given URI is absolute.  </p>
1091      *
1092      * @param  uri  The URI to be resolved against this URI
1093      * @return The resulting URI
1094      *
1095      * @throws  NullPointerException
1096      *          If {@code uri} is {@code null}
1097      * @spec https://www.rfc-editor.org/info/rfc2396
1098      *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
1099      */
1100     public URI resolve(URI uri) {
1101         return resolve(this, uri);
1102     }
1103 
1104     /**
1105      * Constructs a new URI by parsing the given string and then resolving it
1106      * against this URI.
1107      *
1108      * <p> This convenience method works as if invoking it were equivalent to
1109      * evaluating the expression {@link #resolve(java.net.URI)
1110      * resolve}{@code (URI.}{@link #create(String) create}{@code (str))}. </p>
1111      *
1112      * @param  str   The string to be parsed into a URI
1113      * @return The resulting URI
1114      *
1115      * @throws  NullPointerException
1116      *          If {@code str} is {@code null}
1117      *
1118      * @throws  IllegalArgumentException
1119      *          If the given string violates RFC&nbsp;2396
1120      */
1121     public URI resolve(String str) {
1122         return resolve(URI.create(str));
1123     }
1124 
1125     /**
1126      * Relativizes the given URI against this URI.
1127      *
1128      * <p> The relativization of the given URI against this URI is computed as
1129      * follows: </p>
1130      *
1131      * <ol>
1132      *
1133      *   <li><p> If either this URI or the given URI are opaque, or if the
1134      *   scheme and authority components of the two URIs are not identical, or
1135      *   if the path of this URI is not a prefix of the path of the given URI,
1136      *   then the given URI is returned. </p></li>
1137      *
1138      *   <li><p> Otherwise a new relative hierarchical URI is constructed with
1139      *   query and fragment components taken from the given URI and with a path
1140      *   component computed by removing this URI's path from the beginning of
1141      *   the given URI's path. </p></li>
1142      *
1143      * </ol>
1144      *
1145      * @param  uri  The URI to be relativized against this URI
1146      * @return The resulting URI
1147      *
1148      * @throws  NullPointerException
1149      *          If {@code uri} is {@code null}
1150      */
1151     public URI relativize(URI uri) {
1152         return relativize(this, uri);
1153     }
1154 
1155     /**
1156      * Constructs a URL from this URI.
1157      *
1158      * <p> This convenience method works as if invoking it were equivalent to
1159      * evaluating the expression {@code new URL(this.toString())} after
1160      * first checking that this URI is absolute. </p>
1161      *
1162      * @return  A URL constructed from this URI
1163      *
1164      * @throws  IllegalArgumentException
1165      *          If this URL is not absolute
1166      *
1167      * @throws  MalformedURLException
1168      *          If a protocol handler for the URL could not be found,
1169      *          or if some other error occurred while constructing the URL
1170      */
1171     public URL toURL() throws MalformedURLException {
1172         return URL.of(this, null);
1173     }
1174 
1175     // -- Component access methods --
1176 
1177     /**
1178      * Returns the scheme component of this URI.
1179      *
1180      * <p> The scheme component of a URI, if defined, only contains characters
1181      * in the <i>alphanum</i> category and in the string {@code "-.+"}.  A
1182      * scheme always starts with an <i>alpha</i> character. <p>
1183      *
1184      * The scheme component of a URI cannot contain escaped octets, hence this
1185      * method does not perform any decoding.
1186      *
1187      * @return  The scheme component of this URI,
1188      *          or {@code null} if the scheme is undefined
1189      */
1190     public String getScheme() {
1191         return scheme;
1192     }
1193 
1194     /**
1195      * Tells whether or not this URI is absolute.
1196      *
1197      * <p> A URI is absolute if, and only if, it has a scheme component. </p>
1198      *
1199      * @return  {@code true} if, and only if, this URI is absolute
1200      */
1201     public boolean isAbsolute() {
1202         return scheme != null;
1203     }
1204 
1205     /**
1206      * Tells whether or not this URI is opaque.
1207      *
1208      * <p> A URI is opaque if, and only if, it is absolute and its
1209      * scheme-specific part does not begin with a slash character ('/').
1210      * An opaque URI has a scheme, a scheme-specific part, and possibly
1211      * a fragment; all other components are undefined. </p>
1212      *
1213      * @return  {@code true} if, and only if, this URI is opaque
1214      */
1215     public boolean isOpaque() {
1216         return path == null;
1217     }
1218 
1219     /**
1220      * Returns the raw scheme-specific part of this URI.  The scheme-specific
1221      * part is never undefined, though it may be empty.
1222      *
1223      * <p> The scheme-specific part of a URI only contains legal URI
1224      * characters. </p>
1225      *
1226      * @return  The raw scheme-specific part of this URI
1227      *          (never {@code null})
1228      */
1229     public String getRawSchemeSpecificPart() {
1230         String part = schemeSpecificPart;
1231         if (part != null) {
1232             return part;
1233         }
1234 
1235         String s = string;
1236         if (s != null) {
1237             // if string is defined, components will have been parsed
1238             int start = 0;
1239             int end = s.length();
1240             if (scheme != null) {
1241                 start = scheme.length() + 1;
1242             }
1243             if (fragment != null) {
1244                 end -= fragment.length() + 1;
1245             }
1246             if (path != null && path.length() == end - start) {
1247                 part = path;
1248             } else {
1249                 part = s.substring(start, end);
1250             }
1251         } else {
1252             StringBuilder sb = new StringBuilder();
1253             appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
1254                                  host, port, getPath(), getQuery());
1255             part = sb.toString();
1256         }
1257         return schemeSpecificPart = part;
1258     }
1259 
1260     /**
1261      * Returns the decoded scheme-specific part of this URI.
1262      *
1263      * <p> The string returned by this method is equal to that returned by the
1264      * {@link #getRawSchemeSpecificPart() getRawSchemeSpecificPart} method
1265      * except that all sequences of escaped octets are <a
1266      * href="#decode">decoded</a>.  </p>
1267      *
1268      * @return  The decoded scheme-specific part of this URI
1269      *          (never {@code null})
1270      */
1271     public String getSchemeSpecificPart() {
1272         String part = decodedSchemeSpecificPart;
1273         if (part == null) {
1274             decodedSchemeSpecificPart = part = decode(getRawSchemeSpecificPart());
1275         }
1276         return part;
1277     }
1278 
1279     /**
1280      * Returns the raw authority component of this URI.
1281      *
1282      * <p> The authority component of a URI, if defined, only contains the
1283      * commercial-at character ({@code '@'}) and characters in the
1284      * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and <i>other</i>
1285      * categories.  If the authority is server-based then it is further
1286      * constrained to have valid user-information, host, and port
1287      * components. </p>
1288      *
1289      * @return  The raw authority component of this URI,
1290      *          or {@code null} if the authority is undefined
1291      */
1292     public String getRawAuthority() {
1293         return authority;
1294     }
1295 
1296     /**
1297      * Returns the decoded authority component of this URI.
1298      *
1299      * <p> The string returned by this method is equal to that returned by the
1300      * {@link #getRawAuthority() getRawAuthority} method except that all
1301      * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
1302      *
1303      * @return  The decoded authority component of this URI,
1304      *          or {@code null} if the authority is undefined
1305      */
1306     public String getAuthority() {
1307         String auth = decodedAuthority;
1308         if ((auth == null) && (authority != null)) {
1309             decodedAuthority = auth = decode(authority);
1310         }
1311         return auth;
1312     }
1313 
1314     /**
1315      * Returns the raw user-information component of this URI.
1316      *
1317      * <p> The user-information component of a URI, if defined, only contains
1318      * characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and
1319      * <i>other</i> categories. </p>
1320      *
1321      * @return  The raw user-information component of this URI,
1322      *          or {@code null} if the user information is undefined
1323      */
1324     public String getRawUserInfo() {
1325         return userInfo;
1326     }
1327 
1328     /**
1329      * Returns the decoded user-information component of this URI.
1330      *
1331      * <p> The string returned by this method is equal to that returned by the
1332      * {@link #getRawUserInfo() getRawUserInfo} method except that all
1333      * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
1334      *
1335      * @return  The decoded user-information component of this URI,
1336      *          or {@code null} if the user information is undefined
1337      */
1338     public String getUserInfo() {
1339         String user = decodedUserInfo;
1340         if ((user == null) && (userInfo != null)) {
1341             decodedUserInfo = user = decode(userInfo);
1342         }
1343         return user;
1344     }
1345 
1346     /**
1347      * Returns the host component of this URI.
1348      *
1349      * <p> The host component of a URI, if defined, will have one of the
1350      * following forms: </p>
1351      *
1352      * <ul>
1353      *
1354      *   <li><p> A domain name consisting of one or more <i>labels</i>
1355      *   separated by period characters ({@code '.'}), optionally followed by
1356      *   a period character.  Each label consists of <i>alphanum</i> characters
1357      *   as well as hyphen characters ({@code '-'}), though hyphens never
1358      *   occur as the first or last characters in a label. The rightmost
1359      *   label of a domain name consisting of two or more labels, begins
1360      *   with an <i>alpha</i> character. </li>
1361      *
1362      *   <li><p> A dotted-quad IPv4 address of the form
1363      *   <i>digit</i>{@code +.}<i>digit</i>{@code +.}<i>digit</i>{@code +.}<i>digit</i>{@code +},
1364      *   where no <i>digit</i> sequence is longer than three characters and no
1365      *   sequence has a value larger than 255. </p></li>
1366      *
1367      *   <li><p> An IPv6 address enclosed in square brackets ({@code '['} and
1368      *   {@code ']'}) and consisting of hexadecimal digits, colon characters
1369      *   ({@code ':'}), and possibly an embedded IPv4 address.  The full
1370      *   syntax of IPv6 addresses is specified in <a
1371      *   href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IPv6
1372      *   Addressing Architecture</i></a>.  </p></li>
1373      *
1374      * </ul>
1375      *
1376      * The host component of a URI cannot contain escaped octets, hence this
1377      * method does not perform any decoding.
1378      *
1379      * @return  The host component of this URI,
1380      *          or {@code null} if the host is undefined
1381      * @spec https://www.rfc-editor.org/info/rfc2373
1382      *      RFC 2373: IP Version 6 Addressing Architecture
1383      */
1384     public String getHost() {
1385         return host;
1386     }
1387 
1388     /**
1389      * Returns the port number of this URI.
1390      *
1391      * <p> The port component of a URI, if defined, is a non-negative
1392      * integer. </p>
1393      *
1394      * @return  The port component of this URI,
1395      *          or {@code -1} if the port is undefined
1396      */
1397     public int getPort() {
1398         return port;
1399     }
1400 
1401     /**
1402      * Returns the raw path component of this URI.
1403      *
1404      * <p> The path component of a URI, if defined, only contains the slash
1405      * character ({@code '/'}), the commercial-at character ({@code '@'}),
1406      * and characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>,
1407      * and <i>other</i> categories. </p>
1408      *
1409      * @return  The path component of this URI,
1410      *          or {@code null} if the path is undefined
1411      */
1412     public String getRawPath() {
1413         return path;
1414     }
1415 
1416     /**
1417      * Returns the decoded path component of this URI.
1418      *
1419      * <p> The string returned by this method is equal to that returned by the
1420      * {@link #getRawPath() getRawPath} method except that all sequences of
1421      * escaped octets are <a href="#decode">decoded</a>.  </p>
1422      *
1423      * @return  The decoded path component of this URI,
1424      *          or {@code null} if the path is undefined
1425      */
1426     public String getPath() {
1427         String decoded = decodedPath;
1428         if ((decoded == null) && (path != null)) {
1429             decodedPath = decoded = decode(path);
1430         }
1431         return decoded;
1432     }
1433 
1434     /**
1435      * Returns the raw query component of this URI.
1436      *
1437      * <p> The query component of a URI, if defined, only contains legal URI
1438      * characters. </p>
1439      *
1440      * @return  The raw query component of this URI,
1441      *          or {@code null} if the query is undefined
1442      */
1443     public String getRawQuery() {
1444         return query;
1445     }
1446 
1447     /**
1448      * Returns the decoded query component of this URI.
1449      *
1450      * <p> The string returned by this method is equal to that returned by the
1451      * {@link #getRawQuery() getRawQuery} method except that all sequences of
1452      * escaped octets are <a href="#decode">decoded</a>.  </p>
1453      *
1454      * @return  The decoded query component of this URI,
1455      *          or {@code null} if the query is undefined
1456      */
1457     public String getQuery() {
1458         String decoded = decodedQuery;
1459         if ((decoded == null) && (query != null)) {
1460             decodedQuery = decoded = decode(query, false);
1461         }
1462         return decoded;
1463     }
1464 
1465     /**
1466      * Returns the raw fragment component of this URI.
1467      *
1468      * <p> The fragment component of a URI, if defined, only contains legal URI
1469      * characters. </p>
1470      *
1471      * @return  The raw fragment component of this URI,
1472      *          or {@code null} if the fragment is undefined
1473      */
1474     public String getRawFragment() {
1475         return fragment;
1476     }
1477 
1478     /**
1479      * Returns the decoded fragment component of this URI.
1480      *
1481      * <p> The string returned by this method is equal to that returned by the
1482      * {@link #getRawFragment() getRawFragment} method except that all
1483      * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
1484      *
1485      * @return  The decoded fragment component of this URI,
1486      *          or {@code null} if the fragment is undefined
1487      */
1488     public String getFragment() {
1489         String decoded = decodedFragment;
1490         if ((decoded == null) && (fragment != null)) {
1491             decodedFragment = decoded = decode(fragment, false);
1492         }
1493         return decoded;
1494     }
1495 
1496 
1497     // -- Equality, comparison, hash code, toString, and serialization --
1498 
1499     /**
1500      * Tests this URI for equality with another object.
1501      *
1502      * <p> If the given object is not a URI then this method immediately
1503      * returns {@code false}.
1504      *
1505      * <p> For two URIs to be considered equal requires that either both are
1506      * opaque or both are hierarchical.  Their schemes must either both be
1507      * undefined or else be equal without regard to case. Their fragments
1508      * must either both be undefined or else be equal.
1509      *
1510      * <p> For two opaque URIs to be considered equal, their scheme-specific
1511      * parts must be equal.
1512      *
1513      * <p> For two hierarchical URIs to be considered equal, their paths must
1514      * be equal and their queries must either both be undefined or else be
1515      * equal.  Their authorities must either both be undefined, or both be
1516      * registry-based, or both be server-based.  If their authorities are
1517      * defined and are registry-based, then they must be equal.  If their
1518      * authorities are defined and are server-based, then their hosts must be
1519      * equal without regard to case, their port numbers must be equal, and
1520      * their user-information components must be equal.
1521      *
1522      * <p> When testing the user-information, path, query, fragment, authority,
1523      * or scheme-specific parts of two URIs for equality, the raw forms rather
1524      * than the encoded forms of these components are compared and the
1525      * hexadecimal digits of escaped octets are compared without regard to
1526      * case.
1527      *
1528      * <p> This method satisfies the general contract of the {@link
1529      * java.lang.Object#equals(Object) Object.equals} method. </p>
1530      *
1531      * @param   ob   The object to which this object is to be compared
1532      *
1533      * @return  {@code true} if, and only if, the given object is a URI that
1534      *          is identical to this URI
1535      */
1536     public boolean equals(Object ob) {
1537         if (ob == this)
1538             return true;
1539         if (!(ob instanceof URI that))
1540             return false;
1541         if (this.isOpaque() != that.isOpaque()) return false;
1542         if (!equalIgnoringCase(this.scheme, that.scheme)) return false;
1543         if (!equal(this.fragment, that.fragment)) return false;
1544 
1545         // Opaque
1546         if (this.isOpaque())
1547             return equal(this.schemeSpecificPart, that.schemeSpecificPart);
1548 
1549         // Hierarchical
1550         if (!equal(this.path, that.path)) return false;
1551         if (!equal(this.query, that.query)) return false;
1552 
1553         // Authorities
1554         if (this.authority == that.authority) return true;
1555         if (this.host != null) {
1556             // Server-based
1557             if (!equal(this.userInfo, that.userInfo)) return false;
1558             if (!equalIgnoringCase(this.host, that.host)) return false;
1559             if (this.port != that.port) return false;
1560         } else if (this.authority != null) {
1561             // Registry-based
1562             if (!equal(this.authority, that.authority)) return false;
1563         } else if (this.authority != that.authority) {
1564             return false;
1565         }
1566 
1567         return true;
1568     }
1569 
1570     /**
1571      * Returns a hash-code value for this URI.  The hash code is based upon all
1572      * of the URI's components, and satisfies the general contract of the
1573      * {@link java.lang.Object#hashCode() Object.hashCode} method.
1574      *
1575      * @return  A hash-code value for this URI
1576      */
1577     public int hashCode() {
1578         int h = hash;
1579         if (h == 0) {
1580             h = hashIgnoringCase(0, scheme);
1581             h = hash(h, fragment);
1582             if (isOpaque()) {
1583                 h = hash(h, schemeSpecificPart);
1584             } else {
1585                 h = hash(h, path);
1586                 h = hash(h, query);
1587                 if (host != null) {
1588                     h = hash(h, userInfo);
1589                     h = hashIgnoringCase(h, host);
1590                     h += 1949 * port;
1591                 } else {
1592                     h = hash(h, authority);
1593                 }
1594             }
1595             if (h != 0) {
1596                 hash = h;
1597             }
1598         }
1599         return h;
1600     }
1601 
1602     /**
1603      * Compares this URI to another object, which must be a URI.
1604      *
1605      * <p> When comparing corresponding components of two URIs, if one
1606      * component is undefined but the other is defined then the first is
1607      * considered to be less than the second.  Unless otherwise noted, string
1608      * components are ordered according to their natural, case-sensitive
1609      * ordering as defined by the {@link java.lang.String#compareTo(String)
1610      * String.compareTo} method.  String components that are subject to
1611      * encoding are compared by comparing their raw forms rather than their
1612      * encoded forms and the hexadecimal digits of escaped octets are compared
1613      * without regard to case.
1614      *
1615      * <p> The ordering of URIs is defined as follows: </p>
1616      *
1617      * <ul>
1618      *
1619      *   <li><p> Two URIs with different schemes are ordered according the
1620      *   ordering of their schemes, without regard to case. </p></li>
1621      *
1622      *   <li><p> A hierarchical URI is considered to be less than an opaque URI
1623      *   with an identical scheme. </p></li>
1624      *
1625      *   <li><p> Two opaque URIs with identical schemes are ordered according
1626      *   to the ordering of their scheme-specific parts. </p></li>
1627      *
1628      *   <li><p> Two opaque URIs with identical schemes and scheme-specific
1629      *   parts are ordered according to the ordering of their
1630      *   fragments. </p></li>
1631      *
1632      *   <li><p> Two hierarchical URIs with identical schemes are ordered
1633      *   according to the ordering of their authority components: </p>
1634      *
1635      *   <ul>
1636      *
1637      *     <li><p> If both authority components are server-based then the URIs
1638      *     are ordered according to their user-information components; if these
1639      *     components are identical then the URIs are ordered according to the
1640      *     ordering of their hosts, without regard to case; if the hosts are
1641      *     identical then the URIs are ordered according to the ordering of
1642      *     their ports. </p></li>
1643      *
1644      *     <li><p> If one or both authority components are registry-based then
1645      *     the URIs are ordered according to the ordering of their authority
1646      *     components. </p></li>
1647      *
1648      *   </ul></li>
1649      *
1650      *   <li><p> Finally, two hierarchical URIs with identical schemes and
1651      *   authority components are ordered according to the ordering of their
1652      *   paths; if their paths are identical then they are ordered according to
1653      *   the ordering of their queries; if the queries are identical then they
1654      *   are ordered according to the order of their fragments. </p></li>
1655      *
1656      * </ul>
1657      *
1658      * <p> This method satisfies the general contract of the {@link
1659      * java.lang.Comparable#compareTo(Object) Comparable.compareTo}
1660      * method. </p>
1661      *
1662      * @param   that
1663      *          The object to which this URI is to be compared
1664      *
1665      * @return  A negative integer, zero, or a positive integer as this URI is
1666      *          less than, equal to, or greater than the given URI
1667      *
1668      * @throws  ClassCastException
1669      *          If the given object is not a URI
1670      */
1671     public int compareTo(URI that) {
1672         int c;
1673 
1674         if ((c = compareIgnoringCase(this.scheme, that.scheme)) != 0)
1675             return c;
1676 
1677         if (this.isOpaque()) {
1678             if (that.isOpaque()) {
1679                 // Both opaque
1680                 if ((c = compare(this.schemeSpecificPart,
1681                                  that.schemeSpecificPart)) != 0)
1682                     return c;
1683                 return compare(this.fragment, that.fragment);
1684             }
1685             return +1;                  // Opaque > hierarchical
1686         } else if (that.isOpaque()) {
1687             return -1;                  // Hierarchical < opaque
1688         }
1689 
1690         // Hierarchical
1691         if ((this.host != null) && (that.host != null)) {
1692             // Both server-based
1693             if ((c = compare(this.userInfo, that.userInfo)) != 0)
1694                 return c;
1695             if ((c = compareIgnoringCase(this.host, that.host)) != 0)
1696                 return c;
1697             if ((c = this.port - that.port) != 0)
1698                 return c;
1699         } else {
1700             // If one or both authorities are registry-based then we simply
1701             // compare them in the usual, case-sensitive way.  If one is
1702             // registry-based and one is server-based then the strings are
1703             // guaranteed to be unequal, hence the comparison will never return
1704             // zero and the compareTo and equals methods will remain
1705             // consistent.
1706             if ((c = compare(this.authority, that.authority)) != 0) return c;
1707         }
1708 
1709         if ((c = compare(this.path, that.path)) != 0) return c;
1710         if ((c = compare(this.query, that.query)) != 0) return c;
1711         return compare(this.fragment, that.fragment);
1712     }
1713 
1714     /**
1715      * Returns the content of this URI as a string.
1716      *
1717      * <p> If this URI was created by invoking one of the constructors in this
1718      * class then a string equivalent to the original input string, or to the
1719      * string computed from the originally-given components, as appropriate, is
1720      * returned.  Otherwise this URI was created by normalization, resolution,
1721      * or relativization, and so a string is constructed from this URI's
1722      * components according to the rules specified in <a
1723      * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
1724      * section&nbsp;5.2, step&nbsp;7. </p>
1725      *
1726      * @return  The string form of this URI
1727      * @spec https://www.rfc-editor.org/info/rfc2396
1728      *      RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax
1729      */
1730     public String toString() {
1731         String s = string;
1732         if (s == null) {
1733             s = defineString();
1734         }
1735         return s;
1736     }
1737 
1738     private String defineString() {
1739         String s = string;
1740         if (s != null) {
1741             return s;
1742         }
1743 
1744         StringBuilder sb = new StringBuilder();
1745         if (scheme != null) {
1746             sb.append(scheme);
1747             sb.append(':');
1748         }
1749         if (isOpaque()) {
1750             sb.append(schemeSpecificPart);
1751         } else {
1752             if (host != null) {
1753                 sb.append("//");
1754                 if (userInfo != null) {
1755                     sb.append(userInfo);
1756                     sb.append('@');
1757                 }
1758                 boolean needBrackets = ((host.indexOf(':') >= 0)
1759                         && !host.startsWith("[")
1760                         && !host.endsWith("]"));
1761                 if (needBrackets) sb.append('[');
1762                 sb.append(host);
1763                 if (needBrackets) sb.append(']');
1764                 if (port != -1) {
1765                     sb.append(':');
1766                     sb.append(port);
1767                 }
1768             } else if (authority != null) {
1769                 sb.append("//");
1770                 sb.append(authority);
1771             }
1772             if (path != null)
1773                 sb.append(path);
1774             if (query != null) {
1775                 sb.append('?');
1776                 sb.append(query);
1777             }
1778         }
1779         if (fragment != null) {
1780             sb.append('#');
1781             sb.append(fragment);
1782         }
1783         return string = sb.toString();
1784     }
1785 
1786     /**
1787      * Returns the content of this URI as a US-ASCII string.
1788      *
1789      * <p> If this URI does not contain any characters in the <i>other</i>
1790      * category then an invocation of this method will return the same value as
1791      * an invocation of the {@link #toString() toString} method.  Otherwise
1792      * this method works as if by invoking that method and then <a
1793      * href="#encode">encoding</a> the result.  </p>
1794      *
1795      * @return  The string form of this URI, encoded as needed
1796      *          so that it only contains characters in the US-ASCII
1797      *          charset
1798      */
1799     public String toASCIIString() {
1800         return encode(toString());
1801     }
1802 
1803 
1804     // -- Serialization support --
1805 
1806     /**
1807      * Saves the content of this URI to the given serial stream.
1808      *
1809      * <p> The only serializable field of a URI instance is its {@code string}
1810      * field.  That field is given a value, if it does not have one already,
1811      * and then the {@link java.io.ObjectOutputStream#defaultWriteObject()}
1812      * method of the given object-output stream is invoked. </p>
1813      *
1814      * @param  os  The object-output stream to which this object
1815      *             is to be written
1816      *
1817      * @throws IOException
1818      *         If an I/O error occurs
1819      */
1820     @java.io.Serial
1821     private void writeObject(ObjectOutputStream os)
1822         throws IOException
1823     {
1824         defineString();
1825         os.defaultWriteObject();        // Writes the string field only
1826     }
1827 
1828     /**
1829      * Reconstitutes a URI from the given serial stream.
1830      *
1831      * <p> The {@link java.io.ObjectInputStream#defaultReadObject()} method is
1832      * invoked to read the value of the {@code string} field.  The result is
1833      * then parsed in the usual way.
1834      *
1835      * @param  is  The object-input stream from which this object
1836      *             is being read
1837      *
1838      * @throws IOException
1839      *         If an I/O error occurs
1840      *
1841      * @throws ClassNotFoundException
1842      *         If a serialized class cannot be loaded
1843      */
1844     @java.io.Serial
1845     private void readObject(ObjectInputStream is)
1846         throws ClassNotFoundException, IOException
1847     {
1848         port = -1;                      // Argh
1849         is.defaultReadObject();
1850         try {
1851             new Parser(string).parse(false);
1852         } catch (URISyntaxException x) {
1853             IOException y = new InvalidObjectException("Invalid URI");
1854             y.initCause(x);
1855             throw y;
1856         }
1857     }
1858 
1859 
1860     // -- End of public methods --
1861 
1862 
1863     // -- Utility methods for string-field comparison and hashing --
1864 
1865     // These methods return appropriate values for null string arguments,
1866     // thereby simplifying the equals, hashCode, and compareTo methods.
1867     //
1868     // The case-ignoring methods should only be applied to strings whose
1869     // characters are all known to be US-ASCII.  Because of this restriction,
1870     // these methods are faster than the similar methods in the String class.
1871 
1872     // US-ASCII only
1873     private static int toLower(char c) {
1874         if ((c >= 'A') && (c <= 'Z'))
1875             return c + ('a' - 'A');
1876         return c;
1877     }
1878 
1879     // US-ASCII only
1880     private static int toUpper(char c) {
1881         if ((c >= 'a') && (c <= 'z'))
1882             return c - ('a' - 'A');
1883         return c;
1884     }
1885 
1886     private static boolean equal(String s, String t) {
1887         boolean testForEquality = true;
1888         int result = percentNormalizedComparison(s, t, testForEquality);
1889         return result == 0;
1890     }
1891 
1892     // US-ASCII only
1893     private static boolean equalIgnoringCase(String s, String t) {
1894         if (s == t) return true;
1895         if ((s != null) && (t != null)) {
1896             int n = s.length();
1897             if (t.length() != n)
1898                 return false;
1899             for (int i = 0; i < n; i++) {
1900                 if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
1901                     return false;
1902             }
1903             return true;
1904         }
1905         return false;
1906     }
1907 
1908     private static int hash(int hash, String s) {
1909         if (s == null) return hash;
1910         return s.indexOf('%') < 0 ? hash * 127 + s.hashCode()
1911                                   : normalizedHash(hash, s);
1912     }
1913 
1914 
1915     private static int normalizedHash(int hash, String s) {
1916         int h = 0;
1917         for (int index = 0; index < s.length(); index++) {
1918             char ch = s.charAt(index);
1919             h = 31 * h + ch;
1920             if (ch == '%') {
1921                 /*
1922                  * Process the next two encoded characters
1923                  */
1924                 for (int i = index + 1; i < index + 3; i++)
1925                     h = 31 * h + toUpper(s.charAt(i));
1926                 index += 2;
1927             }
1928         }
1929         return hash * 127 + h;
1930     }
1931 
1932     // US-ASCII only
1933     private static int hashIgnoringCase(int hash, String s) {
1934         if (s == null) return hash;
1935         int h = hash;
1936         int n = s.length();
1937         for (int i = 0; i < n; i++)
1938             h = 31 * h + toLower(s.charAt(i));
1939         return h;
1940     }
1941 
1942     private static int compare(String s, String t) {
1943         boolean testForEquality = false;
1944         int result = percentNormalizedComparison(s, t, testForEquality);
1945         return result;
1946     }
1947 
1948     // The percentNormalizedComparison method does not verify two
1949     // characters that follow the % sign are hexadecimal digits.
1950     // Reason being:
1951     // 1) percentNormalizedComparison method is not called with
1952     // 'decoded' strings
1953     // 2) The only place where a percent can be followed by anything
1954     // other than hexadecimal digits is in the authority component
1955     // (for a IPv6 scope) and the whole authority component is case
1956     // insensitive.
1957     private static int percentNormalizedComparison(String s, String t,
1958                                                    boolean testForEquality) {
1959 
1960         if (s == t) return 0;
1961         if (s != null) {
1962             if (t != null) {
1963                 if (s.indexOf('%') < 0) {
1964                     return s.compareTo(t);
1965                 }
1966                 int sn = s.length();
1967                 int tn = t.length();
1968                 if ((sn != tn) && testForEquality)
1969                     return sn - tn;
1970                 int val = 0;
1971                 int n = Math.min(sn, tn);
1972                 for (int i = 0; i < n; ) {
1973                     char c = s.charAt(i);
1974                     char d = t.charAt(i);
1975                     val = c - d;
1976                     if (c != '%') {
1977                         if (val != 0)
1978                             return val;
1979                         i++;
1980                         continue;
1981                     }
1982                     if (d != '%') {
1983                         if (val != 0)
1984                             return val;
1985                     }
1986                     i++;
1987                     val = toLower(s.charAt(i)) - toLower(t.charAt(i));
1988                     if (val != 0)
1989                         return val;
1990                     i++;
1991                     val = toLower(s.charAt(i)) - toLower(t.charAt(i));
1992                     if (val != 0)
1993                         return val;
1994                     i++;
1995                 }
1996                 return sn - tn;
1997             } else
1998                 return +1;
1999         } else {
2000             return -1;
2001         }
2002     }
2003 
2004     // US-ASCII only
2005     private static int compareIgnoringCase(String s, String t) {
2006         if (s == t) return 0;
2007         if (s != null) {
2008             if (t != null) {
2009                 int sn = s.length();
2010                 int tn = t.length();
2011                 int n = sn < tn ? sn : tn;
2012                 for (int i = 0; i < n; i++) {
2013                     int c = toLower(s.charAt(i)) - toLower(t.charAt(i));
2014                     if (c != 0)
2015                         return c;
2016                 }
2017                 return sn - tn;
2018             }
2019             return +1;
2020         } else {
2021             return -1;
2022         }
2023     }
2024 
2025 
2026     // -- String construction --
2027 
2028     // If a scheme is given then the path, if given, must be absolute
2029     //
2030     private static void checkPath(String s, String scheme, String path)
2031         throws URISyntaxException
2032     {
2033         if (scheme != null) {
2034             if (path != null && !path.isEmpty() && path.charAt(0) != '/')
2035                 throw new URISyntaxException(s, "Relative path in absolute URI");
2036         }
2037     }
2038 
2039     private void appendAuthority(StringBuilder sb,
2040                                  String authority,
2041                                  String userInfo,
2042                                  String host,
2043                                  int port)
2044     {
2045         if (host != null) {
2046             sb.append("//");
2047             if (userInfo != null) {
2048                 sb.append(quote(userInfo, L_USERINFO, H_USERINFO));
2049                 sb.append('@');
2050             }
2051             boolean needBrackets = ((host.indexOf(':') >= 0)
2052                                     && !host.startsWith("[")
2053                                     && !host.endsWith("]"));
2054             if (needBrackets) sb.append('[');
2055             sb.append(host);
2056             if (needBrackets) sb.append(']');
2057             if (port != -1) {
2058                 sb.append(':');
2059                 sb.append(port);
2060             }
2061         } else if (authority != null) {
2062             sb.append("//");
2063             if (authority.startsWith("[")) {
2064                 // authority should (but may not) contain an embedded IPv6 address
2065                 int end = authority.indexOf(']');
2066                 String doquote = authority;
2067                 if (end != -1 && authority.indexOf(':') != -1) {
2068                     // the authority contains an IPv6 address
2069                     sb.append(authority, 0, end + 1);
2070                     doquote = authority.substring(end + 1);
2071                 }
2072                 sb.append(quote(doquote,
2073                             L_REG_NAME | L_SERVER,
2074                             H_REG_NAME | H_SERVER));
2075             } else {
2076                 sb.append(quote(authority,
2077                             L_REG_NAME | L_SERVER,
2078                             H_REG_NAME | H_SERVER));
2079             }
2080         }
2081     }
2082 
2083     private void appendSchemeSpecificPart(StringBuilder sb,
2084                                           String opaquePart,
2085                                           String authority,
2086                                           String userInfo,
2087                                           String host,
2088                                           int port,
2089                                           String path,
2090                                           String query)
2091     {
2092         if (opaquePart != null) {
2093             /* check if SSP begins with an IPv6 address
2094              * because we must not quote a literal IPv6 address
2095              */
2096             if (opaquePart.startsWith("//[")) {
2097                 int end =  opaquePart.indexOf(']');
2098                 if (end != -1 && opaquePart.indexOf(':')!=-1) {
2099                     String doquote = opaquePart.substring(end + 1);
2100                     sb.append(opaquePart, 0, end + 1);
2101                     sb.append(quote(doquote, L_URIC, H_URIC));
2102                 }
2103             } else {
2104                 sb.append(quote(opaquePart, L_URIC, H_URIC));
2105             }
2106         } else {
2107             appendAuthority(sb, authority, userInfo, host, port);
2108             if (path != null)
2109                 sb.append(quote(path, L_PATH, H_PATH));
2110             if (query != null) {
2111                 sb.append('?');
2112                 sb.append(quote(query, L_URIC, H_URIC));
2113             }
2114         }
2115     }
2116 
2117     private void appendFragment(StringBuilder sb, String fragment) {
2118         if (fragment != null) {
2119             sb.append('#');
2120             sb.append(quote(fragment, L_URIC, H_URIC));
2121         }
2122     }
2123 
2124     private String toString(String scheme,
2125                             String opaquePart,
2126                             String authority,
2127                             String userInfo,
2128                             String host,
2129                             int port,
2130                             String path,
2131                             String query,
2132                             String fragment)
2133     {
2134         StringBuilder sb = new StringBuilder();
2135         if (scheme != null) {
2136             sb.append(scheme);
2137             sb.append(':');
2138         }
2139         appendSchemeSpecificPart(sb, opaquePart,
2140                                  authority, userInfo, host, port,
2141                                  path, query);
2142         appendFragment(sb, fragment);
2143         return sb.toString();
2144     }
2145 
2146     // -- Normalization, resolution, and relativization --
2147 
2148     // RFC2396 5.2 (6)
2149     private static String resolvePath(String base, String child, boolean absolute)
2150     {
2151         int i = base.lastIndexOf('/');
2152         int cn = child.length();
2153         String path = "";
2154 
2155         if (cn == 0) {
2156             // 5.2 (6a)
2157             if (i >= 0)
2158                 path = base.substring(0, i + 1);
2159         } else {
2160             // 5.2 (6a-b)
2161             if (i >= 0 || !absolute) {
2162                 path = base.substring(0, i + 1).concat(child);
2163             } else {
2164                 path = "/".concat(child);
2165             }
2166 
2167         }
2168 
2169         // 5.2 (6c-f)
2170         String np = normalize(path);
2171 
2172         // 5.2 (6g): If the result is absolute but the path begins with "../",
2173         // then we simply leave the path as-is
2174 
2175         return np;
2176     }
2177 
2178     // RFC2396 5.2
2179     private static URI resolve(URI base, URI child) {
2180         // check if child if opaque first so that NPE is thrown
2181         // if child is null.
2182         if (child.isOpaque() || base.isOpaque())
2183             return child;
2184 
2185         // 5.2 (2): Reference to current document (lone fragment)
2186         if ((child.scheme == null) && (child.authority == null)
2187             && child.path.isEmpty() && (child.fragment != null)
2188             && (child.query == null)) {
2189             if ((base.fragment != null)
2190                 && child.fragment.equals(base.fragment)) {
2191                 return base;
2192             }
2193             URI ru = new URI();
2194             ru.scheme = base.scheme;
2195             ru.authority = base.authority;
2196             ru.userInfo = base.userInfo;
2197             ru.host = base.host;
2198             ru.port = base.port;
2199             ru.path = base.path;
2200             ru.fragment = child.fragment;
2201             ru.query = base.query;
2202             return ru;
2203         }
2204 
2205         // 5.2 (3): Child is absolute
2206         if (child.scheme != null)
2207             return child;
2208 
2209         URI ru = new URI();             // Resolved URI
2210         ru.scheme = base.scheme;
2211         ru.query = child.query;
2212         ru.fragment = child.fragment;
2213 
2214         // 5.2 (4): Authority
2215         if (child.authority == null) {
2216             ru.authority = base.authority;
2217             ru.host = base.host;
2218             ru.userInfo = base.userInfo;
2219             ru.port = base.port;
2220 
2221             String cp = child.path;
2222             if (!cp.isEmpty() && cp.charAt(0) == '/') {
2223                 // 5.2 (5): Child path is absolute
2224                 ru.path = child.path;
2225             } else {
2226                 // 5.2 (6): Resolve relative path
2227                 ru.path = resolvePath(base.path, cp, base.isAbsolute());
2228             }
2229         } else {
2230             ru.authority = child.authority;
2231             ru.host = child.host;
2232             ru.userInfo = child.userInfo;
2233             ru.port = child.port;
2234             ru.path = child.path;
2235         }
2236 
2237         // 5.2 (7): Recombine (nothing to do here)
2238         return ru;
2239     }
2240 
2241     // If the given URI's path is normal then return the URI;
2242     // o.w., return a new URI containing the normalized path.
2243     //
2244     private static URI normalize(URI u) {
2245         if (u.isOpaque() || u.path == null || u.path.isEmpty())
2246             return u;
2247 
2248         String np = normalize(u.path);
2249         if (np == u.path)
2250             return u;
2251 
2252         URI v = new URI();
2253         v.scheme = u.scheme;
2254         v.fragment = u.fragment;
2255         v.authority = u.authority;
2256         v.userInfo = u.userInfo;
2257         v.host = u.host;
2258         v.port = u.port;
2259         v.path = np;
2260         v.query = u.query;
2261         return v;
2262     }
2263 
2264     // If both URIs are hierarchical, their scheme and authority components are
2265     // identical, and the base path is a prefix of the child's path, then
2266     // return a relative URI that, when resolved against the base, yields the
2267     // child; otherwise, return the child.
2268     //
2269     private static URI relativize(URI base, URI child) {
2270         // check if child if opaque first so that NPE is thrown
2271         // if child is null.
2272         if (child.isOpaque() || base.isOpaque())
2273             return child;
2274         if (!equalIgnoringCase(base.scheme, child.scheme)
2275             || !equal(base.authority, child.authority))
2276             return child;
2277 
2278         String bp = normalize(base.path);
2279         String cp = normalize(child.path);
2280         if (!bp.equals(cp)) {
2281             if (!bp.endsWith("/"))
2282                 bp = bp + "/";
2283             if (!cp.startsWith(bp))
2284                 return child;
2285         }
2286 
2287         URI v = new URI();
2288         v.path = cp.substring(bp.length());
2289         v.query = child.query;
2290         v.fragment = child.fragment;
2291         return v;
2292     }
2293 
2294 
2295 
2296     // -- Path normalization --
2297 
2298     // The following algorithm for path normalization avoids the creation of a
2299     // string object for each segment, as well as the use of a string buffer to
2300     // compute the final result, by using a single char array and editing it in
2301     // place.  The array is first split into segments, replacing each slash
2302     // with '\0' and creating a segment-index array, each element of which is
2303     // the index of the first char in the corresponding segment.  We then walk
2304     // through both arrays, removing ".", "..", and other segments as necessary
2305     // by setting their entries in the index array to -1.  Finally, the two
2306     // arrays are used to rejoin the segments and compute the final result.
2307     //
2308     // This code is based upon src/solaris/native/java/io/canonicalize_md.c
2309 
2310 
2311     // Check the given path to see if it might need normalization.  A path
2312     // might need normalization if it contains duplicate slashes, a "."
2313     // segment, or a ".." segment.  Return -1 if no further normalization is
2314     // possible, otherwise return the number of segments found.
2315     //
2316     // This method takes a string argument rather than a char array so that
2317     // this test can be performed without invoking path.toCharArray().
2318     //
2319     private static int needsNormalization(String path) {
2320         boolean normal = true;
2321         int ns = 0;                     // Number of segments
2322         int end = path.length() - 1;    // Index of last char in path
2323         int p = 0;                      // Index of next char in path
2324 
2325         // Skip initial slashes
2326         while (p <= end) {
2327             if (path.charAt(p) != '/') break;
2328             p++;
2329         }
2330         if (p > 1) normal = false;
2331 
2332         // Scan segments
2333         while (p <= end) {
2334 
2335             // Looking at "." or ".." ?
2336             if ((path.charAt(p) == '.')
2337                 && ((p == end)
2338                     || ((path.charAt(p + 1) == '/')
2339                         || ((path.charAt(p + 1) == '.')
2340                             && ((p + 1 == end)
2341                                 || (path.charAt(p + 2) == '/')))))) {
2342                 normal = false;
2343             }
2344             ns++;
2345 
2346             // Find beginning of next segment
2347             while (p <= end) {
2348                 if (path.charAt(p++) != '/')
2349                     continue;
2350 
2351                 // Skip redundant slashes
2352                 while (p <= end) {
2353                     if (path.charAt(p) != '/') break;
2354                     normal = false;
2355                     p++;
2356                 }
2357 
2358                 break;
2359             }
2360         }
2361 
2362         return normal ? -1 : ns;
2363     }
2364 
2365 
2366     // Split the given path into segments, replacing slashes with nulls and
2367     // filling in the given segment-index array.
2368     //
2369     // Preconditions:
2370     //   segs.length == Number of segments in path
2371     //
2372     // Postconditions:
2373     //   All slashes in path replaced by '\0'
2374     //   segs[i] == Index of first char in segment i (0 <= i < segs.length)
2375     //
2376     private static void split(char[] path, int[] segs) {
2377         int end = path.length - 1;      // Index of last char in path
2378         int p = 0;                      // Index of next char in path
2379         int i = 0;                      // Index of current segment
2380 
2381         // Skip initial slashes
2382         while (p <= end) {
2383             if (path[p] != '/') break;
2384             path[p] = '\0';
2385             p++;
2386         }
2387 
2388         while (p <= end) {
2389 
2390             // Note start of segment
2391             segs[i++] = p++;
2392 
2393             // Find beginning of next segment
2394             while (p <= end) {
2395                 if (path[p++] != '/')
2396                     continue;
2397                 path[p - 1] = '\0';
2398 
2399                 // Skip redundant slashes
2400                 while (p <= end) {
2401                     if (path[p] != '/') break;
2402                     path[p++] = '\0';
2403                 }
2404                 break;
2405             }
2406         }
2407 
2408         if (i != segs.length)
2409             throw new InternalError();  // ASSERT
2410     }
2411 
2412 
2413     // Join the segments in the given path according to the given segment-index
2414     // array, ignoring those segments whose index entries have been set to -1,
2415     // and inserting slashes as needed.  Return the length of the resulting
2416     // path.
2417     //
2418     // Preconditions:
2419     //   segs[i] == -1 implies segment i is to be ignored
2420     //   path computed by split, as above, with '\0' having replaced '/'
2421     //
2422     // Postconditions:
2423     //   path[0] .. path[return value] == Resulting path
2424     //
2425     private static int join(char[] path, int[] segs) {
2426         int ns = segs.length;           // Number of segments
2427         int end = path.length - 1;      // Index of last char in path
2428         int p = 0;                      // Index of next path char to write
2429 
2430         if (path[p] == '\0') {
2431             // Restore initial slash for absolute paths
2432             path[p++] = '/';
2433         }
2434 
2435         for (int i = 0; i < ns; i++) {
2436             int q = segs[i];            // Current segment
2437             if (q == -1)
2438                 // Ignore this segment
2439                 continue;
2440 
2441             if (p == q) {
2442                 // We're already at this segment, so just skip to its end
2443                 while ((p <= end) && (path[p] != '\0'))
2444                     p++;
2445                 if (p <= end) {
2446                     // Preserve trailing slash
2447                     path[p++] = '/';
2448                 }
2449             } else if (p < q) {
2450                 // Copy q down to p
2451                 while ((q <= end) && (path[q] != '\0'))
2452                     path[p++] = path[q++];
2453                 if (q <= end) {
2454                     // Preserve trailing slash
2455                     path[p++] = '/';
2456                 }
2457             } else
2458                 throw new InternalError(); // ASSERT false
2459         }
2460 
2461         return p;
2462     }
2463 
2464 
2465     // Remove "." segments from the given path, and remove segment pairs
2466     // consisting of a non-".." segment followed by a ".." segment.
2467     //
2468     private static void removeDots(char[] path, int[] segs) {
2469         int ns = segs.length;
2470         int end = path.length - 1;
2471 
2472         for (int i = 0; i < ns; i++) {
2473             int dots = 0;               // Number of dots found (0, 1, or 2)
2474 
2475             // Find next occurrence of "." or ".."
2476             do {
2477                 int p = segs[i];
2478                 if (path[p] == '.') {
2479                     if (p == end) {
2480                         dots = 1;
2481                         break;
2482                     } else if (path[p + 1] == '\0') {
2483                         dots = 1;
2484                         break;
2485                     } else if ((path[p + 1] == '.')
2486                                && ((p + 1 == end)
2487                                    || (path[p + 2] == '\0'))) {
2488                         dots = 2;
2489                         break;
2490                     }
2491                 }
2492                 i++;
2493             } while (i < ns);
2494             if ((i > ns) || (dots == 0))
2495                 break;
2496 
2497             if (dots == 1) {
2498                 // Remove this occurrence of "."
2499                 segs[i] = -1;
2500             } else {
2501                 // If there is a preceding non-".." segment, remove both that
2502                 // segment and this occurrence of ".."; otherwise, leave this
2503                 // ".." segment as-is.
2504                 int j;
2505                 for (j = i - 1; j >= 0; j--) {
2506                     if (segs[j] != -1) break;
2507                 }
2508                 if (j >= 0) {
2509                     int q = segs[j];
2510                     if (!((path[q] == '.')
2511                           && (path[q + 1] == '.')
2512                           && (path[q + 2] == '\0'))) {
2513                         segs[i] = -1;
2514                         segs[j] = -1;
2515                     }
2516                 }
2517             }
2518         }
2519     }
2520 
2521 
2522     // DEVIATION: If the normalized path is relative, and if the first
2523     // segment could be parsed as a scheme name, then prepend a "." segment
2524     //
2525     private static void maybeAddLeadingDot(char[] path, int[] segs) {
2526 
2527         if (path[0] == '\0')
2528             // The path is absolute
2529             return;
2530 
2531         int ns = segs.length;
2532         int f = 0;                      // Index of first segment
2533         while (f < ns) {
2534             if (segs[f] >= 0)
2535                 break;
2536             f++;
2537         }
2538         if ((f >= ns) || (f == 0))
2539             // The path is empty, or else the original first segment survived,
2540             // in which case we already know that no leading "." is needed
2541             return;
2542 
2543         int p = segs[f];
2544         while ((p < path.length) && (path[p] != ':') && (path[p] != '\0')) p++;
2545         if (p >= path.length || path[p] == '\0')
2546             // No colon in first segment, so no "." needed
2547             return;
2548 
2549         // At this point we know that the first segment is unused,
2550         // hence we can insert a "." segment at that position
2551         path[0] = '.';
2552         path[1] = '\0';
2553         segs[0] = 0;
2554     }
2555 
2556 
2557     // Normalize the given path string.  A normal path string has no empty
2558     // segments (i.e., occurrences of "//"), no segments equal to ".", and no
2559     // segments equal to ".." that are preceded by a segment not equal to "..".
2560     // In contrast to Unix-style pathname normalization, for URI paths we
2561     // always retain trailing slashes.
2562     //
2563     private static String normalize(String ps) {
2564 
2565         // Does this path need normalization?
2566         int ns = needsNormalization(ps);        // Number of segments
2567         if (ns < 0)
2568             // Nope -- just return it
2569             return ps;
2570 
2571         char[] path = ps.toCharArray();         // Path in char-array form
2572 
2573         // Split path into segments
2574         int[] segs = new int[ns];               // Segment-index array
2575         split(path, segs);
2576 
2577         // Remove dots
2578         removeDots(path, segs);
2579 
2580         // Prevent scheme-name confusion
2581         maybeAddLeadingDot(path, segs);
2582 
2583         // Join the remaining segments and return the result
2584         String s = new String(path, 0, join(path, segs));
2585         if (s.equals(ps)) {
2586             // string was already normalized
2587             return ps;
2588         }
2589         return s;
2590     }
2591 
2592 
2593 
2594     // -- Character classes for parsing --
2595 
2596     // RFC2396 precisely specifies which characters in the US-ASCII charset are
2597     // permissible in the various components of a URI reference.  We here
2598     // define a set of mask pairs to aid in enforcing these restrictions.  Each
2599     // mask pair consists of two longs, a low mask and a high mask.  Taken
2600     // together they represent a 128-bit mask, where bit i is set iff the
2601     // character with value i is permitted.
2602     //
2603     // This approach is more efficient than sequentially searching arrays of
2604     // permitted characters.  It could be made still more efficient by
2605     // precompiling the mask information so that a character's presence in a
2606     // given mask could be determined by a single table lookup.
2607 
2608     // To save startup time, we manually calculate the low-/highMask constants.
2609     // For reference, the following methods were used to calculate the values:
2610 
2611     // Compute the low-order mask for the characters in the given string
2612     //     private static long lowMask(String chars) {
2613     //        int n = chars.length();
2614     //        long m = 0;
2615     //        for (int i = 0; i < n; i++) {
2616     //            char c = chars.charAt(i);
2617     //            if (c < 64)
2618     //                m |= (1L << c);
2619     //        }
2620     //        return m;
2621     //    }
2622 
2623     // Compute the high-order mask for the characters in the given string
2624     //    private static long highMask(String chars) {
2625     //        int n = chars.length();
2626     //        long m = 0;
2627     //        for (int i = 0; i < n; i++) {
2628     //            char c = chars.charAt(i);
2629     //            if ((c >= 64) && (c < 128))
2630     //                m |= (1L << (c - 64));
2631     //        }
2632     //        return m;
2633     //    }
2634 
2635     // Compute a low-order mask for the characters
2636     // between first and last, inclusive
2637     //    private static long lowMask(char first, char last) {
2638     //        long m = 0;
2639     //        int f = Math.max(Math.min(first, 63), 0);
2640     //        int l = Math.max(Math.min(last, 63), 0);
2641     //        for (int i = f; i <= l; i++)
2642     //            m |= 1L << i;
2643     //        return m;
2644     //    }
2645 
2646     // Compute a high-order mask for the characters
2647     // between first and last, inclusive
2648     //    private static long highMask(char first, char last) {
2649     //        long m = 0;
2650     //        int f = Math.max(Math.min(first, 127), 64) - 64;
2651     //        int l = Math.max(Math.min(last, 127), 64) - 64;
2652     //        for (int i = f; i <= l; i++)
2653     //            m |= 1L << i;
2654     //        return m;
2655     //    }
2656 
2657     // Tell whether the given character is permitted by the given mask pair
2658     private static boolean match(char c, long lowMask, long highMask) {
2659         if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
2660             return false;
2661         if (c < 64)
2662             return ((1L << c) & lowMask) != 0;
2663         if (c < 128)
2664             return ((1L << (c - 64)) & highMask) != 0;
2665         return false;
2666     }
2667 
2668     // Character-class masks, in reverse order from RFC2396 because
2669     // initializers for static fields cannot make forward references.
2670 
2671     // digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
2672     //            "8" | "9"
2673     private static final long L_DIGIT = 0x3FF000000000000L; // lowMask('0', '9');
2674     private static final long H_DIGIT = 0L;
2675 
2676     // upalpha  = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
2677     //            "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
2678     //            "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
2679     private static final long L_UPALPHA = 0L;
2680     private static final long H_UPALPHA = 0x7FFFFFEL; // highMask('A', 'Z');
2681 
2682     // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
2683     //            "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
2684     //            "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
2685     private static final long L_LOWALPHA = 0L;
2686     private static final long H_LOWALPHA = 0x7FFFFFE00000000L; // highMask('a', 'z');
2687 
2688     // alpha         = lowalpha | upalpha
2689     private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
2690     private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
2691 
2692     // alphanum      = alpha | digit
2693     private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
2694     private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
2695 
2696     // hex           = digit | "A" | "B" | "C" | "D" | "E" | "F" |
2697     //                         "a" | "b" | "c" | "d" | "e" | "f"
2698     private static final long L_HEX = L_DIGIT;
2699     private static final long H_HEX = 0x7E0000007EL; // highMask('A', 'F') | highMask('a', 'f');
2700 
2701     // mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
2702     //                 "(" | ")"
2703     private static final long L_MARK = 0x678200000000L; // lowMask("-_.!~*'()");
2704     private static final long H_MARK = 0x4000000080000000L; // highMask("-_.!~*'()");
2705 
2706     // unreserved    = alphanum | mark
2707     private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
2708     private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
2709 
2710     // reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
2711     //                 "$" | "," | "[" | "]"
2712     // Added per RFC2732: "[", "]"
2713     private static final long L_RESERVED = 0xAC00985000000000L; // lowMask(";/?:@&=+$,[]");
2714     private static final long H_RESERVED = 0x28000001L; // highMask(";/?:@&=+$,[]");
2715 
2716     // The zero'th bit is used to indicate that escape pairs and non-US-ASCII
2717     // characters are allowed; this is handled by the scanEscape method below.
2718     private static final long L_ESCAPED = 1L;
2719     private static final long H_ESCAPED = 0L;
2720 
2721     // uric          = reserved | unreserved | escaped
2722     private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED;
2723     private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED;
2724 
2725     // pchar         = unreserved | escaped |
2726     //                 ":" | "@" | "&" | "=" | "+" | "$" | ","
2727     private static final long L_PCHAR
2728         = L_UNRESERVED | L_ESCAPED | 0x2400185000000000L; // lowMask(":@&=+$,");
2729     private static final long H_PCHAR
2730         = H_UNRESERVED | H_ESCAPED | 0x1L; // highMask(":@&=+$,");
2731 
2732     // All valid path characters
2733     private static final long L_PATH = L_PCHAR | 0x800800000000000L; // lowMask(";/");
2734     private static final long H_PATH = H_PCHAR; // highMask(";/") == 0x0L;
2735 
2736     // Dash, for use in domainlabel and toplabel
2737     private static final long L_DASH = 0x200000000000L; // lowMask("-");
2738     private static final long H_DASH = 0x0L; // highMask("-");
2739 
2740     // Dot, for use in hostnames
2741     private static final long L_DOT = 0x400000000000L; // lowMask(".");
2742     private static final long H_DOT = 0x0L; // highMask(".");
2743 
2744     // userinfo      = *( unreserved | escaped |
2745     //                    ";" | ":" | "&" | "=" | "+" | "$" | "," )
2746     private static final long L_USERINFO
2747         = L_UNRESERVED | L_ESCAPED | 0x2C00185000000000L; // lowMask(";:&=+$,");
2748     private static final long H_USERINFO
2749         = H_UNRESERVED | H_ESCAPED; // | highMask(";:&=+$,") == 0L;
2750 
2751     // reg_name      = 1*( unreserved | escaped | "$" | "," |
2752     //                     ";" | ":" | "@" | "&" | "=" | "+" )
2753     private static final long L_REG_NAME
2754         = L_UNRESERVED | L_ESCAPED | 0x2C00185000000000L; // lowMask("$,;:@&=+");
2755     private static final long H_REG_NAME
2756         = H_UNRESERVED | H_ESCAPED | 0x1L; // highMask("$,;:@&=+");
2757 
2758     // All valid characters for server-based authorities
2759     private static final long L_SERVER
2760         = L_USERINFO | L_ALPHANUM | L_DASH | 0x400400000000000L; // lowMask(".:@[]");
2761     private static final long H_SERVER
2762         = H_USERINFO | H_ALPHANUM | H_DASH | 0x28000001L; // highMask(".:@[]");
2763 
2764     // Special case of server authority that represents an IPv6 address
2765     // In this case, a % does not signify an escape sequence
2766     private static final long L_SERVER_PERCENT
2767         = L_SERVER | 0x2000000000L; // lowMask("%");
2768     private static final long H_SERVER_PERCENT
2769         = H_SERVER; // | highMask("%") == 0L;
2770 
2771     // scheme        = alpha *( alpha | digit | "+" | "-" | "." )
2772     private static final long L_SCHEME = L_ALPHA | L_DIGIT | 0x680000000000L; // lowMask("+-.");
2773     private static final long H_SCHEME = H_ALPHA | H_DIGIT; // | highMask("+-.") == 0L
2774 
2775     // scope_id = alpha | digit | "_" | "."
2776     private static final long L_SCOPE_ID
2777         = L_ALPHANUM | 0x400000000000L; // lowMask("_.");
2778     private static final long H_SCOPE_ID
2779         = H_ALPHANUM | 0x80000000L; // highMask("_.");
2780 
2781     // -- Escaping and encoding --
2782 
2783     private static final char[] hexDigits = {
2784         '0', '1', '2', '3', '4', '5', '6', '7',
2785         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
2786     };
2787 
2788     private static void appendEscape(StringBuilder sb, byte b) {
2789         sb.append('%');
2790         sb.append(hexDigits[(b >> 4) & 0x0f]);
2791         sb.append(hexDigits[(b >> 0) & 0x0f]);
2792     }
2793 
2794     private static void appendEncoded(CharsetEncoder encoder, StringBuilder sb, char c) {
2795         ByteBuffer bb = null;
2796         try {
2797             bb = encoder.encode(CharBuffer.wrap(new char[]{c}));
2798         } catch (CharacterCodingException x) {
2799             assert false;
2800         }
2801         while (bb.hasRemaining()) {
2802             int b = bb.get() & 0xff;
2803             if (b >= 0x80)
2804                 appendEscape(sb, (byte)b);
2805             else
2806                 sb.append((char)b);
2807         }
2808     }
2809 
2810     // Quote any characters in s that are not permitted
2811     // by the given mask pair
2812     //
2813     private static String quote(String s, long lowMask, long highMask) {
2814         StringBuilder sb = null;
2815         CharsetEncoder encoder = null;
2816         boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
2817         for (int i = 0; i < s.length(); i++) {
2818             char c = s.charAt(i);
2819             if (c < '\u0080') {
2820                 if (!match(c, lowMask, highMask)) {
2821                     if (sb == null) {
2822                         sb = new StringBuilder();
2823                         sb.append(s, 0, i);
2824                     }
2825                     appendEscape(sb, (byte)c);
2826                 } else {
2827                     if (sb != null)
2828                         sb.append(c);
2829                 }
2830             } else if (allowNonASCII
2831                        && (Character.isSpaceChar(c)
2832                            || Character.isISOControl(c))) {
2833                 if (encoder == null)
2834                     encoder = UTF_8.INSTANCE.newEncoder();
2835                 if (sb == null) {
2836                     sb = new StringBuilder();
2837                     sb.append(s, 0, i);
2838                 }
2839                 appendEncoded(encoder, sb, c);
2840             } else {
2841                 if (sb != null)
2842                     sb.append(c);
2843             }
2844         }
2845         return (sb == null) ? s : sb.toString();
2846     }
2847 
2848     // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets,
2849     // assuming that s is otherwise legal
2850     //
2851     private static String encode(String s) {
2852         int n = s.length();
2853         if (n == 0)
2854             return s;
2855 
2856         // First check whether we actually need to encode
2857         for (int i = 0;;) {
2858             if (s.charAt(i) >= '\u0080')
2859                 break;
2860             if (++i >= n)
2861                 return s;
2862         }
2863 
2864         String ns = Normalizer.normalize(s, Normalizer.Form.NFC);
2865         ByteBuffer bb = null;
2866         try {
2867             bb = UTF_8.INSTANCE.newEncoder()
2868                 .encode(CharBuffer.wrap(ns));
2869 
2870         } catch (CharacterCodingException x) {
2871             assert false;
2872         }
2873 
2874         StringBuilder sb = new StringBuilder();
2875         while (bb.hasRemaining()) {
2876             int b = bb.get() & 0xff;
2877             if (b >= 0x80)
2878                 appendEscape(sb, (byte)b);
2879             else
2880                 sb.append((char)b);
2881         }
2882         return sb.toString();
2883     }
2884 
2885     private static int decode(char c) {
2886         if ((c >= '0') && (c <= '9'))
2887             return c - '0';
2888         if ((c >= 'a') && (c <= 'f'))
2889             return c - 'a' + 10;
2890         if ((c >= 'A') && (c <= 'F'))
2891             return c - 'A' + 10;
2892         assert false;
2893         return -1;
2894     }
2895 
2896     private static byte decode(char c1, char c2) {
2897         return (byte)(  ((decode(c1) & 0xf) << 4)
2898                       | ((decode(c2) & 0xf) << 0));
2899     }
2900 
2901     // Evaluates all escapes in s, applying UTF-8 decoding if needed.  Assumes
2902     // that escapes are well-formed syntactically, i.e., of the form %XX.  If a
2903     // sequence of escaped octets is not valid UTF-8 then the erroneous octets
2904     // are replaced with '\uFFFD'.
2905     // Exception: any "%" found between "[]" is left alone. It is an IPv6 literal
2906     //            with a scope_id
2907     //
2908     private static String decode(String s) {
2909         return decode(s, true);
2910     }
2911 
2912     // This method was introduced as a generalization of URI.decode method
2913     // to provide a fix for JDK-8037396
2914     private static String decode(String s, boolean ignorePercentInBrackets) {
2915         if (s == null)
2916             return s;
2917         int n = s.length();
2918         if (n == 0)
2919             return s;
2920         if (s.indexOf('%') < 0)
2921             return s;
2922 
2923         StringBuilder sb = new StringBuilder(n);
2924         ByteBuffer bb = ByteBuffer.allocate(n);
2925         CharBuffer cb = CharBuffer.allocate(n);
2926         CharsetDecoder dec = UTF_8.INSTANCE.newDecoder()
2927             .onMalformedInput(CodingErrorAction.REPLACE)
2928             .onUnmappableCharacter(CodingErrorAction.REPLACE);
2929 
2930         // This is not horribly efficient, but it will do for now
2931         char c = s.charAt(0);
2932         boolean betweenBrackets = false;
2933 
2934         for (int i = 0; i < n;) {
2935             assert c == s.charAt(i);    // Loop invariant
2936             if (c == '[') {
2937                 betweenBrackets = true;
2938             } else if (betweenBrackets && c == ']') {
2939                 betweenBrackets = false;
2940             }
2941             if (c != '%' || (betweenBrackets && ignorePercentInBrackets)) {
2942                 sb.append(c);
2943                 if (++i >= n)
2944                     break;
2945                 c = s.charAt(i);
2946                 continue;
2947             }
2948             bb.clear();
2949             for (;;) {
2950                 assert (n - i >= 2);
2951                 bb.put(decode(s.charAt(++i), s.charAt(++i)));
2952                 if (++i >= n)
2953                     break;
2954                 c = s.charAt(i);
2955                 if (c != '%')
2956                     break;
2957             }
2958             bb.flip();
2959             cb.clear();
2960             dec.reset();
2961             CoderResult cr = dec.decode(bb, cb, true);
2962             assert cr.isUnderflow();
2963             cr = dec.flush(cb);
2964             assert cr.isUnderflow();
2965             sb.append(cb.flip().toString());
2966         }
2967 
2968         return sb.toString();
2969     }
2970 
2971 
2972     // -- Parsing --
2973 
2974     // For convenience we wrap the input URI string in a new instance of the
2975     // following internal class.  This saves always having to pass the input
2976     // string as an argument to each internal scan/parse method.
2977 
2978     private class Parser {
2979 
2980         private final String input;           // URI input string
2981         private boolean requireServerAuthority = false;
2982 
2983         Parser(String s) {
2984             input = s;
2985             string = s;
2986         }
2987 
2988         // -- Methods for throwing URISyntaxException in various ways --
2989 
2990         private void fail(String reason) throws URISyntaxException {
2991             throw new URISyntaxException(input, reason);
2992         }
2993 
2994         private void fail(String reason, int p) throws URISyntaxException {
2995             throw new URISyntaxException(input, reason, p);
2996         }
2997 
2998         private void failExpecting(String expected, int p)
2999             throws URISyntaxException
3000         {
3001             fail("Expected " + expected, p);
3002         }
3003 
3004 
3005         // -- Simple access to the input string --
3006 
3007         // Tells whether start < end and, if so, whether charAt(start) == c
3008         //
3009         private boolean at(int start, int end, char c) {
3010             return (start < end) && (input.charAt(start) == c);
3011         }
3012 
3013         // Tells whether start + s.length() < end and, if so,
3014         // whether the chars at the start position match s exactly
3015         //
3016         private boolean at(int start, int end, String s) {
3017             int p = start;
3018             int sn = s.length();
3019             if (sn > end - p)
3020                 return false;
3021             int i = 0;
3022             while (i < sn) {
3023                 if (input.charAt(p++) != s.charAt(i)) {
3024                     break;
3025                 }
3026                 i++;
3027             }
3028             return (i == sn);
3029         }
3030 
3031 
3032         // -- Scanning --
3033 
3034         // The various scan and parse methods that follow use a uniform
3035         // convention of taking the current start position and end index as
3036         // their first two arguments.  The start is inclusive while the end is
3037         // exclusive, just as in the String class, i.e., a start/end pair
3038         // denotes the left-open interval [start, end) of the input string.
3039         //
3040         // These methods never proceed past the end position.  They may return
3041         // -1 to indicate outright failure, but more often they simply return
3042         // the position of the first char after the last char scanned.  Thus
3043         // a typical idiom is
3044         //
3045         //     int p = start;
3046         //     int q = scan(p, end, ...);
3047         //     if (q > p)
3048         //         // We scanned something
3049         //         ...;
3050         //     else if (q == p)
3051         //         // We scanned nothing
3052         //         ...;
3053         //     else if (q == -1)
3054         //         // Something went wrong
3055         //         ...;
3056 
3057 
3058         // Scan a specific char: If the char at the given start position is
3059         // equal to c, return the index of the next char; otherwise, return the
3060         // start position.
3061         //
3062         private int scan(int start, int end, char c) {
3063             if ((start < end) && (input.charAt(start) == c))
3064                 return start + 1;
3065             return start;
3066         }
3067 
3068         // Scan forward from the given start position.  Stop at the first char
3069         // in the err string (in which case -1 is returned), or the first char
3070         // in the stop string (in which case the index of the preceding char is
3071         // returned), or the end of the input string (in which case the length
3072         // of the input string is returned).  May return the start position if
3073         // nothing matches.
3074         //
3075         private int scan(int start, int end, String err, String stop) {
3076             int p = start;
3077             while (p < end) {
3078                 char c = input.charAt(p);
3079                 if (err.indexOf(c) >= 0)
3080                     return -1;
3081                 if (stop.indexOf(c) >= 0)
3082                     break;
3083                 p++;
3084             }
3085             return p;
3086         }
3087 
3088         // Scan forward from the given start position.  Stop at the first char
3089         // in the stop string (in which case the index of the preceding char is
3090         // returned), or the end of the input string (in which case the length
3091         // of the input string is returned).  May return the start position if
3092         // nothing matches.
3093         //
3094         private int scan(int start, int end, String stop) {
3095             int p = start;
3096             while (p < end) {
3097                 char c = input.charAt(p);
3098                 if (stop.indexOf(c) >= 0)
3099                     break;
3100                 p++;
3101             }
3102             return p;
3103         }
3104 
3105         // Scan a potential escape sequence, starting at the given position,
3106         // with the given first char (i.e., charAt(start) == c).
3107         //
3108         // This method assumes that if escapes are allowed then visible
3109         // non-US-ASCII chars are also allowed.
3110         //
3111         private int scanEscape(int start, int n, char first)
3112             throws URISyntaxException
3113         {
3114             int p = start;
3115             char c = first;
3116             if (c == '%') {
3117                 // Process escape pair
3118                 if ((p + 3 <= n)
3119                     && match(input.charAt(p + 1), L_HEX, H_HEX)
3120                     && match(input.charAt(p + 2), L_HEX, H_HEX)) {
3121                     return p + 3;
3122                 }
3123                 fail("Malformed escape pair", p);
3124             } else if ((c > 128)
3125                        && !Character.isSpaceChar(c)
3126                        && !Character.isISOControl(c)) {
3127                 // Allow unescaped but visible non-US-ASCII chars
3128                 return p + 1;
3129             }
3130             return p;
3131         }
3132 
3133         // Scan chars that match the given mask pair
3134         //
3135         private int scan(int start, int n, long lowMask, long highMask)
3136             throws URISyntaxException
3137         {
3138             int p = start;
3139             while (p < n) {
3140                 char c = input.charAt(p);
3141                 if (match(c, lowMask, highMask)) {
3142                     p++;
3143                     continue;
3144                 }
3145                 if ((lowMask & L_ESCAPED) != 0) {
3146                     int q = scanEscape(p, n, c);
3147                     if (q > p) {
3148                         p = q;
3149                         continue;
3150                     }
3151                 }
3152                 break;
3153             }
3154             return p;
3155         }
3156 
3157         // Check that each of the chars in [start, end) matches the given mask
3158         //
3159         private void checkChars(int start, int end,
3160                                 long lowMask, long highMask,
3161                                 String what)
3162             throws URISyntaxException
3163         {
3164             int p = scan(start, end, lowMask, highMask);
3165             if (p < end)
3166                 fail("Illegal character in " + what, p);
3167         }
3168 
3169         // Check that the char at position p matches the given mask
3170         //
3171         private void checkChar(int p,
3172                                long lowMask, long highMask,
3173                                String what)
3174             throws URISyntaxException
3175         {
3176             checkChars(p, p + 1, lowMask, highMask, what);
3177         }
3178 
3179 
3180         // -- Parsing --
3181 
3182         // [<scheme>:]<scheme-specific-part>[#<fragment>]
3183         //
3184         void parse(boolean rsa) throws URISyntaxException {
3185             requireServerAuthority = rsa;
3186             int n = input.length();
3187             int p = scan(0, n, "/?#", ":");
3188             if ((p >= 0) && at(p, n, ':')) {
3189                 if (p == 0)
3190                     failExpecting("scheme name", 0);
3191                 checkChar(0, L_ALPHA, H_ALPHA, "scheme name");
3192                 checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name");
3193                 scheme = input.substring(0, p);
3194                 p++;                    // Skip ':'
3195                 if (at(p, n, '/')) {
3196                     p = parseHierarchical(p, n);
3197                 } else {
3198                     // opaque; need to create the schemeSpecificPart
3199                     int q = scan(p, n, "#");
3200                     if (q <= p)
3201                         failExpecting("scheme-specific part", p);
3202                     checkChars(p, q, L_URIC, H_URIC, "opaque part");
3203                     schemeSpecificPart = input.substring(p, q);
3204                     p = q;
3205                 }
3206             } else {
3207                 p = parseHierarchical(0, n);
3208             }
3209             if (at(p, n, '#')) {
3210                 checkChars(p + 1, n, L_URIC, H_URIC, "fragment");
3211                 fragment = input.substring(p + 1, n);
3212                 p = n;
3213             }
3214             if (p < n)
3215                 fail("end of URI", p);
3216         }
3217 
3218         // [//authority]<path>[?<query>]
3219         //
3220         // DEVIATION from RFC2396: We allow an empty authority component as
3221         // long as it's followed by a non-empty path, query component, or
3222         // fragment component.  This is so that URIs such as "file:///foo/bar"
3223         // will parse.  This seems to be the intent of RFC2396, though the
3224         // grammar does not permit it.  If the authority is empty then the
3225         // userInfo, host, and port components are undefined.
3226         //
3227         // DEVIATION from RFC2396: We allow empty relative paths.  This seems
3228         // to be the intent of RFC2396, but the grammar does not permit it.
3229         // The primary consequence of this deviation is that "#f" parses as a
3230         // relative URI with an empty path.
3231         //
3232         private int parseHierarchical(int start, int n)
3233             throws URISyntaxException
3234         {
3235             int p = start;
3236             if (at(p, n, '/') && at(p + 1, n, '/')) {
3237                 p += 2;
3238                 int q = scan(p, n, "/?#");
3239                 if (q > p) {
3240                     p = parseAuthority(p, q);
3241                 } else if (q < n) {
3242                     // DEVIATION: Allow empty authority prior to non-empty
3243                     // path, query component or fragment identifier
3244                 } else
3245                     failExpecting("authority", p);
3246             }
3247             int q = scan(p, n, "?#"); // DEVIATION: May be empty
3248             checkChars(p, q, L_PATH, H_PATH, "path");
3249             path = input.substring(p, q);
3250             p = q;
3251             if (at(p, n, '?')) {
3252                 p++;
3253                 q = scan(p, n, "#");
3254                 checkChars(p, q, L_URIC, H_URIC, "query");
3255                 query = input.substring(p, q);
3256                 p = q;
3257             }
3258             return p;
3259         }
3260 
3261         // authority     = server | reg_name
3262         //
3263         // Ambiguity: An authority that is a registry name rather than a server
3264         // might have a prefix that parses as a server.  We use the fact that
3265         // the authority component is always followed by '/' or the end of the
3266         // input string to resolve this: If the complete authority did not
3267         // parse as a server then we try to parse it as a registry name.
3268         //
3269         private int parseAuthority(int start, int n)
3270             throws URISyntaxException
3271         {
3272             int p = start;
3273             int q = p;
3274             int qreg = p;
3275             URISyntaxException ex = null;
3276 
3277             boolean serverChars;
3278             boolean regChars;
3279             boolean skipParseException;
3280 
3281             if (scan(p, n, "]") > p) {
3282                 // contains a literal IPv6 address, therefore % is allowed
3283                 serverChars = (scan(p, n, L_SERVER_PERCENT, H_SERVER_PERCENT) == n);
3284             } else {
3285                 serverChars = (scan(p, n, L_SERVER, H_SERVER) == n);
3286             }
3287             regChars = ((qreg = scan(p, n, L_REG_NAME, H_REG_NAME)) == n);
3288 
3289             if (regChars && !serverChars) {
3290                 // Must be a registry-based authority
3291                 authority = input.substring(p, n);
3292                 return n;
3293             }
3294 
3295             // When parsing a URI, skip creating exception objects if the server-based
3296             // authority is not required and the registry parse is successful.
3297             //
3298             skipParseException = (!requireServerAuthority && regChars);
3299             if (serverChars) {
3300                 // Might be (probably is) a server-based authority, so attempt
3301                 // to parse it as such.  If the attempt fails, try to treat it
3302                 // as a registry-based authority.
3303                 try {
3304                     q = parseServer(p, n, skipParseException);
3305                     if (q < n) {
3306                         if (skipParseException) {
3307                             userInfo = null;
3308                             host = null;
3309                             port = -1;
3310                             q = p;
3311                         } else {
3312                             failExpecting("end of authority", q);
3313                         }
3314                     } else {
3315                         authority = input.substring(p, n);
3316                     }
3317                 } catch (URISyntaxException x) {
3318                     // Undo results of failed parse
3319                     userInfo = null;
3320                     host = null;
3321                     port = -1;
3322                     if (requireServerAuthority) {
3323                         // If we're insisting upon a server-based authority,
3324                         // then just re-throw the exception
3325                         throw x;
3326                     } else {
3327                         // Save the exception in case it doesn't parse as a
3328                         // registry either
3329                         ex = x;
3330                         q = p;
3331                     }
3332                 }
3333             }
3334 
3335             if (q < n) {
3336                 if (regChars) {
3337                     // Registry-based authority
3338                     authority = input.substring(p, n);
3339                 } else if (ex != null) {
3340                     // Re-throw exception; it was probably due to
3341                     // a malformed IPv6 address
3342                     throw ex;
3343                 } else {
3344                     fail("Illegal character in authority", serverChars ? q : qreg);
3345                 }
3346             }
3347 
3348             return n;
3349         }
3350 
3351 
3352         // [<userinfo>@]<host>[:<port>]
3353         //
3354         private int parseServer(int start, int n, boolean skipParseException)
3355             throws URISyntaxException
3356         {
3357             int p = start;
3358             int q;
3359 
3360             // userinfo
3361             q = scan(p, n, "/?#", "@");
3362             if ((q >= p) && at(q, n, '@')) {
3363                 checkChars(p, q, L_USERINFO, H_USERINFO, "user info");
3364                 userInfo = input.substring(p, q);
3365                 p = q + 1;              // Skip '@'
3366             }
3367 
3368             // hostname, IPv4 address, or IPv6 address
3369             if (at(p, n, '[')) {
3370                 // DEVIATION from RFC2396: Support IPv6 addresses, per RFC2732
3371                 p++;
3372                 q = scan(p, n, "/?#", "]");
3373                 if ((q > p) && at(q, n, ']')) {
3374                     // look for a "%" scope id
3375                     int r = scan (p, q, "%");
3376                     if (r > p) {
3377                         parseIPv6Reference(p, r);
3378                         if (r+1 == q) {
3379                             fail ("scope id expected");
3380                         }
3381                         checkChars (r+1, q, L_SCOPE_ID, H_SCOPE_ID,
3382                                                 "scope id");
3383                     } else {
3384                         parseIPv6Reference(p, q);
3385                     }
3386                     host = input.substring(p-1, q+1);
3387                     p = q + 1;
3388                 } else {
3389                     failExpecting("closing bracket for IPv6 address", q);
3390                 }
3391             } else {
3392                 q = parseIPv4Address(p, n);
3393                 if (q <= p)
3394                     q = parseHostname(p, n, skipParseException);
3395                 p = q;
3396             }
3397 
3398             // port
3399             if (at(p, n, ':')) {
3400                 p++;
3401                 q = scan(p, n, "/");
3402                 if (q > p) {
3403                     checkChars(p, q, L_DIGIT, H_DIGIT, "port number");
3404                     try {
3405                         port = Integer.parseInt(input, p, q, 10);
3406                     } catch (NumberFormatException x) {
3407                         fail("Malformed port number", p);
3408                     }
3409                     p = q;
3410                 }
3411             } else if (p < n && skipParseException) {
3412                 return p;
3413             }
3414 
3415             if (p < n)
3416                 failExpecting("port number", p);
3417 
3418             return p;
3419         }
3420 
3421         // Scan a string of decimal digits whose value fits in a byte
3422         //
3423         private int scanByte(int start, int n)
3424             throws URISyntaxException
3425         {
3426             int p = start;
3427             int q = scan(p, n, L_DIGIT, H_DIGIT);
3428             if (q <= p) return q;
3429             if (Integer.parseInt(input, p, q, 10) > 255) return p;
3430             return q;
3431         }
3432 
3433         // Scan an IPv4 address.
3434         //
3435         // If the strict argument is true then we require that the given
3436         // interval contain nothing besides an IPv4 address; if it is false
3437         // then we only require that it start with an IPv4 address.
3438         //
3439         // If the interval does not contain or start with (depending upon the
3440         // strict argument) a legal IPv4 address characters then we return -1
3441         // immediately; otherwise we insist that these characters parse as a
3442         // legal IPv4 address and throw an exception on failure.
3443         //
3444         // We assume that any string of decimal digits and dots must be an IPv4
3445         // address.  It won't parse as a hostname anyway, so making that
3446         // assumption here allows more meaningful exceptions to be thrown.
3447         //
3448         private int scanIPv4Address(int start, int n, boolean strict)
3449             throws URISyntaxException
3450         {
3451             int p = start;
3452             int q;
3453             int m = scan(p, n, L_DIGIT | L_DOT, H_DIGIT | H_DOT);
3454             if ((m <= p) || (strict && (m != n)))
3455                 return -1;
3456             for (;;) {
3457                 // Per RFC2732: At most three digits per byte
3458                 // Further constraint: Each element fits in a byte
3459                 if ((q = scanByte(p, m)) <= p) break;   p = q;
3460                 if ((q = scan(p, m, '.')) <= p) break;  p = q;
3461                 if ((q = scanByte(p, m)) <= p) break;   p = q;
3462                 if ((q = scan(p, m, '.')) <= p) break;  p = q;
3463                 if ((q = scanByte(p, m)) <= p) break;   p = q;
3464                 if ((q = scan(p, m, '.')) <= p) break;  p = q;
3465                 if ((q = scanByte(p, m)) <= p) break;   p = q;
3466                 if (q < m) break;
3467                 return q;
3468             }
3469             fail("Malformed IPv4 address", q);
3470             return -1;
3471         }
3472 
3473         // Take an IPv4 address: Throw an exception if the given interval
3474         // contains anything except an IPv4 address
3475         //
3476         private int takeIPv4Address(int start, int n, String expected)
3477             throws URISyntaxException
3478         {
3479             int p = scanIPv4Address(start, n, true);
3480             if (p <= start)
3481                 failExpecting(expected, start);
3482             return p;
3483         }
3484 
3485         // Attempt to parse an IPv4 address, returning -1 on failure but
3486         // allowing the given interval to contain [:<characters>] after
3487         // the IPv4 address.
3488         //
3489         private int parseIPv4Address(int start, int n) {
3490             int p;
3491 
3492             try {
3493                 p = scanIPv4Address(start, n, false);
3494             } catch (URISyntaxException | NumberFormatException x) {
3495                 return -1;
3496             }
3497 
3498             if (p > start && p < n) {
3499                 // IPv4 address is followed by something - check that
3500                 // it's a ":" as this is the only valid character to
3501                 // follow an address.
3502                 if (input.charAt(p) != ':') {
3503                     p = -1;
3504                 }
3505             }
3506 
3507             if (p > start)
3508                 host = input.substring(start, p);
3509 
3510             return p;
3511         }
3512 
3513         // hostname      = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ]
3514         // domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
3515         // toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
3516         //
3517         private int parseHostname(int start, int n, boolean skipParseException)
3518             throws URISyntaxException
3519         {
3520             int p = start;
3521             int q;
3522             int l = -1;                 // Start of last parsed label
3523 
3524             do {
3525                 // domainlabel = alphanum [ *( alphanum | "-" ) alphanum ]
3526                 q = scan(p, n, L_ALPHANUM, H_ALPHANUM);
3527                 if (q <= p)
3528                     break;
3529                 l = p;
3530                 p = q;
3531                 q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH);
3532                 if (q > p) {
3533                     if (input.charAt(q - 1) == '-')
3534                         fail("Illegal character in hostname", q - 1);
3535                     p = q;
3536                 }
3537                 q = scan(p, n, '.');
3538                 if (q <= p)
3539                     break;
3540                 p = q;
3541             } while (p < n);
3542 
3543             if ((p < n) && !at(p, n, ':')) {
3544                 if (skipParseException) {
3545                     return p;
3546                 }
3547                 fail("Illegal character in hostname", p);
3548             }
3549             if (l < 0)
3550                 failExpecting("hostname", start);
3551 
3552             // for a fully qualified hostname check that the rightmost
3553             // label starts with an alpha character.
3554             if (l > start && !match(input.charAt(l), L_ALPHA, H_ALPHA)) {
3555                 fail("Illegal character in hostname", l);
3556             }
3557 
3558             host = input.substring(start, p);
3559             return p;
3560         }
3561 
3562 
3563         // IPv6 address parsing, from RFC2373: IPv6 Addressing Architecture
3564         //
3565         // Bug: The grammar in RFC2373 Appendix B does not allow addresses of
3566         // the form ::12.34.56.78, which are clearly shown in the examples
3567         // earlier in the document.  Here is the original grammar:
3568         //
3569         //   IPv6address = hexpart [ ":" IPv4address ]
3570         //   hexpart     = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
3571         //   hexseq      = hex4 *( ":" hex4)
3572         //   hex4        = 1*4HEXDIG
3573         //
3574         // We therefore use the following revised grammar:
3575         //
3576         //   IPv6address = hexseq [ ":" IPv4address ]
3577         //                 | hexseq [ "::" [ hexpost ] ]
3578         //                 | "::" [ hexpost ]
3579         //   hexpost     = hexseq | hexseq ":" IPv4address | IPv4address
3580         //   hexseq      = hex4 *( ":" hex4)
3581         //   hex4        = 1*4HEXDIG
3582         //
3583         // This covers all and only the following cases:
3584         //
3585         //   hexseq
3586         //   hexseq : IPv4address
3587         //   hexseq ::
3588         //   hexseq :: hexseq
3589         //   hexseq :: hexseq : IPv4address
3590         //   hexseq :: IPv4address
3591         //   :: hexseq
3592         //   :: hexseq : IPv4address
3593         //   :: IPv4address
3594         //   ::
3595         //
3596         // Additionally we constrain the IPv6 address as follows :-
3597         //
3598         //  i.  IPv6 addresses without compressed zeros should contain
3599         //      exactly 16 bytes.
3600         //
3601         //  ii. IPv6 addresses with compressed zeros should contain
3602         //      less than 16 bytes.
3603 
3604         private int ipv6byteCount = 0;
3605 
3606         private int parseIPv6Reference(int start, int n)
3607             throws URISyntaxException
3608         {
3609             int p = start;
3610             int q;
3611             boolean compressedZeros = false;
3612 
3613             q = scanHexSeq(p, n);
3614 
3615             if (q > p) {
3616                 p = q;
3617                 if (at(p, n, "::")) {
3618                     compressedZeros = true;
3619                     p = scanHexPost(p + 2, n);
3620                 } else if (at(p, n, ':')) {
3621                     p = takeIPv4Address(p + 1,  n, "IPv4 address");
3622                     ipv6byteCount += 4;
3623                 }
3624             } else if (at(p, n, "::")) {
3625                 compressedZeros = true;
3626                 p = scanHexPost(p + 2, n);
3627             }
3628             if (p < n)
3629                 fail("Malformed IPv6 address", start);
3630             if (ipv6byteCount > 16)
3631                 fail("IPv6 address too long", start);
3632             if (!compressedZeros && ipv6byteCount < 16)
3633                 fail("IPv6 address too short", start);
3634             if (compressedZeros && ipv6byteCount == 16)
3635                 fail("Malformed IPv6 address", start);
3636 
3637             return p;
3638         }
3639 
3640         private int scanHexPost(int start, int n)
3641             throws URISyntaxException
3642         {
3643             int p = start;
3644             int q;
3645 
3646             if (p == n)
3647                 return p;
3648 
3649             q = scanHexSeq(p, n);
3650             if (q > p) {
3651                 p = q;
3652                 if (at(p, n, ':')) {
3653                     p++;
3654                     p = takeIPv4Address(p, n, "hex digits or IPv4 address");
3655                     ipv6byteCount += 4;
3656                 }
3657             } else {
3658                 p = takeIPv4Address(p, n, "hex digits or IPv4 address");
3659                 ipv6byteCount += 4;
3660             }
3661             return p;
3662         }
3663 
3664         // Scan a hex sequence; return -1 if one could not be scanned
3665         //
3666         private int scanHexSeq(int start, int n)
3667             throws URISyntaxException
3668         {
3669             int p = start;
3670             int q;
3671 
3672             q = scan(p, n, L_HEX, H_HEX);
3673             if (q <= p)
3674                 return -1;
3675             if (at(q, n, '.'))          // Beginning of IPv4 address
3676                 return -1;
3677             if (q > p + 4)
3678                 fail("IPv6 hexadecimal digit sequence too long", p);
3679             ipv6byteCount += 2;
3680             p = q;
3681             while (p < n) {
3682                 if (!at(p, n, ':'))
3683                     break;
3684                 if (at(p + 1, n, ':'))
3685                     break;              // "::"
3686                 p++;
3687                 q = scan(p, n, L_HEX, H_HEX);
3688                 if (q <= p)
3689                     failExpecting("digits for an IPv6 address", p);
3690                 if (at(q, n, '.')) {    // Beginning of IPv4 address
3691                     p--;
3692                     break;
3693                 }
3694                 if (q > p + 4)
3695                     fail("IPv6 hexadecimal digit sequence too long", p);
3696                 ipv6byteCount += 2;
3697                 p = q;
3698             }
3699 
3700             return p;
3701         }
3702 
3703     }
3704 
3705     static {
3706         runtimeSetup();
3707     }
3708 
3709     // Called from JVM when loading an AOT cache
3710     private static void runtimeSetup() {
3711         SharedSecrets.setJavaNetUriAccess(
3712             new JavaNetUriAccess() {
3713                 public URI create(String scheme, String path) {
3714                     return new URI(scheme, path);
3715                 }
3716             }
3717         );
3718     }
3719 }