2

How could I set multiple Access-Control-Allow-Origin headers with Rack compatitable application.

Specification said that I should return [status, headers, body] array as a result. Headers is a hash of headers :). So I can't set same header twice.

headers = {}
headers["Access-Control-Allow-Origin"] = "http://my.domain1.com"
headers["Access-Control-Allow-Origin"] = "http://my.domain2.com"

won't ever work.

What should I do in my case? How can I send two identical headers?

fl00r
  • 79,728
  • 29
  • 207
  • 231

2 Answers2

1

It's very common to use a hash of arrays so try:

headers = {
  "Access-Control-Allow-Origin" => %w[
    http://my.domain1.com
    http://my.domain2.com
  ]
}

I've got a guess that it should be { "Access-Control-Allow-Origin" => [ 'a', 'b' ] * "\n" }

Looking at the RFC, the pertinent part is "5.1 Access-Control-Allow-Origin Response Header" which points to:

The Origin header field has the following syntax:

origin              = "Origin:" OWS origin-list-or-null OWS
origin-list-or-null = %x6E %x75 %x6C %x6C / origin-list
origin-list         = serialized-origin *( SP serialized-origin )
serialized-origin   = scheme "://" host [ ":" port ]
                    ; <scheme>, <host>, <port> from RFC 3986

So, try:

[ 'a', 'b' ] * ";"

Or, for the uninitiated:

%w[a b].join(';')
the Tin Man
  • 150,910
  • 39
  • 198
  • 279
  • I've already tested it before asking :) and no, it didn't help me. I've got a guess that it should be `{ "Access-Control-Allow-Origin" => [ 'a', 'b' ] * "\n" }`, going to test it tomorrow – fl00r Jul 08 '13 at 20:00
  • Check the edit. I looked at the RFC and should have guessed it was ';'. – the Tin Man Jul 08 '13 at 20:55
  • Good morning! I didn't understand where did you find `;` in http://www.w3.org/TR/cors/#access-control-allow-origin-response-header :D – fl00r Jul 09 '13 at 07:50
  • Ho-ho-ho, it is application server dependent. I've tested with rainbows and with thin and it looks like only rainbows support of this kind of headers with `\n` separator. – fl00r Jul 09 '13 at 07:59
  • 1
    It also looks like "Access-Control-Allow-Origin" is not correctly implemented in some browsers. This answer is old, but http://stackoverflow.com/a/1850482/128421 has what looks like a reasonable way to try. – the Tin Man Jul 09 '13 at 08:05
  • Ha, even if you use Rack standard library thin and rackup ignores multiple headers, and unicorn and rainbows works well https://gist.github.com/fl00r/5955566 – fl00r Jul 09 '13 at 08:08
  • IE8+ is well enough for 2013 :D – fl00r Jul 09 '13 at 08:08
  • @fl00r it looks like Thin explicitly checks the headers and only allows duplicates for certains values: https://github.com/macournoyer/thin/blob/v1.5.1/lib/thin/headers.rb#L6 – matt Jul 10 '13 at 00:35
  • @fl00r I think you can also add Puma to the list of servers that work (i.e. return two headers). Webrick converts it into a single header with a comma separated list as the value. – matt Jul 10 '13 at 00:38
0

Based on https://www.w3.org/TR/cors/#access-control-allow-origin-response-header specification, Access-Control-Allow-Origin header might have just one resource.

I've solved that case by custom middleware:

class CORS
  ORIGINS = %w[http://localhost:3001 http://localhost:3002].freeze

  # ...

  def call(env)
    @status, @headers, @response = @app.call(env)
    @headers['Access-Control-Allow-Origin'] = assign_allow_origin_header(env['HTTP_ORIGIN'])
    [@status, @headers, @response]
  end

  private

  def assign_allow_origin_header(origin)
    ORIGINS.include?(origin) ? origin : 'null'
  end
end
Anton Ruban
  • 111
  • 1
  • 3