mirror of https://github.com/rails/rails
Link preloading should keep integrity hashes in the header
When a stylesheet or javascript link tag (or preload link tag) is output in the view, it also gets sent as a Link header for preloading. This Link header is missing the integrity attribute even when one is set on the tag, which prevents the browser from using the preloaded resource. Co-authored-by: Adrianna Chang <adrianna.chang@shopify.com>
This commit is contained in:
parent
446bf0a91d
commit
4aa91262f0
|
@ -90,12 +90,14 @@ module ActionView
|
|||
nopush = options["nopush"].nil? ? true : options.delete("nopush")
|
||||
crossorigin = options.delete("crossorigin")
|
||||
crossorigin = "anonymous" if crossorigin == true
|
||||
integrity = options["integrity"]
|
||||
|
||||
sources_tags = sources.uniq.map { |source|
|
||||
href = path_to_javascript(source, path_options)
|
||||
unless options["defer"]
|
||||
preload_link = "<#{href}>; rel=preload; as=script"
|
||||
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
||||
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
||||
preload_link += "; nopush" if nopush
|
||||
preload_links << preload_link
|
||||
end
|
||||
|
@ -149,11 +151,13 @@ module ActionView
|
|||
crossorigin = options.delete("crossorigin")
|
||||
crossorigin = "anonymous" if crossorigin == true
|
||||
nopush = options["nopush"].nil? ? true : options.delete("nopush")
|
||||
integrity = options["integrity"]
|
||||
|
||||
sources_tags = sources.uniq.map { |source|
|
||||
href = path_to_stylesheet(source, path_options)
|
||||
preload_link = "<#{href}>; rel=preload; as=style"
|
||||
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
||||
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
||||
preload_link += "; nopush" if nopush
|
||||
preload_links << preload_link
|
||||
tag_options = {
|
||||
|
@ -256,6 +260,7 @@ module ActionView
|
|||
# * <tt>:as</tt> - Override the auto-generated value for as attribute, calculated using +source+ extension and mime type.
|
||||
# * <tt>:crossorigin</tt> - Specify the crossorigin attribute, required to load cross-origin resources.
|
||||
# * <tt>:nopush</tt> - Specify if the use of server push is not desired for the resource. Defaults to +false+.
|
||||
# * <tt>:integrity</tt> - Specify the integrity attribute.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
|
@ -287,6 +292,7 @@ module ActionView
|
|||
as_type = options.delete(:as) || resolve_link_as(extname, mime_type)
|
||||
crossorigin = options.delete(:crossorigin)
|
||||
crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
|
||||
integrity = options[:integrity]
|
||||
nopush = options.delete(:nopush) || false
|
||||
|
||||
link_tag = tag.link(**{
|
||||
|
@ -300,6 +306,7 @@ module ActionView
|
|||
preload_link = "<#{href}>; rel=preload; as=#{as_type}"
|
||||
preload_link += "; type=#{mime_type}" if mime_type
|
||||
preload_link += "; crossorigin=#{crossorigin}" if crossorigin
|
||||
preload_link += "; integrity=#{integrity}" if integrity
|
||||
preload_link += "; nopush" if nopush
|
||||
|
||||
send_preload_links_header([preload_link])
|
||||
|
|
|
@ -239,7 +239,8 @@ class AssetTagHelperTest < ActionView::TestCase
|
|||
%(preload_link_tag '//example.com/map?callback=initMap', as: 'fetch', type: 'application/javascript') => %(<link rel="preload" href="//example.com/map?callback=initMap" as="fetch" type="application/javascript" />),
|
||||
%(preload_link_tag '//example.com/font.woff2') => %(<link rel="preload" href="//example.com/font.woff2" as="font" type="font/woff2" crossorigin="anonymous"/>),
|
||||
%(preload_link_tag '//example.com/font.woff2', crossorigin: 'use-credentials') => %(<link rel="preload" href="//example.com/font.woff2" as="font" type="font/woff2" crossorigin="use-credentials" />),
|
||||
%(preload_link_tag '/media/audio.ogg', nopush: true) => %(<link rel="preload" href="/media/audio.ogg" as="audio" type="audio/ogg" />)
|
||||
%(preload_link_tag '/media/audio.ogg', nopush: true) => %(<link rel="preload" href="/media/audio.ogg" as="audio" type="audio/ogg" />),
|
||||
%(preload_link_tag '/style.css', integrity: 'sha256-AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs') => %(<link rel="preload" href="/style.css" as="style" type="text/css" integrity="sha256-AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs">),
|
||||
}
|
||||
|
||||
VideoPathToTag = {
|
||||
|
@ -535,6 +536,13 @@ class AssetTagHelperTest < ActionView::TestCase
|
|||
assert_equal expected, @response.headers["Link"]
|
||||
end
|
||||
|
||||
def test_should_set_preload_links_with_integrity_hashes
|
||||
stylesheet_link_tag("http://example.com/style.css", integrity: "sha256-AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs")
|
||||
javascript_include_tag("http://example.com/all.js", integrity: "sha256-AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs")
|
||||
expected = "<http://example.com/style.css>; rel=preload; as=style; integrity=sha256-AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs; nopush,<http://example.com/all.js>; rel=preload; as=script; integrity=sha256-AbpHGcgLb+kRsJGnwFEktk7uzpZOCcBY74+YBdrKVGs; nopush"
|
||||
assert_equal expected, @response.headers["Link"]
|
||||
end
|
||||
|
||||
def test_image_path
|
||||
ImagePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) }
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue