font_assets 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,29 @@
1
+ ### master
2
+
3
+ ### 0.1.0 / 2012-01-18
4
+
5
+ [full changelog](https://github.com/rubymaverick/font_assets/compare/v0.0.2...v0.1.0)
6
+
7
+ Enhancements
8
+
9
+ * Refactor MIME type settings into a local object.
10
+ * Add RSpec specs on the middleware and mime type handler.
11
+ * Update the README with more detail and examples.
12
+ * Fixed a typo in "ttf" in the middleware.
13
+ * Removed duplicate Railtie definition.
14
+
15
+ Bug Fixes
16
+
17
+ * Fix MIME types not being properly set in recent versions of Rack (starting in [Rack 1.3.0](https://github.com/rack/rack/commit/469518f7d971ba99fc335cf546d605d2364c81aa))
18
+
19
+ ### 0.0.2 / 2011-12-15
20
+
21
+ [full changelog](https://github.com/rubymaverick/font_assets/compare/v0.0.1...v0.0.2)
22
+
23
+ Enhancements
24
+
25
+ * Make MIME setting more future-compatible by optionally setting it.
26
+
27
+ ### 0.0.1 / 2011-12-15
28
+
29
+ Initial release.
data/README.md CHANGED
@@ -1,32 +1,101 @@
1
1
  Font Assets
2
2
  =============
3
3
 
4
- This little gem helps serve font-face assets in Rails 3.1. It really does these two things:
4
+ This little gem helps serve font-face assets in Rails 3.1. It really does these
5
+ two things:
5
6
 
6
- * Registers font Mime Types for woff, eot, tff, and svg font files
7
- * Sets Access-Control-Allow-Origin response headers for font assets, which Firefox requires for cross domain fonts
7
+ * Responds with "proper" mime types for woff, eot, tff, and svg font files, and
8
+ * Sets Access-Control-Allow-Origin response headers for font assets, which Firefox requires for cross domain fonts.
9
+
10
+ In addition, it will also respond to the pre-flight OPTIONS requests made by
11
+ supporting browsers (Firefox).
8
12
 
9
13
  Install
10
14
  -------
11
15
 
12
16
  Add `font_assets` to your Gemfile:
13
17
 
14
- gem 'font_assets'
18
+ ```ruby
19
+ gem 'font_assets'
20
+ ```
15
21
 
16
22
 
17
23
  Usage
18
24
  -----
19
25
 
20
- Set the origin domain that will get set in the `Access-Control-Allow-Origin` header
26
+ By default, in a Rails application, this gem should Just Work™. However, the
27
+ default settings allow any requesting site to use the linked fonts, due to the
28
+ Allowed Origin being '*', by default. This is only useful for browsers which
29
+ support this feature (Firefox), but restricting it to certain domains may be
30
+ beneficial.
31
+
32
+ Set the origin domain that will get set in the `Access-Control-Allow-Origin`
33
+ header:
34
+
35
+ ```ruby
36
+ # in config/environments/production.rb
37
+ config.font_assets.origin = 'http://codeschool.com'
38
+ ```
39
+
40
+ The origin domain must match the domain of the site serving the page that is
41
+ requesting the font, not the host of the font. For example, if you are using a
42
+ CDN to serve your assets (like CloudFront), and the full path to the font asset
43
+ is `http://d3rd6rvl24noqd.cloudfront.net/assets/fonts/Pacifico-webfont-734f1436e605566ae2f1c132905e28b2.woff`,
44
+ but the URI the user is visiting is `http://coffeescript.codeschool.com/level/1`,
45
+ you'd want to set the origin header to this:
46
+
47
+ ```ruby
48
+ config.font_assets.origin = 'http://coffeescript.codeschool.com'
49
+ ```
50
+
51
+ An Example Response
52
+ -------------------
21
53
 
22
- # in config/environments/production.rb
54
+ Below is an example response for a .woff font asset on a Rails 3.1 application
55
+ running behind several proxies and caches (including CloudFront):
23
56
 
24
- config.font_assets.origin = 'http://codeschool.com'
57
+ ```
58
+ $ curl -i http://d1tijy5l7mg5kk.cloudfront.net/assets/ubuntu/Ubuntu-Bold-webfont-4bcb5239bfd34be67bc07901959fc6e1.woff
59
+ HTTP/1.0 200 OK
60
+ Server: nginx
61
+ Date: Sat, 14 Jan 2012 19:45:19 GMT
62
+ Content-Type: application/x-font-woff
63
+ Last-Modified: Sat, 14 Jan 2012 16:58:14 GMT
64
+ Cache-Control: public, max-age=31557600
65
+ Access-Control-Allow-Origin: http://www.codeschool.com
66
+ Access-Control-Allow-Methods: GET
67
+ Access-Control-Allow-Headers: x-requested-with
68
+ Access-Control-Max-Age: 3628800
69
+ X-Content-Digest: 66049433125f563329c4178848643536f76459e5
70
+ X-Rack-Cache: fresh
71
+ Content-Length: 17440
72
+ X-Varnish: 311344447
73
+ Age: 289983
74
+ X-Cache: Hit from cloudfront
75
+ X-Amz-Cf-Id: 9yzifs_hIQF_MxPLwSR8zck3eZVXJ8LFKpMUpXnu2SmMuEmyrUbHdQ==,Lbh9kfjr0YRm77seSmOSQ6oFkUEMabvtFStJLhTOy9BfGrIXVneoKQ==
76
+ Via: 1.1 varnish, 1.0 2815dd16e8c2a0074b81a6148bd8aa3a.cloudfront.net:11180 (CloudFront), 1.0 f9e7403ca14431787835521769ace98a.cloudfront.net:11180 (CloudFront)
77
+ Connection: close
78
+ ```
25
79
 
26
- The origin domain must match the domain of the site serving the page that is requesting the font, not the host of the font. For example, if you are using a CDN to serve your assets (like CloudFront), and the full path to the font asset is `http://d3rd6rvl24noqd.cloudfront.net/assets/fonts/Pacifico-webfont-734f1436e605566ae2f1c132905e28b2.woff`, but the URI the user is visiting if `http://coffeescript.codeschool.com/level/1`, you'd want to set the origin head to this:
80
+ In it, you can see where this middleware has injected the `Content-Type` and
81
+ `Access-Control-*` headers into the response.
27
82
 
28
- config.font_assets.origin = 'http://coffeescript.codeschool.com'
83
+ And below is an example OPTIONS request response:
29
84
 
85
+ ```
86
+ $ curl -i -X OPTIONS http://www.codeschool.com/
87
+ HTTP/1.1 200 OK
88
+ Server: nginx
89
+ Date: Wed, 18 Jan 2012 04:13:25 GMT
90
+ Connection: keep-alive
91
+ Access-Control-Allow-Origin: http://www.codeschool.com
92
+ Access-Control-Allow-Methods: GET
93
+ Access-Control-Allow-Headers: x-requested-with
94
+ Access-Control-Max-Age: 3628800
95
+ Vary: Accept-Encoding
96
+ X-Rack-Cache: invalidate, pass
97
+ Content-Length: 0
98
+ ```
30
99
 
31
100
  License
32
101
  -------
@@ -18,7 +18,6 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
23
- # s.add_runtime_dependency "rest-client"
21
+ s.add_dependency "rack"
22
+ s.add_development_dependency "rspec"
24
23
  end
@@ -2,6 +2,4 @@ require "font_assets/version"
2
2
  require "font_assets/railtie" if defined?(Rails)
3
3
 
4
4
  module FontAssets
5
- class Railtie < Rails::Railtie
6
- end
7
5
  end
@@ -1,9 +1,13 @@
1
+ require 'rack'
2
+ require 'font_assets/mime_types'
3
+
1
4
  module FontAssets
2
5
  class Middleware
3
6
 
4
7
  def initialize(app, origin)
5
8
  @app = app
6
9
  @origin = origin
10
+ @mime_types = FontAssets::MimeTypes.new(Rack::Mime::MIME_TYPES)
7
11
  end
8
12
 
9
13
  def access_control_headers
@@ -21,21 +25,32 @@ module FontAssets
21
25
  return [200, access_control_headers, []]
22
26
  else
23
27
  code, headers, body = @app.call(env)
24
- headers.merge!(access_control_headers) if font_asset?(env["PATH_INFO"])
28
+ set_headers! headers, body, env["PATH_INFO"]
25
29
  [code, headers, body]
26
30
  end
27
31
  end
28
32
 
33
+
29
34
  private
30
35
 
36
+
31
37
  def extension(path)
32
- path.split("?").first.split(".").last
38
+ "." + path.split("?").first.split(".").last
33
39
  end
34
40
 
35
41
  def font_asset?(path)
36
- %w(woff eot tff svg).include? extension(path)
42
+ @mime_types.font? extension(path)
37
43
  end
38
44
 
45
+ def set_headers!(headers, body, path)
46
+ if ext = extension(path) and font_asset?(ext)
47
+ headers.merge!(access_control_headers)
48
+ headers.merge!('Content-Type' => mime_type(ext)) unless body.empty?
49
+ end
50
+ end
51
+
52
+ def mime_type(extension)
53
+ @mime_types[extension]
54
+ end
39
55
  end
40
-
41
56
  end
@@ -0,0 +1,38 @@
1
+ module FontAssets
2
+ class MimeTypes
3
+ DEFAULT_TYPE = 'application/octet-stream'
4
+ MIME_TYPES = {
5
+ '.eot' => 'application/vnd.ms-fontobject',
6
+ '.svg' => 'image/svg+xml',
7
+ '.ttf' => 'application/x-font-ttf',
8
+ '.woff' => 'application/x-font-woff'
9
+ }
10
+
11
+ def initialize(types, default = DEFAULT_TYPE.dup)
12
+ @types = types.dup
13
+ @default = default
14
+
15
+ MIME_TYPES.each_pair do |extension, type|
16
+ set extension, type
17
+ end
18
+ end
19
+
20
+ def [](extension)
21
+ @types.fetch(extension, DEFAULT_TYPE.dup).dup
22
+ end
23
+
24
+ def font?(extension)
25
+ MIME_TYPES.keys.include? extension
26
+ end
27
+
28
+ def set(extension, mime_type)
29
+ if @types[extension].nil? || @types[extension] == @default
30
+ set!(extension, mime_type)
31
+ end
32
+ end
33
+
34
+ def set!(extension, mime_type)
35
+ @types[extension] = mime_type
36
+ end
37
+ end
38
+ end
@@ -9,12 +9,5 @@ module FontAssets
9
9
 
10
10
  app.middleware.insert_before 'ActionDispatch::Static', FontAssets::Middleware, config.font_assets.origin
11
11
  end
12
-
13
- config.after_initialize do
14
- Rack::Mime::MIME_TYPES['.woff'] ||= 'application/x-font-woff'
15
- Rack::Mime::MIME_TYPES['.ttf'] ||= 'application/x-font-ttf'
16
- Rack::Mime::MIME_TYPES['.eot'] ||= 'application/vnd.ms-fontobject'
17
- Rack::Mime::MIME_TYPES['.svg'] ||= 'image/svg+xml'
18
- end
19
12
  end
20
13
  end
@@ -1,3 +1,3 @@
1
1
  module FontAssets
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+ require 'font_assets/middleware'
3
+
4
+ describe FontAssets::Middleware do
5
+ it 'passes all Rack::Lint checks' do
6
+ app = Rack::Lint.new(FontAssets::Middleware.new(inner_app, 'http://test.local'))
7
+ request app, '/'
8
+ end
9
+
10
+ context 'for GET requests' do
11
+ context 'to font assets' do
12
+ let(:app) { load_app 'http://test.origin' }
13
+ let(:call) { request app, '/test.ttf' }
14
+
15
+ context 'the response headers' do
16
+ subject { call[1] }
17
+
18
+ its(["Access-Control-Allow-Headers"]) { should == "x-requested-with" }
19
+ its(["Access-Control-Max-Age"]) { should == "3628800" }
20
+ its(['Access-Control-Allow-Methods']) { should == 'GET' }
21
+ its(['Access-Control-Allow-Origin']) { should == 'http://test.origin' }
22
+ its(['Content-Type']) { should == 'application/x-font-ttf' }
23
+ end
24
+ end
25
+
26
+ context 'to non-font assets' do
27
+ let(:app) { load_app }
28
+ let(:call) { request app, '/' }
29
+
30
+ context 'the response headers' do
31
+ subject { call[1] }
32
+
33
+ its(["Access-Control-Allow-Headers"]) { should be_nil }
34
+ its(["Access-Control-Max-Age"]) { should be_nil }
35
+ its(['Access-Control-Allow-Methods']) { should be_nil }
36
+ its(['Access-Control-Allow-Origin']) { should be_nil }
37
+ its(['Content-Type']) { should == 'text/plain' }
38
+ end
39
+ end
40
+ end
41
+
42
+ context 'for OPTIONS requests' do
43
+ let(:app) { load_app 'http://test.options' }
44
+ let(:call) { request app, '/test.ttf', :method => 'OPTIONS' }
45
+
46
+ context 'the response headers' do
47
+ subject { call[1] }
48
+
49
+ its(["Access-Control-Allow-Headers"]) { should == "x-requested-with" }
50
+ its(["Access-Control-Max-Age"]) { should == "3628800" }
51
+ its(['Access-Control-Allow-Methods']) { should == 'GET' }
52
+ its(['Access-Control-Allow-Origin']) { should == 'http://test.options' }
53
+
54
+ it 'should not contain a Content-Type' do
55
+ subject['Content-Type'].should be_nil
56
+ end
57
+ end
58
+
59
+ context 'the response body' do
60
+ subject { call[2] }
61
+ it { should be_empty }
62
+ end
63
+ end
64
+
65
+
66
+ private
67
+
68
+
69
+ def load_app(origin = 'http://test.local')
70
+ FontAssets::Middleware.new(inner_app, origin)
71
+ end
72
+
73
+ def inner_app
74
+ lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'Success'] }
75
+ end
76
+
77
+ def request(app, path, options = {})
78
+ app.call Rack::MockRequest.env_for(path, options)
79
+ end
80
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+ require 'font_assets/mime_types'
3
+
4
+ describe FontAssets::MimeTypes do
5
+ context 'given an empty hash' do
6
+ let(:hash) { Hash.new }
7
+ subject { described_class.new(hash) }
8
+
9
+ it 'adds the known mime types' do
10
+ FontAssets::MimeTypes::MIME_TYPES.each_pair do |ext, type|
11
+ subject[ext].should == type
12
+ end
13
+ end
14
+ end
15
+
16
+ context 'given a populated hash' do
17
+ let(:default_type) { 'default/type' }
18
+ let(:hash) { { '.ttf' => default_type, '.svg' => 'test/type' } }
19
+ subject { described_class.new(hash, default_type) }
20
+
21
+ it 'retains the non-default-matching mime types' do
22
+ subject['.svg'].should == hash['.svg']
23
+ end
24
+
25
+ it 'overrides the default-matching mime types' do
26
+ subject['.ttf'].should_not == hash['.ttf']
27
+ end
28
+ end
29
+
30
+ context '#[]' do
31
+ let(:types) { described_class.new({}) }
32
+
33
+ it 'returns the mime type of the passed extension' do
34
+ types['.woff'].should == 'application/x-font-woff'
35
+ end
36
+
37
+ it 'returns the default mime type for unknown extensions' do
38
+ types['.bad'].should == 'application/octet-stream'
39
+ end
40
+ end
41
+
42
+ context '#font?' do
43
+ let(:types) { described_class.new({}) }
44
+
45
+ it 'is true for known font extensions' do
46
+ FontAssets::MimeTypes::MIME_TYPES.keys.each do |key|
47
+ types.font?(key).should be_true
48
+ end
49
+ end
50
+
51
+ it 'is false for unrecognized font extensions' do
52
+ types.font?('.bad').should be_false
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,5 @@
1
+ RSpec.configure do |config|
2
+ config.treat_symbols_as_metadata_keys_with_true_values = true
3
+ config.run_all_when_everything_filtered = true
4
+ config.filter_run :focus
5
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: font_assets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,30 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-15 00:00:00.000000000Z
13
- dependencies: []
12
+ date: 2012-01-18 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rack
16
+ requirement: &70274473944840 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70274473944840
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70274473944080 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70274473944080
14
36
  description: Improve font serving in Rails 3.1
15
37
  email:
16
38
  - rubymaverick@gmail.com
@@ -19,14 +41,20 @@ extensions: []
19
41
  extra_rdoc_files: []
20
42
  files:
21
43
  - .gitignore
44
+ - .rspec
45
+ - CHANGELOG.md
22
46
  - Gemfile
23
47
  - README.md
24
48
  - Rakefile
25
49
  - font_assets.gemspec
26
50
  - lib/font_assets.rb
27
51
  - lib/font_assets/middleware.rb
52
+ - lib/font_assets/mime_types.rb
28
53
  - lib/font_assets/railtie.rb
29
54
  - lib/font_assets/version.rb
55
+ - spec/middleware_spec.rb
56
+ - spec/mime_types_spec.rb
57
+ - spec/spec_helper.rb
30
58
  homepage: https://github.com/rubymaverick/font_assets
31
59
  licenses: []
32
60
  post_install_message:
@@ -51,4 +79,7 @@ rubygems_version: 1.8.10
51
79
  signing_key:
52
80
  specification_version: 3
53
81
  summary: Improve font serving in Rails 3.1
54
- test_files: []
82
+ test_files:
83
+ - spec/middleware_spec.rb
84
+ - spec/mime_types_spec.rb
85
+ - spec/spec_helper.rb