Giter Site home page Giter Site logo

akka-http-cors's Introduction

akka-http-cors

Software License Scala Steward badge

CORS (Cross Origin Resource Sharing) is a mechanism to enable cross origin requests.

This is a Scala/Java implementation for the server-side targeting the akka-http library.

A version supporting the Apache Pekko fork is also available in pekko-http-cors.

Versions

Version Release date Akka Http version Scala versions
1.2.0 2023-03-04 10.2.10 2.12.17, 2.13.10, 3.2.2
1.1.3 2022-01-30 10.2.7 2.12.15, 2.13.8, 3.1.1
1.0.0 2020-05-25 10.1.12 2.12.11, 2.13.2
0.1.0 2016-03-20 2.4.2 2.11.8

Some less interesting versions are not listed in the above table. The complete list can be found in the CHANGELOG file.

Getting Akka Http Cors

akka-http-cors is deployed to Maven Central. Add it to your build.sbt or Build.scala:

libraryDependencies += "ch.megard" %% "akka-http-cors" % "1.2.0"

Quick Start

The simplest way to enable CORS in your application is to use the cors directive. Settings are passed as a parameter to the directive, with your overrides loaded from the application.conf.

import ch.megard.akka.http.cors.scaladsl.CorsDirectives._

val route: Route = cors() {
  complete(...)
}

The settings can be updated programmatically too.

val settings = CorsSettings(...).withAllowGenericHttpRequests(false)
val strictRoute: Route = cors(settings) {
  complete(...)
}

A full example, with proper exception and rejection handling, is available in the akka-http-cors-example sub-project.

Rejection

The CORS directives can reject requests using the CorsRejection class. Requests can be either malformed or not allowed to access the resource.

A rejection handler is provided by the library to return meaningful HTTP responses. Read the akka documentation to learn more about rejections, or if you need to write your own handler.

import akka.http.scaladsl.server.directives.ExecutionDirectives._
import ch.megard.akka.http.cors.scaladsl.CorsDirectives._

val route: Route = handleRejections(corsRejectionHandler) {
  cors() {
    complete(...)
  }
}

Java support

Starting from version 0.2.1 Java is supported, mirroring the Scala API. For usage, look at the full Java CorsServer example.

Configuration

Reference configuration.

allowGenericHttpRequests

Boolean with default value true.

If true, allow generic requests (that are outside the scope of the specification) to pass through the directive. Else, strict CORS filtering is applied and any invalid request will be rejected.

allowCredentials

Boolean with default value true.

Indicates whether the resource supports user credentials. If true, the header Access-Control-Allow-Credentials is set in the response, indicating the actual request can include user credentials.

Examples of user credentials are: cookies, HTTP authentication or client-side certificates.

allowedOrigins

HttpOriginMatcher with default value HttpOriginMatcher.*.

List of origins that the CORS filter must allow. Can also be set to * to allow access to the resource from any origin. Controls the content of the Access-Control-Allow-Origin response header:

  • if parameter is * and credentials are not allowed, a * is set in Access-Control-Allow-Origin.
  • otherwise, the origins given in the Origin request header are echoed.

Hostname starting with *. will match any sub-domain. The scheme and the port are always strictly matched.

The actual or preflight request is rejected if any of the origins from the request is not allowed.

allowedHeaders

HttpHeaderRange with default value HttpHeaderRange.*.

List of request headers that can be used when making an actual request. Controls the content of the Access-Control-Allow-Headers header in a preflight response:

  • if parameter is *, the headers from Access-Control-Request-Headers are echoed.
  • otherwise the parameter list is returned as part of the header.

allowedMethods

Seq[HttpMethod] with default value Seq(GET, POST, HEAD, OPTIONS).

List of methods that can be used when making an actual request. The list is returned as part of the Access-Control-Allow-Methods preflight response header.

The preflight request will be rejected if the Access-Control-Request-Method header's method is not part of the list.

exposedHeaders

Seq[String] with default value Seq.empty.

List of headers (other than simple response headers) that browsers are allowed to access. If not empty, this list is returned as part of the Access-Control-Expose-Headers header in the actual response.

maxAge

Option[Long] (in seconds) with default value Some (30 * 60).

When set, the amount of seconds the browser is allowed to cache the results of a preflight request. This value is returned as part of the Access-Control-Max-Age preflight response header. If None, the header is not added to the preflight response.

Benchmarks

Using the sbt-jmh plugin, preliminary benchmarks have been performed to measure the impact of the cors directive on the performance. The first results are shown below.

Results are not all coming from the same machine.

v0.1.2 (Akka 2.4.4)

> jmh:run -i 40 -wi 30 -f2 -t1
Benchmark                         Mode  Cnt     Score     Error  Units
CorsBenchmark.baseline           thrpt   80  3601.121 ± 102.274  ops/s
CorsBenchmark.default_cors       thrpt   80  3582.090 ±  95.304  ops/s
CorsBenchmark.default_preflight  thrpt   80  3482.716 ±  89.124  ops/s

v0.1.3 (Akka 2.4.7)

> jmh:run -i 40 -wi 30 -f2 -t1
Benchmark                         Mode  Cnt     Score     Error  Units
CorsBenchmark.baseline           thrpt   80  3657.762 ± 141.409  ops/s
CorsBenchmark.default_cors       thrpt   80  3687.351 ±  35.176  ops/s
CorsBenchmark.default_preflight  thrpt   80  3645.629 ±  30.411  ops/s

v0.2.2 (Akka HTTP 10.0.6)

> jmh:run -i 40 -wi 30 -f2 -t1
Benchmark                         Mode  Cnt     Score     Error  Units
CorsBenchmark.baseline           thrpt   80  9730.001 ±  25.281  ops/s
CorsBenchmark.default_cors       thrpt   80  9159.320 ±  25.459  ops/s
CorsBenchmark.default_preflight  thrpt   80  9172.938 ±  26.794  ops/s

References

License

This code is open source software licensed under the Apache 2.0 License.

akka-http-cors's People

Contributors

jiminhsieh avatar jonfox avatar lomigmegard avatar mhengelein avatar pjfanning avatar rodrigorn avatar scala-steward avatar sethtisue avatar sirocchj avatar sorenbs avatar xuwei-k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

akka-http-cors's Issues

Adding CORS headers to non-CORS-related rejections

I've observed that when a Route rejects a request for a non-CORS related reason this library won't map the rejection response to include CORS headers even when the request is valid from a CORS perspective. The result is that when an error response is returned to a browser the actual body of the response is opaque because of CORS security.

I looked at the CORS spec and nothing caught my attention that would indicate that error responses should be ignored. Do you think it would make sense to add the headers in this case? I can create a PR if you're in agreement.

Can't use default Seq in CorsSettings methods

Some methods in CoreSettings take a Seq, e.g. CoreSettings.withAllowedMethods. However this does not work with the default Seq that is imported from the scala package. It requires the more restrictive scala.collection.immutable.Seq which is a subclass of the default Seq.

The reason for this is that CorsSettings.scala has import scala.collection.immutable.Seq so all uses of Seq refer to the more restrictive type. Looking at the code there appears to be no benefit from this more restrictive type, so the fix is to remove the import.

Handling PUT actions for Allow-Origin

I'm getting "Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource."

So assuming i need to inject cors handling (in java) like

   final CorsSettings settings = CorsSettings.defaultSettings().withAllowedOrigins(HttpOriginRange.create(HttpOrigin.create("http", Host.create("*"))));
    return CorsDirectives.cors(settings, () ->
        pathPrefix(PATH, () -> concat(
            path(PathMatchers.segment(RouteDirectory.UPLOAD)
                            .slash(PathMatchers.segment()
                             ),(token)-> upload(token,context)),
            path(PathMatchers.segment(RouteDirectory.DOWNLOAD)
                            .slash(PathMatchers.segment()
                             ),(token)-> withRangeSupport(() -> download(token,context)))
            ))
        );

now i realize "*" isn't good, but i'm just trying to get anything working.... This didn't seem to effect anything. Am i doing this wrong?

Origin with path in the uri rejected

So, long story short :

OPTIONS with the following origin works : http://127.0.0.1:8080 returning :

