ericallam / font_assets

Helps with serving font assets with Rails 3.1
137 stars 79 forks source link

Insert more than one domain #6

Open HoneyryderChuck opened 12 years ago

HoneyryderChuck commented 12 years ago

Hi man,

Great gem you got there. I'm just missing something: What if I want to had more than one domain? Thing is, the way the Access-Control-Allow-Origin header field should work, the field has to be repeated in the header:

Access-Control-Allow-Origin: http://example.com Access-Control-Allow-Origin. https://example.com

At least that's what I read, comma separation doesn't work in this case.

Regards, Tiago

HoneyryderChuck commented 12 years ago

Actually, after reading a bit more, the right solution would be defining a list of allowed domains, and then check the ORIGIN header field for the font resource request. If it belongs to the list of allowed domains, then fill the Access-Control-Allow-Origin field with the respective domain and ship the response.

HoneyryderChuck commented 12 years ago

I got a temporary work around working. Basically I rewrote some of the logic of the middleware in an intializer:


module FontAssets
  class Middleware

    def call(env)
      origin = env["HTTP_ORIGIN"]
      # intercept the "preflight" request
      if env["REQUEST_METHOD"] == "OPTIONS"
        return [200, access_control_headers(origin), []]
      else
        code, headers, body = @app.call(env)
        set_headers! headers, body, env["PATH_INFO"], origin
        [code, headers, body]
      end
    end

    def access_control_headers(origin)
      return {} unless allowed_origin?(origin)
      {
        "Access-Control-Allow-Origin" => origin,
        "Access-Control-Allow-Methods" => "GET",
        "Access-Control-Allow-Headers" => "x-requested-with",
        "Access-Control-Max-Age" => "3628800"
      }
    end

    private

    def set_headers!(headers, body, path, origin)
      if ext = extension(path) and font_asset?(ext) and allowed_origin?(origin)
        headers.merge!(access_control_headers(origin))
        headers.merge!('Content-Type' => mime_type(ext)) if headers['Content-Type']
      end
    end

    def allowed_origin?(origin)
      @origin.include?(origin)
    end

  end

end

It is not optimal, but it does the trick now. But instead of assigning a domain in application.rb, I have to assign an array of domains. I've noticed that the set_headers! function takes the body parameter needlessly. I'll try to work on this a bit more, but tell me what you think meanwhile.

reconbot commented 10 years ago

This is the right approach but has one issue with cloundfront as they don't support the vary header and will cache whatever domain's "Access-Control-Allow-Origin" header gets served first. (The vary header tells caches use headers and not just urls in their cache keys.)