All Downloads are FREE. Search and download functionalities are using the official Maven repository.

skinny.micro.rl.Uri.scala Maven / Gradle / Ivy

// The MIT License (MIT) Copyright (c) 2011 Mojolly Ltd.
package skinny.micro.rl

import java.net.{ IDN, URI, URISyntaxException }

import scala.util.control.NonFatal

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 withPath(path: String): this.type

  def asciiStringWithoutTrailingSlash = {
    scheme.uriPart + authority.map(_.uriPart).getOrElse("") +
      segments.uriPartWithoutTrailingSlash +
      query.uriPart +
      fragment.uriPart
  }

  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)

  def withPath(path: String): this.type = {
    val segments = UriPath.parsePath(path.blankOption map UrlCodingUtils.ensureUrlEncoding).normalize
    copy(segments = segments).asInstanceOf[this.type]
  }

}

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)

  def withPath(path: String): this.type = {
    val segments = UriPath.parsePath(path.blankOption map UrlCodingUtils.ensureUrlEncoding).normalize
    copy(segments = segments).asInstanceOf[this.type]
  }

}

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

  def withPath(path: String): this.type = 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 = UriPath.parsePath(u.getRawPath.blankOption map UrlCodingUtils.ensureUrlEncoding)

      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 NonFatal(e) => {
        FailedUri(e, originalUri getOrElse u.toString)
      }
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy