rl.Uri.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rl_2.9.1 Show documentation
Show all versions of rl_2.9.1 Show documentation
An RFC-3986 compliant URI library.
The newest version!
package rl
import java.lang.{ UnsupportedOperationException, Boolean }
import java.net.{ URI, URISyntaxException, IDN }
trait UriNode {
def uriPart: String
def normalize: UriNode
def apply(): String
}
trait UriOperations {
def +(other: Uri): Uri
def normalize: Uri
def /(other: Uri): Uri
}
trait Uri {
def scheme: UriScheme
def authority: Option[Authority]
def segments: UriPath
def query: QueryString
def fragment: UriFragment
lazy val user = authority flatMap (_.userInfo map (_.user))
lazy val secret = authority flatMap (_.userInfo map (_.secret))
lazy val host = authority map (_.host.value)
lazy val port = authority map (_.port)
lazy val path = segments()
lazy val queryString = query()
lazy val rawQuery = query.rawValue
def originalUri: String
def isAbsolute: Boolean
def isRelative: Boolean
def normalize: Uri = normalize(false)
def normalize(stripCommonPrefixFromHost: Boolean = false): Uri
def asciiString = {
scheme.uriPart + authority.map(_.uriPart).getOrElse("") + segments.uriPart + query.uriPart + fragment.uriPart
}
}
case class AbsoluteUri(scheme: Scheme, authority: Option[Authority], segments: UriPath, query: QueryString, fragment: UriFragment, originalUri: String = "") extends Uri {
val isAbsolute: Boolean = true
val isRelative: Boolean = false
def normalize(stripCommonPrefixFromHost: Boolean = false) =
copy(scheme.normalize, authority.map(_.normalize(stripCommonPrefixFromHost)), segments.normalize, query.normalize, fragment.normalize)
}
case class RelativeUri(authority: Option[Authority], segments: UriPath, query: QueryString, fragment: UriFragment, originalUri: String = "") extends Uri {
val scheme = NoScheme
val isAbsolute: Boolean = false
val isRelative: Boolean = true
def normalize(stripCommonPrefixFromHost: Boolean = false) =
copy(authority.map(_.normalize(stripCommonPrefixFromHost)), segments.normalize, query.normalize, fragment.normalize)
}
case class FailedUri(throwable: Throwable, originalUri: String = "") extends Uri {
private def noop = {
val u = originalUri.blankOption getOrElse "not set"
throw new UnsupportedOperationException("Parsing the uri '%s' failed." format u, throwable)
}
def fragment = noop
def query = noop
def segments = noop
def authority = noop
def scheme = noop
val isRelative: Boolean = false
val isAbsolute: Boolean = false
def normalize(stripCommonPrefixFromHost: Boolean = false) = this
}
object Uri {
/*
* The regex to split a URI up into its parts for further processing
* Source: http://tools.ietf.org/html/rfc3986#appendix-B
*/
val UriParts = """^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?""".r
def apply(uriString: String): Uri = {
try {
apply(URI.create(uriString))
} catch {
case e: URISyntaxException ⇒ {
FailedUri(e, uriString)
}
case e: IllegalArgumentException ⇒ {
FailedUri(e, uriString)
}
}
}
def apply(u: URI, originalUri: Option[String] = None): Uri = {
try {
val pth = parsePath(u.getRawPath.blankOption)
if (u.isAbsolute) {
AbsoluteUri(
Scheme(u.getScheme),
u.getRawAuthority.blankOption.map(a ⇒ Authority(IDN.toASCII(a))),
pth,
QueryString(u.getRawQuery),
UriFragment(u.getRawFragment),
originalUri getOrElse u.toString)
} else {
RelativeUri(
u.getRawAuthority.blankOption.map(a ⇒ Authority(IDN.toASCII(a))),
pth,
QueryString(u.getRawQuery),
UriFragment(u.getRawFragment),
originalUri getOrElse u.toString)
}
} catch {
case e: NullPointerException ⇒ {
FailedUri(e, originalUri getOrElse u.toString)
}
case e: Throwable ⇒ {
FailedUri(e, originalUri getOrElse u.toString)
}
}
}
private def parsePath(text: Option[String]): UriPath = {
text match {
case None ⇒ EmptyPath
case Some(pt) if pt.trim == "/" ⇒ EmptyPath
case Some(pt) if pt.startsWith("/") ⇒ AbsolutePath(pt.split("/").drop(1).toList)
case Some(pt) ⇒ RelativePath(pt.split("/"))
}
}
}