font_assets 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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