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

scalaz.http.response.Response.scala Maven / Gradle / Ivy

The newest version!
package scalaz
package http
package response


import request.Request
import request.UserAgent
import Scalaz._
import Util._
import Util.Nel._

/**
 * HTTP response.
 * RFC 2616 Section 6 Response.
 *
 * @author Tony Morris
 */
sealed trait Response[OUT[_]] {
  /**
   * The response status line.
   */
  val line: StatusLine

  /**
   * The response headers.
   */
  val headers: List[(ResponseHeader, NonEmptyList[Char])]

  /**
   * The response body.
   */
  val body: OUT[Byte]

  import Response.response

  /**
   * Add the given header and value to this response.
   */
  def apply(h: ResponseHeader, v: NonEmptyList[Char]) = response[OUT](line, (h, v) :: headers, body)

  /**
   * Add the given header and value to this response.
   * This function fails if the given string value is empty.
   */
  def apply(h: ResponseHeader, s: String): Response[OUT] = apply(h, s.charsNelErr("Header values must be non-empty"))

  /**
   * Replace the status line of this reponse with the given status line.
   */
  def apply(l: StatusLine) = response[OUT](l, headers, body)

  /**
   * Return the value of given header.
   */
  def apply(h: ResponseHeader) = headersMapHeads.get(h)

  /**
   * Replace the body of this response with the given body.
   */
  def >>(b: OUT[Byte]) = response[OUT](line, headers, b)

  /**
   * Append the given value to the body of this response.
   */
  def |+|(b: OUT[Byte])(implicit s: Semigroup[OUT[Byte]]) = response[OUT](line, headers, s.append(body, b))

  /**
   * Delete the given header value from this response.
   */
  def -(h: ResponseHeader) = response[OUT](line, headers filter { case (k, _) => h != k }, body)

  /**
   * Append the given value to the body of this response.
   */
  def <<[A](a: A)(implicit b: Body[OUT, A], s: Semigroup[OUT[Byte]]) = response[OUT](line, headers, s.append(body, b(a)))

  /**
   * Prepend the given value to the body of this response.
   */
  def <<:[A](a: A)(implicit b: Body[OUT, A], s: Semigroup[OUT[Byte]]) = response[OUT](line, headers, s.append(b(a), body))

  /**
   * A map of headers offering optimal seek time.
   */
  lazy val headersMap = asHashMap[List, NonEmptyList](headers)

  /**
   * A map of headers offering optimal seek time.
   */
  lazy val headersMapHeads = mapHeads(headersMap)

  /**
   * The response version major of the status line.
   */
  def versionMajor = line.version.major

  /**
   * The response version minor of the status line.
   */
  def versionMinor = line.version.minor

  /**
   * The response status.
   */
  def status = line.status

  /**
   * The response status.
   */
  def reasonPhrase = line.reasonPhrase

  /**
   * Returns true if the status code of this response is a 200 OK.
   */
  def isOK = status == OK

  /**
   * Returns true if the status code of this response is a 400 Bad Request.
   */
  def isBadRequest = status == BadRequest

  /**
   * Returns true if the value of the given content-type header satisfies the given condition.
   */
  def contentType(f: NonEmptyList[Char] => Boolean) =
    (this(ContentType): Iterable[NonEmptyList[Char]]) exists f

  /**
   * Returns true if the value of the given content-type header equals the given value.
   */
  def contentTypeEquals(s: String) = contentType(_.mkString == s)

  /**
   * Returns true if this response has set the content-type header.
   */
  def hasContentType = this(ContentType).isDefined

  /**
   * The length of the response body.
   */
  def bodyLength(implicit f: Foldable[OUT]) = body.count

  /**
   * Returns the response body as a string.
   */
  def bodyString(implicit e: Each[OUT]) = {
    val s = new StringBuilder
    e.each(body, (b: Byte) => s append (b.toChar))
    s.toString
  }

  /**
   * Sets the Content-Type response header for HTML.
   */
  def html = this(ContentType, "text/html")

  /**
   * Sets the Content-Type response header for XHTML.
   */
  def xhtml = this(ContentType, "application/xhtml+xml")

  /**
   * Sets the Content-Type response header for XML.
   */
  def xml = this(ContentType, "text/xml")

  /**
   * Sets the ContentType response header according to the
   * W3C MIME Reference if the given request path
   * has a file extension and corresponds to a known file extension.
   */
  def unary_~[IN[_]](implicit request: Request[IN]) =
    ContentTypeResolver.w3cMimeReference(request.pathExtension) map (this(ContentType, _)) getOrElse this

  /**
   * Sets the content-type response header for XHTML (application/xhtml+xml), however, if the browser
   * identifies itself as not accepting this content type, set the response header for HTML
   * (text/html).
   */
  def acceptsXhtml[IN[_]](implicit req: Request[IN]) =
    if(hasContentType) this else this(ContentType, if(req.isInternetExplorer) "text/html" else "application/xhtml+xml")
}

import request.Request
import StatusLine.statusLine

/**
 * HTTP response.
 * RFC 2616 Section 6 Response.
 */
