sprockets 3.0.0.beta.1 → 3.0.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sprockets might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/lib/sprockets.rb +3 -2
- data/lib/sprockets/asset.rb +20 -4
- data/lib/sprockets/base.rb +16 -16
- data/lib/sprockets/cache.rb +3 -3
- data/lib/sprockets/cached_environment.rb +14 -14
- data/lib/sprockets/configuration.rb +4 -4
- data/lib/sprockets/digest_utils.rb +144 -0
- data/lib/sprockets/manifest.rb +2 -1
- data/lib/sprockets/path_utils.rb +35 -0
- data/lib/sprockets/processing.rb +2 -2
- data/lib/sprockets/server.rb +10 -10
- data/lib/sprockets/utils.rb +0 -49
- data/lib/sprockets/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dcb1bab6dcd806bd08e5f467aa057cd75004be8
|
4
|
+
data.tar.gz: 86037ea057923f8b2afd7dbffdea6d72f3596d02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce12f8ec442a3d4a3cef5352f12a6c83151ff4dd717ce0fb94d31811ca9f3c80953a3f52e3f582eb5ecb42d0af05d2e5320fe925c3c55e4b8b61fd6280ff4ef8
|
7
|
+
data.tar.gz: fbe0b9468d6e81a596517d4b4ecda0faf34ef84027ac7340ea2b603bc7635585ed2f93fa7e215e9c1062df1990c46222aefefd97caa4ba54a2dfcafa68c21811
|
data/README.md
CHANGED
@@ -394,6 +394,10 @@ submit a pull request.
|
|
394
394
|
idea](https://issues.apache.org/bugzilla/show_bug.cgi?id=39727)
|
395
395
|
* Added linked or referenced assets. When an asset is compiled, any of its links
|
396
396
|
will be compiled as well.
|
397
|
+
* Add Asset integrity attribute for Subresource Integrity
|
398
|
+
* Default digest changed to SHA256. Configuring digest_class is deprecated.
|
399
|
+
* Rename Asset#digest to Asset#hexdigest. Asset#digest is deprecated and will
|
400
|
+
return a raw byte String in 4.x.
|
397
401
|
|
398
402
|
**2.12.2** (September 5, 2014)
|
399
403
|
|
data/lib/sprockets.rb
CHANGED
@@ -29,6 +29,7 @@ module Sprockets
|
|
29
29
|
autoload :AssetURI, 'sprockets/asset_uri'
|
30
30
|
autoload :Cache, 'sprockets/cache'
|
31
31
|
autoload :ContentTypeMismatch, 'sprockets/errors'
|
32
|
+
autoload :DigestUtils, 'sprockets/digest_utils'
|
32
33
|
autoload :EncodingUtils, 'sprockets/encoding_utils'
|
33
34
|
autoload :Error, 'sprockets/errors'
|
34
35
|
autoload :FileNotFound, 'sprockets/errors'
|
@@ -58,8 +59,8 @@ module Sprockets
|
|
58
59
|
@version = ''
|
59
60
|
|
60
61
|
# Set the default digest
|
61
|
-
require 'digest/
|
62
|
-
@digest_class = Digest::
|
62
|
+
require 'digest/sha2'
|
63
|
+
@digest_class = Digest::SHA256
|
63
64
|
|
64
65
|
require 'logger'
|
65
66
|
@logger = Logger.new($stderr)
|
data/lib/sprockets/asset.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'base64'
|
1
2
|
require 'fileutils'
|
2
3
|
require 'pathname'
|
3
4
|
|
@@ -49,7 +50,7 @@ module Sprockets
|
|
49
50
|
|
50
51
|
# Internal: Unique asset object ID.
|
51
52
|
#
|
52
|
-
# Returns
|
53
|
+
# Returns a String.
|
53
54
|
attr_reader :id
|
54
55
|
|
55
56
|
# Public: Internal URI to lookup asset by.
|
@@ -65,7 +66,7 @@ module Sprockets
|
|
65
66
|
#
|
66
67
|
# Returns String.
|
67
68
|
def digest_path
|
68
|
-
logical_path.sub(/\.(\w+)$/) { |ext| "-#{
|
69
|
+
logical_path.sub(/\.(\w+)$/) { |ext| "-#{etag}#{ext}" }
|
69
70
|
end
|
70
71
|
|
71
72
|
# Public: Returns String MIME type of asset. Returns nil if type is unknown.
|
@@ -165,10 +166,25 @@ module Sprockets
|
|
165
166
|
end
|
166
167
|
|
167
168
|
# Public: Returns String hexdigest of source.
|
168
|
-
|
169
|
+
def hexdigest
|
170
|
+
DigestUtils.pack_hexdigest(@digest)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Deprecated: Returns String hexdigest of source.
|
174
|
+
#
|
175
|
+
# In 4.x this will be changed to return a raw Digest byte String.
|
176
|
+
alias_method :digest, :hexdigest
|
169
177
|
|
170
178
|
# Pubic: ETag String of Asset.
|
171
|
-
alias_method :etag, :
|
179
|
+
alias_method :etag, :hexdigest
|
180
|
+
|
181
|
+
# Public: Returns String base64 digest of source.
|
182
|
+
def base64digest
|
183
|
+
DigestUtils.pack_base64digest(@digest)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Public: A "named information" URL for subresource integrity.
|
187
|
+
attr_reader :integrity
|
172
188
|
|
173
189
|
# Public: Add enumerator to allow `Asset` instances to be used as Rack
|
174
190
|
# compatible body objects.
|
data/lib/sprockets/base.rb
CHANGED
@@ -8,7 +8,7 @@ require 'sprockets/server'
|
|
8
8
|
module Sprockets
|
9
9
|
# `Base` class for `Environment` and `Cached`.
|
10
10
|
class Base
|
11
|
-
include PathUtils, HTTPUtils
|
11
|
+
include PathUtils, HTTPUtils, DigestUtils
|
12
12
|
include Configuration
|
13
13
|
include Server
|
14
14
|
include Resolve
|
@@ -33,39 +33,37 @@ module Sprockets
|
|
33
33
|
end
|
34
34
|
alias_method :index, :cached
|
35
35
|
|
36
|
-
# Internal: Compute
|
36
|
+
# Internal: Compute digest for path.
|
37
37
|
#
|
38
38
|
# path - String filename or directory path.
|
39
39
|
#
|
40
|
-
# Returns a String
|
41
|
-
def
|
40
|
+
# Returns a String digest or nil.
|
41
|
+
def file_digest(path)
|
42
42
|
if stat = self.stat(path)
|
43
43
|
# Caveat: Digests are cached by the path's current mtime. Its possible
|
44
44
|
# for a files contents to have changed and its mtime to have been
|
45
45
|
# negligently reset thus appearing as if the file hasn't changed on
|
46
46
|
# disk. Also, the mtime is only read to the nearest second. Its
|
47
47
|
# also possible the file was updated more than once in a given second.
|
48
|
-
cache.fetch(['
|
48
|
+
cache.fetch(['file_digest', path, stat.mtime.to_i]) do
|
49
49
|
if stat.directory?
|
50
50
|
# If its a directive, digest the list of filenames
|
51
|
-
|
51
|
+
digest_class.digest(self.entries(path).join(','))
|
52
52
|
elsif stat.file?
|
53
53
|
# If its a file, digest the contents
|
54
|
-
|
54
|
+
digest_class.file(path.to_s).digest
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
# Internal: Compute
|
60
|
+
# Internal: Compute digest for a set of paths.
|
61
61
|
#
|
62
62
|
# paths - Array of filename or directory paths.
|
63
63
|
#
|
64
|
-
# Returns a String
|
65
|
-
def
|
66
|
-
digest
|
67
|
-
paths.each { |path| digest.update(file_hexdigest(path).to_s) }
|
68
|
-
digest.hexdigest
|
64
|
+
# Returns a String digest.
|
65
|
+
def files_digest(paths)
|
66
|
+
digest(paths.map { |path| file_digest(path) })
|
69
67
|
end
|
70
68
|
|
71
69
|
# Find asset by logical path or expanded path.
|
@@ -191,16 +189,18 @@ module Sprockets
|
|
191
189
|
asset.merge!({
|
192
190
|
encoding: Encoding::BINARY,
|
193
191
|
length: self.stat(asset[:filename]).size,
|
194
|
-
digest:
|
192
|
+
digest: file_digest(asset[:filename]),
|
195
193
|
metadata: {}
|
196
194
|
})
|
197
195
|
end
|
198
196
|
|
199
197
|
metadata = asset[:metadata]
|
200
198
|
metadata[:dependency_paths] = Set.new(metadata[:dependency_paths]).merge([asset[:filename]])
|
201
|
-
metadata[:
|
199
|
+
metadata[:dependency_sources_digest] = files_digest(metadata[:dependency_paths])
|
202
200
|
|
203
|
-
asset[:
|
201
|
+
asset[:integrity] = integrity_uri(asset[:digest], asset[:content_type])
|
202
|
+
|
203
|
+
asset[:id] = pack_hexdigest(digest(asset))
|
204
204
|
asset[:uri] = AssetURI.build(filename, params.merge(id: asset[:id]))
|
205
205
|
|
206
206
|
# TODO: Avoid tracking Asset mtime
|
data/lib/sprockets/cache.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'sprockets/
|
1
|
+
require 'sprockets/digest_utils'
|
2
2
|
require 'logger'
|
3
3
|
|
4
4
|
module Sprockets
|
@@ -142,7 +142,7 @@ module Sprockets
|
|
142
142
|
#
|
143
143
|
# Returns a String with a length less than 250 characters.
|
144
144
|
def expand_key(key)
|
145
|
-
"sprockets/v#{VERSION}/#{
|
145
|
+
"sprockets/v#{VERSION}/#{DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key))}"
|
146
146
|
end
|
147
147
|
|
148
148
|
PEEK_SIZE = 100
|
@@ -158,7 +158,7 @@ module Sprockets
|
|
158
158
|
key.each { |k| str << peek_key(k) }
|
159
159
|
str.join(':')[0, PEEK_SIZE]
|
160
160
|
else
|
161
|
-
peek_key(
|
161
|
+
peek_key(DigestUtils.pack_urlsafe_base64digest(DigestUtils.digest(key)))
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
@@ -14,10 +14,10 @@ module Sprockets
|
|
14
14
|
def initialize(environment)
|
15
15
|
initialize_configuration(environment)
|
16
16
|
|
17
|
-
@cache
|
18
|
-
@stats
|
19
|
-
@entries
|
20
|
-
@
|
17
|
+
@cache = environment.cache
|
18
|
+
@stats = Hash.new { |h, k| h[k] = _stat(k) }
|
19
|
+
@entries = Hash.new { |h, k| h[k] = _entries(k) }
|
20
|
+
@digests = Hash.new { |h, k| h[k] = _file_digest(k) }
|
21
21
|
end
|
22
22
|
|
23
23
|
# No-op return self as cached environment.
|
@@ -38,10 +38,10 @@ module Sprockets
|
|
38
38
|
@stats[path]
|
39
39
|
end
|
40
40
|
|
41
|
-
# Internal: Cache Environment#
|
42
|
-
alias_method :
|
43
|
-
def
|
44
|
-
@
|
41
|
+
# Internal: Cache Environment#file_digest
|
42
|
+
alias_method :_file_digest, :file_digest
|
43
|
+
def file_digest(path)
|
44
|
+
@digests[path]
|
45
45
|
end
|
46
46
|
|
47
47
|
protected
|
@@ -53,7 +53,7 @@ module Sprockets
|
|
53
53
|
self.version,
|
54
54
|
self.paths,
|
55
55
|
uri,
|
56
|
-
|
56
|
+
file_digest(filename)
|
57
57
|
]
|
58
58
|
end
|
59
59
|
|
@@ -75,9 +75,9 @@ module Sprockets
|
|
75
75
|
def build_asset_by_uri(uri)
|
76
76
|
dep_graph_key = asset_dependency_graph_cache_key(uri)
|
77
77
|
|
78
|
-
dependency_paths,
|
79
|
-
if dependency_paths &&
|
80
|
-
if
|
78
|
+
dependency_paths, dependency_sources_digest, digest_uri = cache._get(dep_graph_key)
|
79
|
+
if dependency_paths && dependency_sources_digest && digest_uri
|
80
|
+
if files_digest(dependency_paths) == dependency_sources_digest
|
81
81
|
if asset = cache._get(asset_digest_uri_cache_key(digest_uri))
|
82
82
|
return asset
|
83
83
|
end
|
@@ -86,8 +86,8 @@ module Sprockets
|
|
86
86
|
|
87
87
|
asset = super
|
88
88
|
|
89
|
-
|
90
|
-
cache._set(dep_graph_key, [dependency_paths,
|
89
|
+
dependency_sources_digest, dependency_paths = asset[:metadata].values_at(:dependency_sources_digest, :dependency_paths)
|
90
|
+
cache._set(dep_graph_key, [dependency_paths, dependency_sources_digest, asset[:uri]])
|
91
91
|
cache.fetch(asset_digest_uri_cache_key(asset[:uri])) { asset }
|
92
92
|
|
93
93
|
asset
|
@@ -52,13 +52,13 @@ module Sprockets
|
|
52
52
|
mutate_config(:version) { version.dup }
|
53
53
|
end
|
54
54
|
|
55
|
-
# Returns a `Digest` implementation class.
|
55
|
+
# Deprecated: Returns a `Digest` implementation class.
|
56
56
|
#
|
57
|
-
# Defaults to `Digest::
|
57
|
+
# Defaults to `Digest::SHA256`.
|
58
58
|
attr_reader :digest_class
|
59
59
|
|
60
|
-
# Assign a `Digest` implementation class. This maybe any Ruby
|
61
|
-
# `Digest::` implementation such as `Digest::
|
60
|
+
# Deprecated: Assign a `Digest` implementation class. This maybe any Ruby
|
61
|
+
# `Digest::` implementation such as `Digest::SHA256` or
|
62
62
|
# `Digest::MD5`.
|
63
63
|
#
|
64
64
|
# environment.digest_class = Digest::MD5
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'digest/sha2'
|
4
|
+
|
5
|
+
module Sprockets
|
6
|
+
module DigestUtils
|
7
|
+
extend self
|
8
|
+
|
9
|
+
# Internal: Default digest class.
|
10
|
+
#
|
11
|
+
# Returns a Digest::Base subclass.
|
12
|
+
def digest_class
|
13
|
+
Digest::SHA256
|
14
|
+
end
|
15
|
+
|
16
|
+
# Internal: Maps digest bytesize to the digest class.
|
17
|
+
DIGEST_SIZES = {
|
18
|
+
16 => Digest::MD5,
|
19
|
+
20 => Digest::SHA1,
|
20
|
+
32 => Digest::SHA256,
|
21
|
+
48 => Digest::SHA384,
|
22
|
+
64 => Digest::SHA512
|
23
|
+
}
|
24
|
+
|
25
|
+
# Internal: Detect digest class hash algorithm for digest bytes.
|
26
|
+
#
|
27
|
+
# While not elegant, all the supported digests have a unique bytesize.
|
28
|
+
#
|
29
|
+
# Returns Digest::Base or nil.
|
30
|
+
def detect_digest_class(bytes)
|
31
|
+
DIGEST_SIZES[bytes.bytesize]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
35
|
+
#
|
36
|
+
# obj - A JSON serializable object.
|
37
|
+
#
|
38
|
+
# Returns a String digest of the object.
|
39
|
+
def digest(obj)
|
40
|
+
digest = digest_class.new
|
41
|
+
queue = [obj]
|
42
|
+
|
43
|
+
while queue.length > 0
|
44
|
+
obj = queue.shift
|
45
|
+
klass = obj.class
|
46
|
+
|
47
|
+
if klass == String
|
48
|
+
digest << obj
|
49
|
+
elsif klass == Symbol
|
50
|
+
digest << 'Symbol'
|
51
|
+
digest << obj.to_s
|
52
|
+
elsif klass == Fixnum
|
53
|
+
digest << 'Fixnum'
|
54
|
+
digest << obj.to_s
|
55
|
+
elsif klass == TrueClass
|
56
|
+
digest << 'TrueClass'
|
57
|
+
elsif klass == FalseClass
|
58
|
+
digest << 'FalseClass'
|
59
|
+
elsif klass == NilClass
|
60
|
+
digest << 'NilClass'
|
61
|
+
elsif klass == Array
|
62
|
+
digest << 'Array'
|
63
|
+
queue.concat(obj)
|
64
|
+
elsif klass == Hash
|
65
|
+
digest << 'Hash'
|
66
|
+
queue.concat(obj.sort)
|
67
|
+
elsif klass == Set
|
68
|
+
digest << 'Set'
|
69
|
+
queue.concat(obj.to_a)
|
70
|
+
elsif klass == Encoding
|
71
|
+
digest << 'Encoding'
|
72
|
+
digest << obj.name
|
73
|
+
else
|
74
|
+
raise TypeError, "couldn't digest #{klass}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
digest.digest
|
79
|
+
end
|
80
|
+
|
81
|
+
# Internal: Pack a binary digest to a hex encoded string.
|
82
|
+
#
|
83
|
+
# bin - String bytes
|
84
|
+
#
|
85
|
+
# Returns hex String.
|
86
|
+
def pack_hexdigest(bin)
|
87
|
+
bin.unpack('H*').first
|
88
|
+
end
|
89
|
+
|
90
|
+
# Internal: Pack a binary digest to a base64 encoded string.
|
91
|
+
#
|
92
|
+
# bin - String bytes
|
93
|
+
#
|
94
|
+
# Returns base64 String.
|
95
|
+
def pack_base64digest(bin)
|
96
|
+
[bin].pack('m0')
|
97
|
+
end
|
98
|
+
|
99
|
+
# Internal: Pack a binary digest to a urlsafe base64 encoded string.
|
100
|
+
#
|
101
|
+
# bin - String bytes
|
102
|
+
#
|
103
|
+
# Returns urlsafe base64 String.
|
104
|
+
def pack_urlsafe_base64digest(bin)
|
105
|
+
pack_base64digest(bin).tr('+/', '-_').tr('=', '')
|
106
|
+
end
|
107
|
+
|
108
|
+
# Internal: Maps digest class to the named information hash algorithm name.
|
109
|
+
#
|
110
|
+
# http://www.iana.org/assignments/named-information/named-information.xhtml
|
111
|
+
NI_HASH_ALGORIHMS = {
|
112
|
+
Digest::SHA256 => 'sha-256'.freeze,
|
113
|
+
Digest::SHA384 => 'sha-384'.freeze,
|
114
|
+
Digest::SHA512 => 'sha-512'.freeze
|
115
|
+
}
|
116
|
+
|
117
|
+
# Internal: Generate a "named information" URI for use in the `integrity`
|
118
|
+
# attribute of an asset tag as per the subresource integrity specification.
|
119
|
+
#
|
120
|
+
# digest - The String byte digest of the asset content.
|
121
|
+
# content_type - The content-type the asset will be served with. This *must*
|
122
|
+
# be accurate if provided. Otherwise, subresource integrity
|
123
|
+
# will block the loading of the asset.
|
124
|
+
#
|
125
|
+
# Returns a String or nil if hash algorithm is incompatible.
|
126
|
+
def integrity_uri(digest, content_type = nil)
|
127
|
+
case digest
|
128
|
+
when Digest::Base
|
129
|
+
digest_class = digest.class
|
130
|
+
digest = digest.digest
|
131
|
+
when String
|
132
|
+
digest_class = DIGEST_SIZES[digest.bytesize]
|
133
|
+
else
|
134
|
+
raise TypeError, "unknown digest: #{digest.inspect}"
|
135
|
+
end
|
136
|
+
|
137
|
+
if hash_name = NI_HASH_ALGORIHMS[digest_class]
|
138
|
+
uri = "ni:///#{hash_name};#{pack_urlsafe_base64digest(digest)}"
|
139
|
+
uri << "?ct=#{content_type}" if content_type
|
140
|
+
uri
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
data/lib/sprockets/manifest.rb
CHANGED
@@ -173,7 +173,8 @@ module Sprockets
|
|
173
173
|
'logical_path' => asset.logical_path,
|
174
174
|
'mtime' => asset.mtime.iso8601,
|
175
175
|
'size' => asset.bytesize,
|
176
|
-
'digest' => asset.
|
176
|
+
'digest' => asset.hexdigest,
|
177
|
+
'integrity' => asset.integrity
|
177
178
|
}
|
178
179
|
assets[asset.logical_path] = asset.digest_path
|
179
180
|
|
data/lib/sprockets/path_utils.rb
CHANGED
@@ -114,6 +114,41 @@ module Sprockets
|
|
114
114
|
File.basename(path).scan(/\.[^.]+/)
|
115
115
|
end
|
116
116
|
|
117
|
+
# Internal: Returns all parents for path
|
118
|
+
#
|
119
|
+
# path - String absolute filename or directory
|
120
|
+
# root - String path to stop at (default: system root)
|
121
|
+
#
|
122
|
+
# Returns an Array of String paths.
|
123
|
+
def path_parents(path, root = nil)
|
124
|
+
root = "#{root}#{File::SEPARATOR}" if root
|
125
|
+
parents = []
|
126
|
+
|
127
|
+
loop do
|
128
|
+
parent = File.dirname(path)
|
129
|
+
break if parent == path
|
130
|
+
break if root && !path.start_with?(root)
|
131
|
+
parents << path = parent
|
132
|
+
end
|
133
|
+
|
134
|
+
parents
|
135
|
+
end
|
136
|
+
|
137
|
+
# Internal: Find target basename checking upwards from path.
|
138
|
+
#
|
139
|
+
# basename - String filename: ".sprocketsrc"
|
140
|
+
# path - String path to start search: "app/assets/javascripts/app.js"
|
141
|
+
# root - String path to stop at (default: system root)
|
142
|
+
#
|
143
|
+
# Returns String filename or nil.
|
144
|
+
def find_upwards(basename, path, root = nil)
|
145
|
+
path_parents(path, root).each do |dir|
|
146
|
+
filename = File.join(dir, basename)
|
147
|
+
return filename if file?(filename)
|
148
|
+
end
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
|
117
152
|
# Internal: Stat all the files under a directory.
|
118
153
|
#
|
119
154
|
# dir - A String directory
|
data/lib/sprockets/processing.rb
CHANGED
@@ -180,7 +180,7 @@ module Sprockets
|
|
180
180
|
when NilClass
|
181
181
|
# noop
|
182
182
|
when Hash
|
183
|
-
data = result[:data]
|
183
|
+
data = result[:data] if result.key?(:data)
|
184
184
|
metadata = metadata.merge(result)
|
185
185
|
metadata.delete(:data)
|
186
186
|
when String
|
@@ -195,7 +195,7 @@ module Sprockets
|
|
195
195
|
source: data,
|
196
196
|
charset: data.encoding.name.downcase,
|
197
197
|
length: data.bytesize,
|
198
|
-
digest:
|
198
|
+
digest: digest(data),
|
199
199
|
metadata: metadata
|
200
200
|
}
|
201
201
|
end
|
data/lib/sprockets/server.rb
CHANGED
@@ -67,11 +67,11 @@ module Sprockets
|
|
67
67
|
|
68
68
|
if asset.nil?
|
69
69
|
status = :not_found
|
70
|
-
elsif fingerprint && asset.
|
70
|
+
elsif fingerprint && asset.etag != fingerprint
|
71
71
|
status = :not_found
|
72
|
-
elsif if_match && asset.
|
72
|
+
elsif if_match && asset.etag != if_match
|
73
73
|
status = :precondition_failed
|
74
|
-
elsif if_none_match && asset.
|
74
|
+
elsif if_none_match && asset.etag == if_none_match
|
75
75
|
status = :not_modified
|
76
76
|
else
|
77
77
|
status = :ok
|
@@ -124,8 +124,8 @@ module Sprockets
|
|
124
124
|
end
|
125
125
|
|
126
126
|
# Returns a 304 Not Modified response tuple
|
127
|
-
def not_modified_response(env,
|
128
|
-
[ 304, cache_headers(env,
|
127
|
+
def not_modified_response(env, etag)
|
128
|
+
[ 304, cache_headers(env, etag), [] ]
|
129
129
|
end
|
130
130
|
|
131
131
|
# Returns a 403 Forbidden response tuple
|
@@ -221,12 +221,12 @@ module Sprockets
|
|
221
221
|
env["QUERY_STRING"].to_s =~ /body=(1|t)/
|
222
222
|
end
|
223
223
|
|
224
|
-
def cache_headers(env,
|
224
|
+
def cache_headers(env, etag)
|
225
225
|
headers = {}
|
226
226
|
|
227
227
|
# Set caching headers
|
228
228
|
headers["Cache-Control"] = "public"
|
229
|
-
headers["ETag"] = %("#{
|
229
|
+
headers["ETag"] = %("#{etag}")
|
230
230
|
|
231
231
|
# If the request url contains a fingerprint, set a long
|
232
232
|
# expires on the response
|
@@ -262,16 +262,16 @@ module Sprockets
|
|
262
262
|
headers["Content-Type"] = type
|
263
263
|
end
|
264
264
|
|
265
|
-
headers.merge(cache_headers(env, asset.
|
265
|
+
headers.merge(cache_headers(env, asset.etag))
|
266
266
|
end
|
267
267
|
|
268
|
-
# Gets
|
268
|
+
# Gets ETag fingerprint.
|
269
269
|
#
|
270
270
|
# "foo-0aa2105d29558f3eb790d411d7d8fb66.js"
|
271
271
|
# # => "0aa2105d29558f3eb790d411d7d8fb66"
|
272
272
|
#
|
273
273
|
def path_fingerprint(path)
|
274
|
-
path[/-([0-9a-f]{7,
|
274
|
+
path[/-([0-9a-f]{7,128})\.[^.]+$/, 1]
|
275
275
|
end
|
276
276
|
end
|
277
277
|
end
|
data/lib/sprockets/utils.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'digest/sha1'
|
2
1
|
require 'set'
|
3
2
|
|
4
3
|
module Sprockets
|
@@ -101,54 +100,6 @@ module Sprockets
|
|
101
100
|
end
|
102
101
|
end
|
103
102
|
|
104
|
-
# Internal: Generate a hexdigest for a nested JSON serializable object.
|
105
|
-
#
|
106
|
-
# obj - A JSON serializable object.
|
107
|
-
#
|
108
|
-
# Returns a String SHA1 digest of the object.
|
109
|
-
def hexdigest(obj)
|
110
|
-
digest = Digest::SHA1.new
|
111
|
-
queue = [obj]
|
112
|
-
|
113
|
-
while queue.length > 0
|
114
|
-
obj = queue.shift
|
115
|
-
klass = obj.class
|
116
|
-
|
117
|
-
if klass == String
|
118
|
-
digest << 'String'
|
119
|
-
digest << obj
|
120
|
-
elsif klass == Symbol
|
121
|
-
digest << 'Symbol'
|
122
|
-
digest << obj.to_s
|
123
|
-
elsif klass == Fixnum
|
124
|
-
digest << 'Fixnum'
|
125
|
-
digest << obj.to_s
|
126
|
-
elsif klass == TrueClass
|
127
|
-
digest << 'TrueClass'
|
128
|
-
elsif klass == FalseClass
|
129
|
-
digest << 'FalseClass'
|
130
|
-
elsif klass == NilClass
|
131
|
-
digest << 'NilClass'
|
132
|
-
elsif klass == Array
|
133
|
-
digest << 'Array'
|
134
|
-
queue.concat(obj)
|
135
|
-
elsif klass == Hash
|
136
|
-
digest << 'Hash'
|
137
|
-
queue.concat(obj.sort)
|
138
|
-
elsif klass == Set
|
139
|
-
digest << 'Set'
|
140
|
-
queue.concat(obj.to_a)
|
141
|
-
elsif klass == Encoding
|
142
|
-
digest << 'Encoding'
|
143
|
-
digest << obj.name
|
144
|
-
else
|
145
|
-
raise TypeError, "couldn't digest #{klass}"
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
digest.hexdigest
|
150
|
-
end
|
151
|
-
|
152
103
|
# Internal: Post-order Depth-First search algorithm.
|
153
104
|
#
|
154
105
|
# Used for resolving asset dependencies.
|
data/lib/sprockets/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sprockets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0.beta.
|
4
|
+
version: 3.0.0.beta.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Stephenson
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-10-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -237,6 +237,7 @@ files:
|
|
237
237
|
- lib/sprockets/compressing.rb
|
238
238
|
- lib/sprockets/configuration.rb
|
239
239
|
- lib/sprockets/context.rb
|
240
|
+
- lib/sprockets/digest_utils.rb
|
240
241
|
- lib/sprockets/directive_processor.rb
|
241
242
|
- lib/sprockets/eco_template.rb
|
242
243
|
- lib/sprockets/ejs_template.rb
|