Skip to content

Instantly share code, notes, and snippets.

@Atry
Forked from pcting/AkkaHttpCorsSupport.scala
Created July 22, 2016 05:58
Show Gist options
  • Save Atry/f51e5e4fcf5d7151db1b126043b58389 to your computer and use it in GitHub Desktop.
Save Atry/f51e5e4fcf5d7151db1b126043b58389 to your computer and use it in GitHub Desktop.
Akka HTTP 1.0 CORS Support
import akka.http.scaladsl.model.HttpHeader
import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.model.headers.`Access-Control-Allow-Credentials`
import akka.http.scaladsl.model.headers.`Access-Control-Allow-Methods`
import akka.http.scaladsl.model.headers.`Access-Control-Allow-Origin`
import akka.http.scaladsl.model.headers.Origin
import akka.http.scaladsl.server.Directive0
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.MethodRejection
import akka.http.scaladsl.server.RejectionHandler
trait CorsSupport {
protected def corsAllowOrigins: List[String]
protected def corsAllowedHeaders: List[String]
protected def corsAllowCredentials: Boolean
protected def optionsCorsHeaders: List[HttpHeader]
protected def corsRejectionHandler(allowOrigin: `Access-Control-Allow-Origin`) = RejectionHandler
.newBuilder().handle {
case MethodRejection(supported) =>
complete(HttpResponse().withHeaders(
`Access-Control-Allow-Methods`(OPTIONS, supported) ::
allowOrigin ::
optionsCorsHeaders
))
}
.result()
private def originToAllowOrigin(origin: Origin): Option[`Access-Control-Allow-Origin`] =
if (corsAllowOrigins.contains("*") || corsAllowOrigins.contains(origin.value))
origin.origins.headOption.map(`Access-Control-Allow-Origin`.apply)
else
None
def cors[T]: Directive0 = mapInnerRoute { route => context =>
((context.request.method, context.request.header[Origin].flatMap(originToAllowOrigin)) match {
case (OPTIONS, Some(allowOrigin)) =>
handleRejections(corsRejectionHandler(allowOrigin)) {
respondWithHeaders(allowOrigin, `Access-Control-Allow-Credentials`(corsAllowCredentials)) {
route
}
}
case (_, Some(allowOrigin)) =>
respondWithHeaders(allowOrigin, `Access-Control-Allow-Credentials`(corsAllowCredentials)) {
route
}
case (_, _) =>
route
})(context)
}
}
...
object Main extends App with CorsSupport {
override val corsAllowOrigins: List[String] = List("*")
override val corsAllowedHeaders: List[String] = List("Origin", "X-Requested-With", "Content-Type", "Accept", "Accept-Encoding", "Accept-Language", "Host", "Referer", "User-Agent")
override val corsAllowCredentials: Boolean = true
override val optionsCorsHeaders: List[HttpHeader] = List[HttpHeader](
`Access-Control-Allow-Headers`(corsAllowedHeaders.mkString(", ")),
`Access-Control-Max-Age`(60 * 60 * 24 * 20), // cache pre-flight response for 20 days
`Access-Control-Allow-Credentials`(corsAllowCredentials)
)
val routes = cors {
complete("CORS YES!")
}
...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment