diff options
Diffstat (limited to 'examples/scala-js/javalib/src/main/scala/java/net/URI.scala')
-rw-r--r-- | examples/scala-js/javalib/src/main/scala/java/net/URI.scala | 706 |
1 files changed, 0 insertions, 706 deletions
diff --git a/examples/scala-js/javalib/src/main/scala/java/net/URI.scala b/examples/scala-js/javalib/src/main/scala/java/net/URI.scala deleted file mode 100644 index c969f55..0000000 --- a/examples/scala-js/javalib/src/main/scala/java/net/URI.scala +++ /dev/null @@ -1,706 +0,0 @@ -package java.net - -import scala.scalajs.js.RegExp -import scala.scalajs.js -import scala.scalajs.js.{decodeURIComponent => decode} - -import scala.annotation.tailrec - -final class URI(origStr: String) extends Serializable with Comparable[URI] { - - import URI.Fields._ - - /** The fields matched in the regular expression. - * - * This is a local val for the primary constructor. It is a val, - * since we'll set it to null after initializing all fields. - */ - private[this] var _fld = Option(URI.uriRe.exec(origStr)).getOrElse { - throw new URISyntaxException(origStr, "Malformed URI") - } - - private val _isAbsolute = fld(AbsScheme).isDefined - private val _isOpaque = fld(AbsOpaquePart).isDefined - - @inline private def fld(idx: Int): js.UndefOr[String] = _fld(idx) - - @inline private def fld(absIdx: Int, relIdx: Int): js.UndefOr[String] = - if (_isAbsolute) _fld(absIdx) else _fld(relIdx) - - private val _scheme = fld(AbsScheme) - - private val _schemeSpecificPart = { - if (!_isAbsolute) fld(RelSchemeSpecificPart) - else if (_isOpaque) fld(AbsOpaquePart) - else fld(AbsHierPart) - }.get - - private val _authority = fld(AbsAuthority, RelAuthority) - private val _userInfo = fld(AbsUserInfo, RelUserInfo) - private val _host = fld(AbsHost, RelHost) - private val _port = fld(AbsPort, RelPort).fold(-1)(_.toInt) - - private val _path = { - if (_isAbsolute) { - if (_authority.isDefined) fld(AbsNetPath) - else fld(AbsAbsPath) - } else { - if (_authority.isDefined) fld(RelNetPath) - else fld(RelAbsPath) orElse fld(RelRelPath) - } - } - - private val _query = fld(AbsQuery, RelQuery) - private val _fragment = fld(Fragment) - - // End of default ctor. Unset helper field - _fld = null - - def this(scheme: String, ssp: String, fragment: String) = - this(URI.uriStr(scheme, ssp, fragment)) - - def this(scheme: String, userInfo: String, host: String, port: Int, - path: String, query: String, fragment: String) = { - this(URI.uriStr(scheme, userInfo, host, port, path, query, fragment)) - parseServerAuthority() - } - - def this(scheme: String, host: String, path: String, fragment: String) = - this(scheme, null, host, -1, path, null, fragment) - - def this(scheme: String, authority: String, path: String, query: String, - fragment: String) = { - this(URI.uriStr(scheme, authority, path, query, fragment)) - // JavaDoc says to invoke parseServerAuthority() here, but in practice - // it isn't invoked. This makes sense, since you want to be able - // to create URIs with registry-based authorities. - // parseServerAuthority() - } - - /** Compare this URI to another URI while supplying a comparator - * - * This helper is required to account for the semantic differences - * between [[compareTo]] and [[equals]]. ([[equals]] does treat - * URI escapes specially: they are never case-sensitive). - */ - @inline - private def internalCompare(that: URI)(cmp: (String, String) => Int): Int = { - @inline def cmpOpt(x: js.UndefOr[String], y: js.UndefOr[String]): Int = { - if (x == y) 0 - // Undefined components are considered less than defined components - else x.fold(-1)(s1 => y.fold(1)(s2 => cmp(s1, s2))) - } - - if (this._scheme != that._scheme) - this._scheme.fold(-1)(s1 => that._scheme.fold(1)(s1.compareToIgnoreCase)) - else if (this._isOpaque != that._isOpaque) - // A hierarchical URI is less than an opaque URI - if (this._isOpaque) 1 else -1 - else if (_isOpaque) { - val ssp = cmp(this._schemeSpecificPart, that._schemeSpecificPart) - if (ssp != 0) ssp - else cmpOpt(this._fragment, that._fragment) - } else if (this._authority != that._authority) { - if (this._host.isDefined && that._host.isDefined) { - val ui = cmpOpt(this._userInfo, that._userInfo) - if (ui != 0) ui - else { - val hst = this._host.get.compareToIgnoreCase(that._host.get) - if (hst != 0) hst - else if (this._port == that._port) 0 - else if (this._port == -1) -1 - else if (that._port == -1) 1 - else this._port - that._port - } - } else - cmpOpt(this._authority, that._authority) - } else if (this._path != that._path) - cmpOpt(this._path, that._path) - else if (this._query != that._query) - cmpOpt(this._query, that._query) - else - cmpOpt(this._fragment, that._fragment) - } - - def compareTo(that: URI): Int = internalCompare(that)(_.compareTo(_)) - - override def equals(that: Any): Boolean = that match { - case that: URI => internalCompare(that)(URI.escapeAwareCompare) == 0 - case _ => false - } - - def getAuthority(): String = _authority.map(decode).orNull - def getFragment(): String = _fragment.map(decode).orNull - def getHost(): String = _host.orNull - def getPath(): String = _path.map(decode).orNull - def getPort(): Int = _port - def getQuery(): String = _query.map(decode).orNull - def getRawAuthority(): String = _authority.orNull - def getRawFragment(): String = _fragment.orNull - def getRawPath(): String = _path.orNull - def getRawQuery(): String = _query.orNull - def getRawSchemeSpecificPart(): String = _schemeSpecificPart - def getRawUserInfo(): String = _userInfo.orNull - def getScheme(): String = _scheme.orNull - def getSchemeSpecificPart(): String = decode(_schemeSpecificPart) - def getUserInfo(): String = _userInfo.map(decode).orNull - - override def hashCode(): Int = { - import scala.util.hashing.MurmurHash3._ - import URI.normalizeEscapes - - var acc = URI.uriSeed - acc = mix(acc, _scheme.##) // scheme may not contain escapes - acc = mix(acc, normalizeEscapes(_schemeSpecificPart).##) - acc = mixLast(acc, _fragment.map(normalizeEscapes).##) - - finalizeHash(acc, 3) - } - - def isAbsolute(): Boolean = _isAbsolute - def isOpaque(): Boolean = _isOpaque - - def normalize(): URI = if (_isOpaque || _path.isEmpty) this else { - val origPath = _path.get - - // Step 1: Remove all "." segments - // Step 2: Remove ".." segments preceeded by non ".." segment until no - // longer applicable - - /** Checks whether a successive ".." may drop the head of a - * reversed segment list. - */ - def okToDropFrom(resRev: List[String]) = - resRev.nonEmpty && resRev.head != ".." && resRev.head != "" - - @tailrec - def loop(in: List[String], resRev: List[String]): List[String] = in match { - case "." :: Nil => - // convert "." segments at end to an empty segment - // (consider: /a/b/. => /a/b/, not /a/b) - loop(Nil, "" :: resRev) - case ".." :: Nil if okToDropFrom(resRev) => - // prevent a ".." segment at end to change a "dir" into a "file" - // (consider: /a/b/.. => /a/, not /a) - loop(Nil, "" :: resRev.tail) - case "." :: xs => - // remove "." segments - loop(xs, resRev) - case "" :: xs if xs.nonEmpty => - // remove empty segments not at end of path - loop(xs, resRev) - case ".." :: xs if okToDropFrom(resRev) => - // Remove preceeding non-".." segment - loop(xs, resRev.tail) - case x :: xs => - loop(xs, x :: resRev) - case Nil => - resRev.reverse - } - - // Split into segments. -1 since we want empty trailing ones - val segments0 = origPath.split("/", -1).toList - val isAbsPath = segments0.nonEmpty && segments0.head == "" - // Don't inject first empty segment into normalization loop, so we - // won't need to special case it. - val segments1 = if (isAbsPath) segments0.tail else segments0 - val segments2 = loop(segments1, Nil) - - // Step 3: If path is relative and first segment contains ":", prepend "." - // segment (according to JavaDoc). If it is absolute, add empty - // segment again to have leading "/". - val segments3 = { - if (isAbsPath) - "" :: segments2 - else if (segments2.nonEmpty && segments2.head.contains(':')) - "." :: segments2 - else segments2 - } - - val newPath = segments3.mkString("/") - - // Only create new instance if anything changed - if (newPath == origPath) - this - else - new URI(getScheme(), getRawAuthority(), newPath, getQuery(), getFragment()) - } - - def parseServerAuthority(): URI = { - if (_authority.nonEmpty && _host.isEmpty) - throw new URISyntaxException(origStr, "No Host in URI") - else this - } - - def relativize(uri: URI): URI = { - def authoritiesEqual = this._authority.fold(uri._authority.isEmpty) { a1 => - uri._authority.fold(false)(a2 => URI.escapeAwareCompare(a1, a2) == 0) - } - - if (this.isOpaque || uri.isOpaque || - this._scheme != uri._scheme || !authoritiesEqual) uri - else { - val thisN = this.normalize() - val uriN = uri.normalize() - - // Strangely, Java doesn't handle escapes here. So we don't - if (uriN.getRawPath().startsWith(thisN.getRawPath())) { - val newPath = uriN.getRawPath().stripPrefix(thisN.getRawPath()) - - new URI(scheme = null, authority = null, - // never produce an abs path if we relativized - path = newPath.stripPrefix("/"), - query = uri.getQuery(), fragment = uri.getFragment()) - } else uri - } - } - - def resolve(str: String): URI = resolve(URI.create(str)) - - def resolve(uri: URI): URI = { - if (uri.isAbsolute() || this.isOpaque()) uri - else if (uri._scheme.isEmpty && uri._authority.isEmpty && - uri._path.get == "" && uri._query.isEmpty) - // This is a special case for URIs like: "#foo". This allows to - // just change the fragment in the current document. - new URI( - this.getScheme(), - this.getRawAuthority(), - this.getRawPath(), - this.getRawQuery(), - uri.getRawFragment()) - else if (uri._authority.isDefined) - new URI( - this.getScheme(), - uri.getRawAuthority(), - uri.getRawPath(), - uri.getRawQuery(), - uri.getRawFragment()) - else if (uri._path.get.startsWith("/")) - new URI( - this.getScheme(), - this.getRawAuthority(), - uri.getRawPath(), - uri.getRawQuery(), - uri.getRawFragment()) - else { - val basePath = this._path.get - val relPath = uri._path.get - val endIdx = basePath.lastIndexOf('/') - val path = - if (endIdx == -1) relPath - else basePath.substring(0, endIdx+1) + relPath - new URI( - this.getScheme(), - this.getAuthority(), - path, - uri.getRawQuery(), - uri.getRawFragment()).normalize() - } - } - - def toASCIIString(): String = origStr // We allow only ASCII in URIs. - override def toString(): String = origStr - - // Not implemented: - // def toURL(): URL - -} - -object URI { - - def create(str: String): URI = { - try new URI(str) - catch { - case e: URISyntaxException => throw new IllegalArgumentException(e) - } - } - - // IPv4address = 1*digit "." 1*digit "." 1*digit "." 1*digit - private final val ipv4address = "[0-9]{1,3}(?:\\.[0-9]{1,3}){3}" - - private final val ipv6address = { - // http://stackoverflow.com/a/17871737/1149944 - val block = "[0-9a-f]{1,4}" - val lelem = "(?:"+block+":)" - val relem = "(?::"+block+")" - val ipv4 = ipv4address - - "(?:" + - lelem+"{7}"+block+"|"+ // 1:2:3:4:5:6:7:8 - lelem+"{1,7}:|"+ // 1:: 1:2:3:4:5:6:7:: - lelem+"{1,6}"+relem+"|"+ // 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8 - lelem+"{1,5}"+relem+"{1,2}|"+ // 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8 - lelem+"{1,4}"+relem+"{1,3}|"+ // 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8 - lelem+"{1,3}"+relem+"{1,4}|"+ // 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8 - lelem+"{1,2}"+relem+"{1,5}|"+ // 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8 - lelem +relem+"{1,6}|"+ // 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8 - ":(?:"+relem+"{1,7}|:)|" + // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 :: - lelem+"{6}"+ipv4+"|"+ // 1:2:3:4:5:6:10.0.0.1 - lelem+"{1,5}:"+ipv4+"|"+ // 1::10.0.0.1 1:2:3:4:5::10.0.0.1 - lelem+"{1,4}"+relem+":"+ipv4+"|"+ // 1::6:10.0.0.1 1:2:3:4::6:10.0.0.1 - lelem+"{1,3}"+relem+"{1,2}:"+ipv4+"|"+ // 1::5:6:10.0.0.1 1:2:3::5:6:10.0.0.1 1:2:3::6:10.0.0.1 - lelem+"{1,2}"+relem+"{1,3}:"+ipv4+"|"+ // 1::4:5:6:10.0.0.1 1:2::4:5:6:10.0.0.1 1:2::6:10.0.0.1 - lelem +relem+"{1,4}:"+ipv4+"|"+ // 1::3:4:5:6:10.0.0.1 1::3:4:5:6:10.0.0.1 1::6:10.0.0.1 - "::"+lelem+"{1,5}"+ipv4+ // ::2:3:4:5:10.0.0.1 ::5:10.0.0.1 ::10.0.0.1 - ")(?:%[0-9a-z]+)?" - - // This was part of the original regex, but is too specific to - // IPv6 details. - // fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}| # fe80::7:8%eth0 fe80::7:8%1 (link-local IPv6 addresses with zone index) - // ::(ffff(:0{1,4}){0,1}:){0,1} - // ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3} - // (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])| # ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses) - // ([0-9a-fA-F]{1,4}:){1,4}: - // ((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3} - // (25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]) # 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address) - } - - private val ipv6Re = new RegExp("^"+ipv6address+"$", "i") - - // URI syntax parser. Based on RFC2396, RFC2732 and adaptations according to - // JavaDoc. - // - http://www.ietf.org/rfc/rfc2396.txt (see Appendix A for complete syntax) - // - http://www.ietf.org/rfc/rfc2732.txt - - private val uriRe = { - // We don't use any interpolators here to allow for constant folding - - /////////////////// - //// Helpers //// - /////////////////// - - // Inlined definitions - // reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | - // "$" | "," | "[" | "]" ; last two added by RFC2732 - // unreserved = alphanum | mark - // mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | - // "(" | ")" - - // escaped = "%" hex hex - val escaped = "%[a-f0-9]{2}" - - // uric = reserved | unreserved | escaped - val uric = "(?:[;/?:@&=+$,\\[\\]a-z0-9-_.!~*'()]|"+escaped+")" - - // pchar = unreserved | escaped | - // ":" | "@" | "&" | "=" | "+" | "$" | "," - val pchar = "(?:[a-z0-9-_.!~*'():@&=+$,]|"+escaped+")" - - /////////////////// - //// Server //// - /////////////////// - - // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum - val domainlabel = "(?:[a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])" - - // toplabel = alpha | alpha *( alphanum | "-" ) alphanum - val toplabel = "(?:[a-z]|[a-z][a-z0-9-]*[a-z0-9])" - - // hostname = *( domainlabel "." ) toplabel [ "." ] - val hostname = "(?:"+domainlabel+"\\.)*"+toplabel+"\\.?" - - // IPv6reference = "[" IPv6address "]" - val ipv6reference = "\\[(?:"+ipv6address+")\\]" - - // host = hostname | IPv4address | IPv6reference - // ; IPv6reference added by RFC2732 - val host = "("+hostname+"|"+ipv4address+"|"+ipv6reference+")" /*CAPT*/ - - // Inlined definition - // port = *digit - - // hostport = host [ ":" port ] - val hostport = host+"(?::([0-9]*))?" /*CAPT*/ - - // userinfo = *( unreserved | escaped | - // ";" | ":" | "&" | "=" | "+" | "$" | "," ) - val userinfo = "(?:[a-z0-9-_.!~*'();:&=+$,]|"+escaped+")*" - - // server = [ [ userinfo "@" ] hostport ] - val server = "(?:(?:("+userinfo+")@)?"+hostport+")?" /*CAPT*/ - - /////////////////// - //// Authority //// - /////////////////// - - // reg_name = 1*( unreserved | escaped | "$" | "," | - // ";" | ":" | "@" | "&" | "=" | "+" ) - val reg_name = "(?:[a-z0-9-_.!~*'()$,;:@&=+]|"+escaped+")+" - - // authority = server | reg_name - val authority = server+"|"+reg_name - - /////////////////// - //// Paths //// - /////////////////// - - // Inlined definitions - // param = *pchar - - // segment = *pchar *( ";" param ) - val segment = pchar+"*(?:;"+pchar+"*)*" - - // path_segments = segment *( "/" segment ) - val path_segments = segment+"(?:/"+segment+")*" - - // abs_path = "/" path_segments - val abs_path = "/"+path_segments - - // net_path = "//" authority [ abs_path ] - val net_path = "//("+authority+")("+abs_path+")?" /*2CAPT*/ - - // Inlined definition - // Deviation from RCF2396 according to JavaDoc: Allow empty rel_segment - // and hence empty rel_path - // rel_segment = 1*( unreserved | escaped | - // ";" | "@" | "&" | "=" | "+" | "$" | "," ) - - // rel_path = rel_segment [ abs_path ] - val rel_path = "(?:[a-z0-9-_.!~*'();@&=+$,]|"+escaped+")*(?:"+abs_path+")?" - - /////////////////// - /// Query/Frag /// - /////////////////// - - // query = *uric - val query = "("+uric+"*)" /*CAPT*/ - // fragment = *uric - val fragment = "("+uric+"*)" /*CAPT*/ - - /////////////////// - /// Parts /// - /////////////////// - - // hier_part = ( net_path | abs_path ) [ "?" query ] - val hier_part = "(?:"+net_path+"|("+abs_path+"))(?:\\?"+query+")?" /*CAPT*/ - - // Inlined definition - // uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" | - // "&" | "=" | "+" | "$" | "," - - // opaque_part = uric_no_slash *uric - val opaque_part = "(?:[a-z0-9-_.!~*'();?:@&=+$,]|"+escaped+")"+uric+"*" - - /////////////////// - /// URIs /// - /////////////////// - - // scheme = alpha *( alpha | digit | "+" | "-" | "." ) - val scheme = "([a-z][a-z0-9+-.]*)" /*CAPT*/ - - // absoluteURI = scheme ":" ( hier_part | opaque_part ) - val absoluteURI = scheme+":(?:("+hier_part+")|("+opaque_part+"))" /*2CAPT*/ - - // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ] - val relativeURI = /*2CAPT*/ - "(?:"+net_path+"|("+abs_path+")|("+rel_path+"))(?:\\?"+query+")?" - - // URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ] - val uriRef = "^(?:"+absoluteURI+"|"+relativeURI+")(?:#"+fragment+")?$" - - new RegExp(uriRef, "i") - } - - private object Fields { - final val AbsScheme = 1 - final val AbsHierPart = AbsScheme+1 - final val AbsAuthority = AbsHierPart+1 - final val AbsUserInfo = AbsAuthority+1 - final val AbsHost = AbsUserInfo+1 - final val AbsPort = AbsHost+1 - final val AbsNetPath = AbsPort+1 // abs_path part only - final val AbsAbsPath = AbsNetPath+1 - final val AbsQuery = AbsAbsPath+1 - final val AbsOpaquePart = AbsQuery+1 - final val RelSchemeSpecificPart = 0 // It's the whole string - final val RelAuthority = AbsOpaquePart+1 - final val RelUserInfo = RelAuthority+1 - final val RelHost = RelUserInfo+1 - final val RelPort = RelHost+1 - final val RelNetPath = RelPort+1 // abs_path part only - final val RelAbsPath = RelNetPath+1 - final val RelRelPath = RelAbsPath+1 - final val RelQuery = RelRelPath+1 - final val Fragment = RelQuery+1 - } - - // Helpers for constructors - - private def uriStr(scheme: String, ssp: String, fragment: String): String = { - var resStr = "" - - if (scheme != null) - resStr += scheme + ":" - - if (ssp != null) - resStr += quoteIllegal(ssp) - - if (fragment != null) - resStr += "#" + quoteIllegal(fragment) - - resStr - } - - private def uriStr(scheme: String, userInfo: String, host: String, port: Int, - path: String, query: String, fragment: String): String = { - var resStr = "" - - if (scheme != null) - resStr += scheme + ":" - - if (userInfo != null || host != null || port != -1) - resStr += "//" - - if (userInfo != null) - resStr += quoteUserInfo(userInfo) + "@" - - if (host != null) { - if (URI.ipv6Re.test(host)) - resStr += "[" + host + "]" - else - resStr += host - } - - if (port != -1) - resStr += ":" + port - - if (path != null) - resStr += quotePath(path) - - if (query != null) - resStr += "?" + quoteIllegal(query) - - if (fragment != null) - resStr += "#" + quoteIllegal(fragment) - - resStr - } - - private def uriStr(scheme: String, authority: String, path: String, - query: String, fragment: String) = { - var resStr = "" - - if (scheme != null) - resStr += scheme + ":" - - if (authority != null) - resStr += "//" + quoteAuthority(authority) - - if (path != null) - resStr += quotePath(path) - - if (query != null) - resStr += "?" + quoteIllegal(query) - - if (fragment != null) - resStr += "#" + quoteIllegal(fragment) - - resStr - } - - // Quote helpers - - private val quoteChar: js.Function1[String, String] = { (str: String) => - require(str.length == 1) - - val c = str.head.toInt - - if (c > 127) - throw new URISyntaxException(null, "Only ASCII allowed in URIs") - else - f"%%$c%02x" - } - - /** matches any character not in unreserved, punct, escaped or other */ - private val userInfoQuoteRe = - new RegExp("[^a-z0-9-_.!~*'(),;:$&+=%\\s]|%(?![0-9a-f]{2})", "ig") - - /** Quote any character not in unreserved, punct, escaped or other */ - private def quoteUserInfo(str: String) = - (str: js.prim.String).replace(userInfoQuoteRe, quoteChar) - - /** matches any character not in unreserved, punct, escaped, other or equal - * to '/' or '@' - */ - private val pathQuoteRe = - new RegExp("[^a-z0-9-_.!~*'(),;:$&+=%\\s@/]|%(?![0-9a-f]{2})", "ig") - - /** Quote any character not in unreserved, punct, escaped, other or equal - * to '/' or '@' - */ - private def quotePath(str: String) = - (str: js.prim.String).replace(pathQuoteRe, quoteChar) - - /** matches any character not in unreserved, punct, escaped, other or equal - * to '@', '[' or ']' - * The last two are different to how JavaDoc specifies, but hopefully yield - * the same behavior. (We shouldn't escape [], since they may occur - * in IPv6 addresses, but technically speaking they are in reserved - * due to RFC2732). - */ - private val authorityQuoteRe = - new RegExp("[^a-z0-9-_.!~*'(),;:$&+=%\\s@\\[\\]]|%(?![0-9a-f]{2})", "ig") - - /** Quote any character not in unreserved, punct, escaped, other or equal - * to '@' - */ - private def quoteAuthority(str: String) = - (str: js.prim.String).replace(authorityQuoteRe, quoteChar) - - /** matches any character not in unreserved, reserved, escaped or other */ - private val illegalQuoteRe = - new RegExp("[^a-z0-9-_.!~*'(),;:$&+=?/\\[\\]%\\s]|%(?![0-9a-f]{2})", "ig") - - /** Quote any character not in unreserved, reserved, escaped or other */ - private def quoteIllegal(str: String) = - (str: js.prim.String).replace(illegalQuoteRe, quoteChar) - - /** Case-sensitive comparison that is case-insensitive inside URI - * escapes. Will compare `a%A0` and `a%a0` as equal, but `a%A0` and - * `A%A0` as different. - */ - private def escapeAwareCompare(x: String, y: String): Int = { - @tailrec - def loop(i: Int): Int = { - if (i >= x.length || i >= y.length) - x.length - y.length - else { - val diff = x.charAt(i) - y.charAt(i) - if (diff != 0) diff - else if (x.charAt(i) == '%') { - // we need to do a CI compare for the next two characters - assert(x.length > i + 2, "Invalid escape in URI") - assert(y.length > i + 2, "Invalid escape in URI") - val cmp = - x.substring(i+1, i+3).compareToIgnoreCase(y.substring(i+1, i+3)) - if (cmp != 0) cmp - else loop(i+3) - } else loop(i+1) - } - } - - loop(0) - } - - /** Upper-cases all URI escape sequences in `str`. Used for hashing */ - private def normalizeEscapes(str: String): String = { - var i = 0 - var res = "" - while (i < str.length) { - if (str.charAt(i) == '%') { - assert(str.length > i + 2, "Invalid escape in URI") - res += str.substring(i, i+3).toUpperCase() - i += 3 - } else { - res += str.substring(i, i+1) - i += 1 - } - } - - res - } - - private final val uriSeed = 53722356 - -} |