* Connection state changed (MAX_CONCURRENT_STREAMS updated)! < HTTP/2 200 < date: Tue, 05 Nov 2019 08:49:29 GMT < content-length: 0 < server: nginx/1.17.5 < access-control-allow-headers: content-type < access-control-allow-origin: * < access-control-allow-methods: POST, PUT, GET, OPTIONS, DELETE < access-control-max-age: 600

OPTIONS with the following origin doesn't : http://127.0.0.1:8080/mycoolpage

* Connection state changed (MAX_CONCURRENT_STREAMS updated)! < HTTP/2 204 < date: Tue, 05 Nov 2019 08:48:54 GMT < server: nginx/1.17.5 < allow: POST <

My Akka Http Cors is the following :

private val corsSettings: CorsSettings = CorsSettings(actorSystem)
     .withAllowedOrigins(HttpOriginMatcher.*)
     .withAllowCredentials(false)
     .withAllowedMethods(scala.collection.immutable.Seq(HttpMethods.POST, HttpMethods.PUT, HttpMethods.GET, HttpMethods.OPTIONS, HttpMethods.DELETE))
     .withExposedHeaders(scala.collection.immutable.Seq(
       "Content-Type",
       "X-Content-Type",
       "x-access-token",
       "x-refresh-token",
     ))

Akka doesn't seem to manage origin which are not hostnames ?

Library not compatible with Scala 3

Scala 3.2.2 and everything goes fine without "ch.megard" %% "akka-http-cors" % "1.2.0".

When I do below:

libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor-typed" % "2.8.3",
"com.typesafe.akka" %% "akka-stream" % "2.8.3",
"com.typesafe.akka" %% "akka-http" % "10.5.2",
"ch.megard" % "akka-http-cors_3" % "1.2.0",
...

I get:

Modules were resolved with conflicting cross-version suffixes in ...

[error] com.typesafe.akka:akka-http-core _3, _2.13
[error] com.typesafe.akka:akka-parsing _3, _2.13
[error] com.typesafe.akka:akka-http _3, _2.13
[error] java.lang.RuntimeException: Conflicting cross-version suffixes in: com.typesafe.akka:akka-http-core, com.typesafe.akka:akka-parsing, com.typesafe.akka:akka-http
[error] at scala.sys.package$.error(package.scala:30)
[error] at sbt.librarymanagement.ConflictWarning$.processCrossVersioned(ConflictWarning.scala:39)
[error] at sbt.librarymanagement.ConflictWarning$.apply(ConflictWarning.scala:19)
[error] at sbt.Classpaths$.$anonfun$ivyBaseSettings$71(Defaults.scala:3203)
[error] at scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error] at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62)
[error] at sbt.std.Transform$$anon$4.work(Transform.scala:68)
[error] at sbt.Execute.$anonfun$submit$2(Execute.scala:282)
[error] at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
[error] at sbt.Execute.work(Execute.scala:291)
[error] at sbt.Execute.$anonfun$submit$1(Execute.scala:282)
[error] at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error] at sbt.CompletionService$$anon$2.call(CompletionService.scala:64)
[error] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error] at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
[error] at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
[error] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
[error] at java.base/java.lang.Thread.run(Thread.java:832)
[error] (update) Conflicting cross-version suffixes in: com.typesafe.akka:akka-http-core, com.typesafe.akka:akka-parsing, com.typesafe.akka:akka-http

I tried every variation out there including:

"ch.megard" %% "akka-http-cors" % "1.2.0",

and

"ch.megard" % "akka-http-cors_2_13" % "1.2.0",

Still the same error.

Additional `options` directive required for CORS to work

I have a route for POST requests which should accept frontend requests

Expected behaviour: cors(settings){ route } should be enough to serve CORS requests

Actual behaviour: 405, Method not allowed is returned on the OPTIONS request