object Response {
  /**
   * Create a response with the given status line, headers and body.
   */
  def response[OUT[_]](l: StatusLine, h: List[(ResponseHeader, NonEmptyList[Char])], b: OUT[Byte]) =
    new Response[OUT] {
      val line = l
      val headers = h
      val body = b
    }

  // Why can't I name these to 'response' without client code barfing?
  // http://www.nabble.com/Why-does-this-fail-the-compiler--tc19024578.html
  // https://lampsvn.epfl.ch/trac/scala/ticket/1236
  /**
   * Create a response with the given status line and body and no headers.
   */
  def emptyHeadersResponse[OUT[_]](l: StatusLine, b: OUT[Byte]): Response[OUT] = response[OUT](l, Nil, b)

  /**
   * Create a response with the given status line and headers and empty body.
   */
  def emptyResponse[OUT[_]](l: StatusLine, h: List[(ResponseHeader, NonEmptyList[Char])])(implicit e: Empty[OUT]) =
    response[OUT](l, h, e.empty)

  /**
   * Create a response with the given status line and no headers and empty body.
   */
  def emptyHeadersBodyResponse[OUT[_]](l: StatusLine)(implicit e: Empty[OUT]) =
    emptyResponse[OUT](l, Nil)

  /**
   * Create a response with the given status, to give rise to a status line whose version is derived from the given request, and headers and empty body.
   */
  def statusResponse[OUT[_], IN[_]](s: Status, h: List[(ResponseHeader, NonEmptyList[Char])], b: OUT[Byte])(implicit req: Request[IN]) =
    response[OUT](statusLine[IN](s), h, b)

  /**
   * Create a response with the given status, to give rise to a status line whose version is derived from the given request, body and no headers.
   */
  def emptyHeadersStatusResponse[OUT[_], IN[_]](s: Status, b: OUT[Byte])(implicit req: Request[IN]) =
    response[OUT](statusLine[IN](s), Nil, b)

  /**
   * Create a response with the given status, to give rise to a status line whose version is derived from the given request, headers and empty body.
   */
  def emptyStatusResponse[OUT[_], IN[_]](s: Status, h: List[(ResponseHeader, NonEmptyList[Char])])(implicit e: Empty[OUT], req: Request[IN]) =
    response[OUT](statusLine[IN](s), h, e.empty)

  /**
   * Create a response with the given status, to give rise to a status line whose version is derived from the given request, no headers and empty body.
   */
  def emptyHeadersBodyStatusResponse[OUT[_], IN[_]](s: Status)(implicit e: Empty[OUT], req: Request[IN]) =
    response[OUT](statusLine[IN](s), Nil, e.empty)

  /**
   * Create a response with the given version and status in the status line, headers and body.
   */
  def versionStatusResponse[OUT[_]](v: Version, s: Status, h: List[(ResponseHeader, NonEmptyList[Char])], b: OUT[Byte]) =
    response[OUT](statusLine(v, s), h, b)

  /**
   * Create a response with the given version and status in the status line, body and no headers.
   */
  def emptyHeadersVersionStatusResponse[OUT[_]](v: Version, s: Status, b: OUT[Byte]) =
    response[OUT](statusLine(v, s), Nil, b)

  /**
   * Create a response with the given version and status in the status line, headers and empty body.
   */
  def emptyVersionStatusResponse[OUT[_]](v: Version, s: Status, h: List[(ResponseHeader, NonEmptyList[Char])])(implicit e: Empty[OUT]) =
    response[OUT](statusLine(v, s), h, e.empty)

  /**
   * Create a response with the given version and status in the status line, no headers and empty body.
   */
  def emptyHeadersBodyVersionStatusResponse[OUT[_]](v: Version, s: Status)(implicit e: Empty[OUT]) =
    response[OUT](statusLine(v, s), Nil, e.empty)

  /**
   * Create a response with the given version that redirects (301 Moved Permanently) to the given location.
   */
  def versionRedirect[OUT[_]](version: Version, location: NonEmptyList[Char])(implicit e: Empty[OUT]) =
    response[OUT](statusLine(version, MovedPermanently), List((Location, location)), e.empty)

  /**
   * Create a response with the given version that redirects (301 Moved Permanently) to the given location.
   * This function fails if the given string value is empty.
   */
  def versionRedirects[OUT[_]](version: Version, location: String)(implicit e: Empty[OUT]) =
    response[OUT](statusLine(version, MovedPermanently), List((Location, location.charsNelErr("location must be non-empty"))), e.empty)

  /**
   * Create a response with a version derived from the given request that redirects (301 Moved Permanently) to the given location.
   */
  def redirect[OUT[_], IN[_]](location: NonEmptyList[Char], parameters: (String, String)*)(implicit e: Empty[OUT], req: Request[IN]) =
    response[OUT](statusLine[IN](MovedPermanently), List((Location, if(parameters.isEmpty) location else location :::> ('?' + encode(parameters: _*)).toList)), e.empty)

  /**
   * Create a response with a version derived from the given request that redirects (301 Moved Permanently) to the given location.
   * This function fails if the given string value is empty.
   */
  def redirects[OUT[_], IN[_]](location: String, parameters: (String, String)*)(implicit e: Empty[OUT], req: Request[IN]) =
    redirect[OUT, IN](location.charsNelErr("location must be non-empty"), parameters: _*)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy