Search code examples
scalasprayspray-client

Illegal response header Scala Spray pipelining


I'm getting the follow error when I am trying to pipeline a request from Scala spray

[play-akka.actor.default-dispatcher-14] INFO application - Pipelining chain request
[WARN] [03/19/2015 11:08:49.115] [application-akka.actor.default-dispatcher-2] [akka://application/user/IO-HTTP/group-0/0] Illegal response header: Illegal 'Access-Control-Allow-Origin' header: Unexpected end of input, expected $timesAccess$minusControl$minusAllow$minusOrigin (line 1, pos 1):

^

and here is where I am building the request:

val pipeline =
  addCredentials(BasicHttpCredentials("API_KEY",
    "API_SECRET")) ~>  sendReceive

val response: Future[HttpResponse] = pipeline(Post(api,notification))
Logger.info("Pipelining chain request")
response

I don't really know much about Access Control Allow Origin. Do I need to add some sort of header to this request to get it to work?


Solution

  • The error itself means Access-Control-Allow-Origin header wasn't parsed correctly (see grammar). This header is pretty new and allows Cross Origin Resource Sharing. Examples of normal Access-Control-Allow-Origin(from here):

    "Access-Control-Allow-Origin" in {
      "Access-Control-Allow-Origin: *" =!= `Access-Control-Allow-Origin`(AllOrigins)
      "Access-Control-Allow-Origin: null" =!= `Access-Control-Allow-Origin`(SomeOrigins(Nil))
      "Access-Control-Allow-Origin: http://spray.io" =!= `Access-Control-Allow-Origin`(SomeOrigins(Seq("http://spray.io")))
    }
    

    I can guess that you may use some old version of spray, which doesn't support multiple origins or maybe it's related to this. Anyway, server returns a response with this header only if Origin header is specified in request (which means CORS initiation), so the problem should be solved by removing Origin header from it.

    UPDATE: This is a bug of chain.com API, you use. If Origin header is not specified, they return Access-Control-Allow-Origin: (empty string) to you, so it's not parsable:

    > curl -v https://api.chain.com/v2/notifications -X POST
    > POST /v2/notifications HTTP/1.1
    > User-Agent: curl/7.41.0
    > Host: api.chain.com
    > Accept: */*
    >
    < HTTP/1.1 401 Unauthorized
    < Access-Control-Allow-Credentials: true
    < Access-Control-Allow-Methods: GET,POST,PATCH,PUT,DELETE,OPTIONS,HEAD
    < Access-Control-Allow-Origin:
    < Content-Type: text/plain; charset=utf-8
    < Date: Sun, 22 Mar 2015 01:38:07 GMT
    < Strict-Transport-Security: max-age=25920000; includeSubDomains
    < Vary: Accept-Encoding
    < Www-Authenticate: Basic realm="chain-api"
    < X-Content-Type-Options: nosniff
    < X-Frame-Options: DENY
    < X-Xss-Protection: 1
    < Content-Length: 47
    < Connection: keep-alive
    <
    {"code":"CH004","message":"Must authenticate"}
    

    You have to specify some Origin as workaround:

    >curl -v https://api.chain.com/v2/notifications -X POST -H "Origin: http://google.com"
    > POST /v2/notifications HTTP/1.1
    > User-Agent: curl/7.41.0
    > Host: api.chain.com
    > Accept: */*
    > Origin: http://google.com
    
    < HTTP/1.1 401 Unauthorized
    < Access-Control-Allow-Credentials: true
    < Access-Control-Allow-Methods: GET,POST,PATCH,PUT,DELETE,OPTIONS,HEAD
    < Access-Control-Allow-Origin: http://google.com
    < Content-Type: text/plain; charset=utf-8
    < Date: Sun, 22 Mar 2015 01:39:10 GMT
    < Strict-Transport-Security: max-age=25920000; includeSubDomains
    < Vary: Accept-Encoding
    < Www-Authenticate: Basic realm="chain-api"
    < X-Content-Type-Options: nosniff
    < X-Frame-Options: DENY
    < X-Xss-Protection: 1
    < Content-Length: 47
    < Connection: keep-alive