diff options
author | Li Haoyi <haoyi.sg@gmail.com> | 2018-07-21 19:05:57 +0800 |
---|---|---|
committer | Li Haoyi <haoyi.sg@gmail.com> | 2018-07-21 19:05:57 +0800 |
commit | aa67cc44e7154601bdccd852ce43585b9f138215 (patch) | |
tree | fc1d8848e308639f72adbe1069f354c668effef0 /cask | |
parent | 65f27110fa611c34fe8867dbe69ba608da23f592 (diff) | |
download | cask-aa67cc44e7154601bdccd852ce43585b9f138215.tar.gz cask-aa67cc44e7154601bdccd852ce43585b9f138215.tar.bz2 cask-aa67cc44e7154601bdccd852ce43585b9f138215.zip |
Add user-overrideable error renderer
Diffstat (limited to 'cask')
-rw-r--r-- | cask/src/cask/Annotations.scala | 1 | ||||
-rw-r--r-- | cask/src/cask/Main.scala | 49 | ||||
-rw-r--r-- | cask/src/cask/Status.scala | 285 |
3 files changed, 304 insertions, 31 deletions
diff --git a/cask/src/cask/Annotations.scala b/cask/src/cask/Annotations.scala index 83534e6..e77d98c 100644 --- a/cask/src/cask/Annotations.scala +++ b/cask/src/cask/Annotations.scala @@ -15,7 +15,6 @@ class get(val path: String) extends StaticAnnotation with RouteBase class post(val path: String) extends StaticAnnotation with RouteBase class put(val path: String) extends StaticAnnotation with RouteBase class route(val path: String, val methods: Seq[String]) extends StaticAnnotation with RouteBase - class static(val path: String) extends StaticAnnotation{ def wrapOutput(t: String) = t } diff --git a/cask/src/cask/Main.scala b/cask/src/cask/Main.scala index acf7a0d..d16172c 100644 --- a/cask/src/cask/Main.scala +++ b/cask/src/cask/Main.scala @@ -29,14 +29,26 @@ abstract class BaseMain{ yield (Util.splitPath(metadata.metadata.path): IndexedSeq[String], (route, metadata.entryPoint)) ) + def handleError(statusCode: Int): Response = { + Response( + s"Error $statusCode: ${Status.codesToStatus(statusCode).reason}", + statusCode = statusCode + ) + } + + def writeResponse(exchange: HttpServerExchange, response: Response) = { + response.headers.foreach{case (k, v) => + exchange.getResponseHeaders.put(new HttpString(k), v) + } + + exchange.setStatusCode(response.statusCode) + response.data.write(exchange.getOutputStream) + } + lazy val defaultHandler = new HttpHandler() { def handleRequest(exchange: HttpServerExchange): Unit = { routeTrie.lookup(Util.splitPath(exchange.getRequestPath).toList, Map()) match{ - case None => - - exchange.setStatusCode(404) - exchange.getResponseHeaders.put(Headers.CONTENT_TYPE, "text/plain") - exchange.getResponseSender.send("404 Not Found") + case None => writeResponse(exchange, handleError(404)) case Some(((routes, entrypoint), bindings)) => import collection.JavaConverters._ val allBindings = @@ -51,31 +63,8 @@ abstract class BaseMain{ .invoke(routes, exchange, allBindings.map{case (k, v) => (k, Some(v))}) result match{ - case Router.Result.Success(response: Response) => - response.headers.foreach{case (k, v) => - exchange.getResponseHeaders.put(new HttpString(k), v) - } - - exchange.setStatusCode(response.statusCode) - - - response.data.write( - new OutputStream { - def write(b: Int) = { - exchange.getResponseSender.send(ByteBuffer.wrap(Array(b.toByte))) - } - override def write(b: Array[Byte]) = { - exchange.getResponseSender.send(ByteBuffer.wrap(b)) - } - override def write(b: Array[Byte], off: Int, len: Int) = { - exchange.getResponseSender.send(ByteBuffer.wrap(b.slice(off, off + len))) - } - } - ) - case err: Router.Result.Error => - exchange.setStatusCode(400) - exchange.getResponseHeaders.put(Headers.CONTENT_TYPE, "text/plain") - exchange.getResponseSender.send("400 Not Found " + result) + case Router.Result.Success(response: Response) => writeResponse(exchange, response) + case err: Router.Result.Error => writeResponse(exchange, handleError(400)) } diff --git a/cask/src/cask/Status.scala b/cask/src/cask/Status.scala new file mode 100644 index 0000000..a1915b1 --- /dev/null +++ b/cask/src/cask/Status.scala @@ -0,0 +1,285 @@ +package cask + +sealed trait Status { + val code: Int + val reason: String +} + +object Status { + val codesToStatus: Map[Int, Status] = Map( + 100 -> Continue, + 101 -> SwitchingProtocols, + 200 -> OK, + 201 -> Created, + 202 -> Accepted, + 203 -> NonAuthoritativeInformation, + 204 -> NoContent, + 205 -> ResetContent, + 206 -> PartialContent, + 300 -> MultipleChoices, + 301 -> MovedPermanently, + 302 -> Found, + 303 -> SeeOther, + 304 -> NotModified, + 305 -> UseProxy, + 307 -> TemporaryRedirect, + 308 -> PermanentRedirect, + 400 -> BadRequest, + 401 -> Unauthorized, + 402 -> PaymentRequired, + 403 -> Forbidden, + 404 -> NotFound, + 405 -> MethodNotAllowed, + 406 -> NotAcceptable, + 407 -> ProxyAuthenticationRequired, + 408 -> RequestTimeout, + 409 -> Conflict, + 410 -> Gone, + 411 -> LengthRequired, + 412 -> PreconditionFailed, + 413 -> RequestEntityTooLarge, + 414 -> RequestURITooLong, + 415 -> UnsupportedMediaType, + 416 -> RequestedRangeNotSatisfiable, + 417 -> ExpectationFailed, + 418 -> Teapot, + 420 -> EnhanceYourCalm, + 429 -> TooManyRequests, + 451 -> UnavailableForLegalReasons, + 501 -> NotImplemented, + 502 -> BadGateway, + 503 -> ServiceUnavailable, + 504 -> GatewayTimeout, + 505 -> HTTPVersionNotSupported + ) + + val statusToCodes: Map[String, Int] = + codesToStatus.map { case (code, status) => status.reason -> code } +} + +case class Unknown(code: Int, reason: String) extends Status + +case object Continue extends Status { + val code = 100 + val reason: String = "Continue" +} + +case object SwitchingProtocols extends Status { + val code = 101 + val reason: String = "Switching Protocols" +} + +case object OK extends Status { + val code = 200 + val reason: String = "OK" +} + +case object Created extends Status { + val code = 201 + val reason: String = "Created" +} + +case object Accepted extends Status { + val code = 202 + val reason: String = "Accepted" +} + +case object NonAuthoritativeInformation extends Status { + val code = 203 + val reason: String = "Non-Authoritative Information" +} + +case object NoContent extends Status { + val code = 204 + val reason: String = "No Content" +} + +case object ResetContent extends Status { + val code = 205 + val reason: String = "Reset Content" +} + +case object PartialContent extends Status { + val code = 206 + val reason: String = "Partial Content" +} + +case object MultipleChoices extends Status { + val code = 300 + val reason: String = "Multiple Choices" +} + +case object MovedPermanently extends Status { + val code = 301 + val reason: String = "Moved Permanently" +} + +case object Found extends Status { + val code = 302 + val reason: String = "Found" +} + +case object SeeOther extends Status { + val code = 303 + val reason: String = "See Other" +} + +case object NotModified extends Status { + val code = 304 + val reason: String = "Not Modified" +} + +case object UseProxy extends Status { + val code = 305 + val reason: String = "Use Proxy" +} + +case object TemporaryRedirect extends Status { + val code = 307 + val reason: String = "Temporary Redirect" +} + +case object PermanentRedirect extends Status { + val code = 308 + val reason: String = "Permanent Redirect" +} + +case object BadRequest extends Status { + val code = 400 + val reason: String = "Bad Request" +} + +case object Unauthorized extends Status { + val code = 401 + val reason: String = "Unauthorized" +} + +case object PaymentRequired extends Status { + val code = 402 + val reason: String = "Payment Required" +} + +case object Forbidden extends Status { + val code = 403 + val reason: String = "Forbidden" +} + +case object NotFound extends Status { + val code = 404 + val reason: String = "Not Found" +} + +case object MethodNotAllowed extends Status { + val code = 405 + val reason: String = "Method Not Allowed" +} + +case object NotAcceptable extends Status { + val code = 406 + val reason: String = "Not Acceptable" +} + +case object ProxyAuthenticationRequired extends Status { + val code = 407 + val reason: String = "Proxy Authentication Required" +} + +case object RequestTimeout extends Status { + val code = 408 + val reason: String = "Request Time-out" +} + +case object Conflict extends Status { + val code = 409 + val reason: String = "Conflict" +} + +case object Gone extends Status { + val code = 410 + val reason: String = "Gone" +} + +case object LengthRequired extends Status { + val code = 411 + val reason: String = "Length Required" +} + +case object PreconditionFailed extends Status { + val code = 412 + val reason: String = "Precondition Failed" +} + +case object RequestEntityTooLarge extends Status { + val code = 413 + val reason: String = "Request Entity Too Large" +} + +case object RequestURITooLong extends Status { + val code = 414 + val reason: String = "Request-URI Too Large" +} + +case object UnsupportedMediaType extends Status { + val code = 415 + val reason: String = "Unsupported Media Type" +} + +case object RequestedRangeNotSatisfiable extends Status { + val code = 416 + val reason: String = "Requested range not satisfiable" +} + +case object ExpectationFailed extends Status { + val code = 417 + val reason: String = "Expectation Failed" +} + +case object Teapot extends Status { + val code = 418 + val reason: String = "I'm a teapot" +} + +case object EnhanceYourCalm extends Status { + val code = 420 + val reason: String = "Enhance Your Calm" +} + +case object TooManyRequests extends Status { + val code = 429 + val reason: String = "Too Many Requests" +} + +case object UnavailableForLegalReasons extends Status { + val code = 451 + val reason: String = "Unavailable For Legal Reasons" +} + +case object InternalServerError extends Status { + val code = 500 + val reason: String = "Internal Server Error" +} + +case object NotImplemented extends Status { + val code = 501 + val reason: String = "Not Implemented" +} + +case object BadGateway extends Status { + val code = 502 + val reason: String = "Bad Gateway" +} + +case object ServiceUnavailable extends Status { + val code = 503 + val reason: String = "Service Unavailable" +} + +case object GatewayTimeout extends Status { + val code = 504 + val reason: String = "Gateway Time-out" +} + +case object HTTPVersionNotSupported extends Status { + val code = 505 + val reason: String = "HTTP Version not supported" +} |