Workaround: add a simple options directive to route

  private val methods = List(GET, PUT, POST, PATCH, HEAD, DELETE, OPTIONS)
  val corsSettings: CorsSettings.Default =
    CorsSettings.defaultSettings.copy(allowedMethods = methods)

  val fullRoute = handleRejections(CorsDirectives.corsRejectionHandler) {
    cors(corsSettings) {
      handleRejections(RejectionHandler.default) {
        path("upload") {
//          options {
//            complete(HttpResponse(StatusCodes.OK).withHeaders(`Access-Control-Allow-Methods`(methods: _*)))
//          } ~
          post {
            fileUpload("img") {
              case (fileInfo: FileInfo, fileStream: Source[ByteString, Any]) =>
                logger.info(s"storing ${fileInfo.contentType} / ${fileInfo.fieldName} / ${fileInfo.fileName}")
                complete(StatusCodes.OK)
            }
          }
        }
      }
    }
  }

No actual headers in response?

Hi, I am using this plugin version 0.1.10 with akka-http 10.0.0, akka 2.4.14 and scala 2.11.8.
Unfortunately I don't see any actual headers in the response:

 val settings = CorsSettings.defaultSettings
  val routes = cors(settings) {
    complete("yo")
  }

will return

HTTP/1.1 200 OK
Server: akka-http/10.0.0
Date: Fri, 09 Dec 2016 11:45:27 GMT
Connection: close
Content-Type: text/plain; charset=UTF-8
Content-Length: 2

yo

Have you seen this before? Thanks for any help!

cors only seems to work with one route

Am I using the API wrong?

This doesn't work:

 val api = cors(){
      get {
        path("page") {
          parameters('from.as[String], 'length.as[Int]) { (from, length) =>
            complete {
              write(table.page(from, length))
            }
          }
        }
      }
      get {
        path("headings") {
          complete {
            write(table.headings)
          }
        }
      }
  }

But this does:

 val api = cors(){
      get {
        path("page") {
          parameters('from.as[String], 'length.as[Int]) { (from, length) =>
            complete {
              write(table.page(from, length))
            }
          }
        }
      }
  }

How do you ensure CORS headers are present for a Bad Request?

Hey there,

I'm using the validate Directive provided by akka-http, I noticed that if the validation check fails, it doesn't add the CORS header to the response causing frontend clients to cry. Is there any way to make this possible?

Here's an example

  val signupMember: Route = path("signup") {
    post {
      entity(as[IncomingMember]) { incomingMember =>
       // validate rejections do not add the CORS headers
        validate(validateMember(incomingMember), memberError) {
          val result = memberManager.createMember(incomingMember.email, incomingMember.password)
          onComplete(result) {
            case Success(res) =>
              if (res) complete(StatusCodes.Created)
              else complete(StatusCodes.Conflict, ErrorMessage("User already exists"))

            case Failure(cause) =>
              println(cause)
              complete(ServiceUnavailable, ErrorMessage("Failed to signup"))
          }
        }
      }
    }

I tried doing this

  val routes: Route =
  cors(CorsSettings.defaultSettings.copy(allowedMethods = GET :: POST :: HEAD :: OPTIONS :: PUT :: DELETE :: Nil)) {
    handleRejections(corsRejectionHandler) { signupMember }

But requests that fail the validation still don't add CORS headers 😢
Any idea on how to approach this?

Put Error

How can I allow my application perform put's

java.lang.RuntimeException: Unhandled rejection: CorsRejection(None,Some(HttpMethod(PUT)),None)

Thanks

When allowed origins are configured, it blocks even same origin requests

Hello!
I'm trying to use your library to apply cors in akka-http.

When I configured with
cors(settings) { route }
and settings includes allowedOrigins, it seems that the requests from the same origin also be blocked with invalidOrigin rejection. Is there a good way to filter that out?

Upgrade to akka >= 2.7, akka-http >= 10.5

Hi, thanks for maintaining this library. Are there any plans to upgrade to the BSL versions of akka-http and akka? Are there any plans specifically to not upgrade? Thanks.

Cache response headers in CorsSettingsImpl

Caching as much as possible headers that are derived solely from the settings should improve performance.

Fixed headers:

  • Access-Control-Expose-Headers
  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Methods
  • Access-Control-Max-Age

Access-Control-Allow-* headers are not present in the response when some Rejection occurs

Hi all!

When some Http request is rejected by any reason by Akka, then the headers related to CORS are removed and, even reading code and documentation, I'm not able to find a solution for that.

val route = cors() {
       path("ping") {
           get {
               complete("pong")
           }
       } ~
       path("pong") {
           get {
               throw new Exception("BOOM!!!")
           }
       }
}

Then, if I call /ping:

> $  curl -v "http://localhost:3000/ping" -H "Origin: http://localhost:8080"
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET /ping HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.64.1
> Accept: */*
> Origin: http://localhost:8080
>
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: http://localhost:8080
< Access-Control-Allow-Credentials: true
< Server: akka-http/10.1.12
< Date: Wed, 16 Sep 2020 07:56:19 GMT
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 4
<
* Connection #0 to host localhost left intact
pong* Closing connection 0

We can see correctly the "Access-*" headers.

But if I call /pong:

> $  curl -v  "http://localhost:3000/pong" -H "Origin: http://localhost:8080"
*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 3000 (#0)
> GET /pong HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.64.1
> Accept: */*
> Origin: http://localhost:8080
>
< HTTP/1.1 500 Internal Server Error
< Server: akka-http/10.1.12
< Date: Wed, 16 Sep 2020 08:00:03 GMT
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 35
<
* Connection #0 to host localhost left intact
There was an internal server error.* Closing connection 0

We can NOT see correctly the "Access-*" headers.

Could you please give me some tips to fix it?

Thanks!

Bounded wildcard support?

This library uses HttpOriginRange from akka-http to perform its matching.

Unfortunately, there is no way to extend HttpOriginRange or HttpOrigin in order to support more sophisticated/alternate matching.

This means that whilst it's possible to match all hosts (HttpOriginRange.*) or a set of fixed hosts (HttpOriginRange.Default(...)), it's not possible for CORS purposes to match for example *.somedomain.com.

I would open this as an issue upstream, but it's unclear to me whether this is a request that's applicable to other uses of their HttpOriginRange or is specific to akka-http-cors's use of it.

So in summary:

  • Would it be possible here to add support for matching on bounded wildcards.
  • Should this issue go upstream to akka-http instead?

Cors headers does not seem to get sent out

I am not sure what I am doing wrong

using akka-http-cors 1.1.2 in a scala web project with

val route: Route =
extractUri { uri =>
handleExceptions(myExceptionHandler) {
handleRejections(myRejectionHandler) {
cors() {
get {
pathPrefix(defaultStaticReactEndpoint) {
extractMatchedPath { matched =>
log.info("From Static {} URI:{}", matched, uri)
getFromDirectory(defaultWebsiteStatic)
}
}
}
}
}
}
}

This runs on a server say test.site1.com and its content is being cross site referenced from another domain site2.com, both are https://

In config I have

allowed-origins = "https://*.site1.com"

site2 just contains some html to do a cross site access

site2.org

This works fine & serves the image from test.site1.com via site2.com

However when I change

allowed-origins = "https://*.BADsite1.com"

despite the site no no longer being whitelisted it still works and serves the image

I also noticed that the headers for the site 2 access have no-cors set despite being flagged as cross site, so it looks like the wrapper is not sending Access-Control-Allow-Origin: https://*.site1.com in the header

Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site

I was under the impression the cors {} wrapper added the required headers to enforce cors

Also when I add
allow-generic-http-requests = no
it now fails for all requests, which I suspect is due to chrome not realising is supposed to send Origin

I checked this by adding
optionalHeaderValueByType(Origin) { origin => }

and for all requests its None

I'd like to use cors to lock down cross site access to named sites, and right now its seems to either allow everything or forbid it

Help would be gratefully appriciated

_____Full headers

Request

Request URL: https://test.site1.com/static/media/landt.56f7a83a.png
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:443
Referrer Policy: strict-origin-when-cross-origin

Response

Accept-Ranges: bytes
Content-Length: 17398
Content-Type: image/png
Date: Tue, 04 Jan 2022 12:49:24 GMT
ETag: "6fc2017dde802faf"
Last-Modified: Tue, 21 Dec 2021 19:38:02 GMT
Server: akka-http/10.2.7

Request
GET /static/media/landt.56f7a83a.png HTTP/1.1
Host: test2.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"
DNT: 1
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
sec-ch-ua-platform: "macOS"
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/,/*;q=0.8
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: https://test2.com
Accept-Encoding: gzip, deflate, br
Accept-Language: en,en-GB;q=0.9

when testing: Loads settings the wrong way

I had great difficulties overriding the settings in a test.

I think this is caused by the default-config is loaded too early:

val defaultSettings = apply(ConfigFactory.load(getClass.getClassLoader))

The above works when configuring in the default application.conf, but not in a different config-file used specifically when starting the actor-system. It also does not work to configure it by parsing config string when starting actorSystem.

If I loaded the config like this AFTER the actorSystem had started:

def corsSettings(actorSystem:ActorSystem):CorsSettings = CorsSettings(actorSystem)

Then it used the config that was "current".

(Sorry for the bad explanation)

Provide java support

Today the plugin only allows be used with java. Actually is easy to implement java support, akka http has a route adapter that allows to convert a scala http directive to a java directive. Akka http default java directives can be used as example to implement it.

CORS headers not being applied

I''m attempting to use akka-http-cors to implement CORS while connecting a React app running on localhost:3000 to an Akka HTTP REST API running on localhost:8080.

I've followed the documentation but it doesn't seem that the 'Access-Control-Allow-Origin' header is being sent.

The response headers I'm getting when making a POST request to the Akka HTTP API are:

HTTP/1.1 400 Bad Request

    Server: akka-http/10.2.7

    Date: Sat, 12 Mar 2022 18:50:21 GMT

    Content-Type: text/plain; charset=UTF-8

    Content-Length: 124

While the request headers are:

POST /api/posts HTTP/1.1

    Host: localhost:8080

    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0

    Accept: application/json, text/plain, */*

    Accept-Language: en-US,en;q=0.5

    Accept-Encoding: gzip, deflate, br

    Content-Type: application/json

    Content-Length: 336

    Origin: http://localhost:3000

    DNT: 1

    Connection: keep-alive

    Referer: http://localhost:3000/

    Sec-Fetch-Dest: empty

    Sec-Fetch-Mode: cors

    Sec-Fetch-Site: same-site

    Sec-GPC: 1

I'm concatenating four routes together (which might be connected to the problem) but I have tried both wrapping individual routes in a cors directive

val routes = cors() {
    pathPrefix("api" / "posts") {
      get {
        path(Segment) { id =>
          val uuid = UUID.fromString(id)
          complete((postActor ? GetPostByID(uuid)).mapTo[Post])
        } ~
          pathEndOrSingleSlash {
            complete((postActor ? GetAllPosts).mapTo[List[Post]])
          }
      } ~
        post {
          entity(as[Post]) { post =>
            complete((postActor ? CreatePost(post)).map(_ => StatusCodes.Created))
          }
        } ~
        put {
          path(Segment) { id =>
            val uuid = UUID.fromString(id)
            entity(as[Post]) { post =>
              complete((postActor ? UpdatePost(uuid, post)).map(_ => StatusCodes.OK))
            }
          }
        } ~
        delete {
          path(Segment) { id =>
            val uuid = UUID.fromString(id)
            complete((postActor ? DeletePost(uuid)).map(_ => StatusCodes.OK))
          }
        }
    }
  }

And wrapping the concatenated routes in a cors directive

val routes = cors() {
    concat(categoryRoutes, userRoutes, topicRoutes, postRoutes)
}

My application.conf looks like this:

akka-http-cors {
  allowed-origins = "http://localhost:3000"
  allowed-methods = ["GET", "POST", "PUT", "DELETE"]
}

The full source code is available in this repo

Very likely, I've gone wrong somewhere and if anyone can suggest where, I'd be very grateful.

JRE 1.8 support broken in 0.3.2

0.3.2 causes an UnsupportedClassVersionError in JRE 1.8:

java.lang.UnsupportedClassVersionError: ch/megard/akka/http/cors/javadsl/model/HttpHeaderRange has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0

0.3.1 is fine.

Default cors Directive should load settings from the actor system

Currently, the cors directive loads settings from the class loader (in a shared object), ignoring the Actor System and its configuration. It works well for the most simple cases, but using a global variable isn't advised, and can make testing harder (#37).

We should provide two entry points:

  • One that loads settings from the current akka-http Actor System
  • One that explicitly takes settings.

Directive should remove all existing CORS headers from the response

When processing an actual CORS request, the cors directive should remove any existing CORS-related header from the HTTP response, before adding the new ones.

The following headers should be cleaned:

  • Access-Control-Allow-Origin
  • Access-Control-Expose-Headers
  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Methods (should only be part of a pre-flight request anyway)
  • Access-Control-Allow-Headers (idem)
  • Access-Control-Max-Age (idem)

Update akka-http 10.2.0 to 10.2.1

Hi,
while compiling my project I got the following warning:
Here are other dependency conflicts that were resolved:

  • com.typesafe.akka:akka-http_2.13:10.2.1 is selected over 10.2.0
    +- default:postgres_service_2.13:0.1.0-SNAPSHOT (depends on 10.2.1)
    +- de.heikoseeberger:akka-http-circe_2.13:1.35.2 (depends on 10.2.1)
    +- ch.megard:akka-http-cors_2.13:1.1.0 (depends on 10.2.0)

Its possible to upgrade your akka-http dependency to 10.2.1?

Thanks in advance.

Problem with 'Access-Control-Allow-Origin'

Hi, i try to use your library and get 'Access-Control-Allow-Origin' error.

Assume, we have a plain version of backend, that just allow us to handle a POST request:

package com.daniel

import scala.concurrent.duration._
import akka.actor._
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpResponse
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server._
import akka.stream.ActorMaterializer
import akka.util.Timeout
import ch.megard.akka.http.cors.CorsDirectives._
import ch.megard.akka.http.cors.CorsSettings

object Main extends App with UserResources{
  implicit val system = ActorSystem("test-service")
  implicit val materializer = ActorMaterializer()

  implicit val executionContext = system.dispatcher
  implicit val timeout = Timeout(10 seconds)

  val api = routes

  Http().bindAndHandle(handler = api, interface = "0.0.0.0", port = 5000) map { binding =>
    println(s"REST interface bound to ${binding.localAddress}")
  }
}

trait UserResources {
  val settings = CorsSettings.defaultSettings.copy(allowCredentials = false)

  val routes: Route = cors(settings) {
    path("cors-issue") {
      post {
          complete(HttpResponse(200))
      }
    }
  }
}

Our build.sbt:

enablePlugins(JavaServerAppPackaging)

name := "cors-issue"
version := "0.1"
organization := "com.daniel"
scalaVersion := "2.11.8"
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8")

libraryDependencies ++= {
  val AkkaVersion       = "2.4.6"
  val AkkaHttpVersion   = "2.4.3"
  Seq(
    "com.typesafe.akka" %% "akka-slf4j"      % AkkaVersion,
    "com.typesafe.akka" %% "akka-http-core" % AkkaVersion,
    "com.typesafe.akka" %% "akka-http-experimental" % AkkaHttpVersion,
    "ch.megard" %% "akka-http-cors" % "0.1.2"
  )
}

Revolver.settings

And if we use cURL command:

$ curl -v -H "Content-Type: application/json" \
> -X POST "http://localhost:5000/cors-issue" \
> -d '{"id": "test"}'

We will get a response:

*   Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> POST /cors-issue HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.45.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 14
>
* upload completely sent off: 14 out of 14 bytes
< HTTP/1.1 200 OK
< Server: akka-http/2.4.6
< Date: Sat, 11 Jun 2016 10:55:05 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact

And that's OK. But if we try POST request using AJAX (with jQuery):

jQuery.ajax({
            type: "POST",
            url: "http://localhost:5000/cors-issue/",
            contentType: "application/json",
            crossDomain: true,
            data: {"name": name},
            dataType: "json",
            success: function(status) {
                console.log("OK: " + status)
            },
            error: function(xhr,status,error) {
                console.log("NOT OK: " + xhr + " " + status + " " + error)
            }
});

We will get an error:

> POST http://localhost:5000/cors-issue/ 
> XMLHttpRequest cannot load http://localhost:5000/cors-issue/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 404.
> NOT OK: [object Object] error 

Where I made a mistake?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.