mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #42056 from Shopify/split-link-headers
Make sure not to generate Link headers longer than 8kiB
This commit is contained in:
commit
08e3e663ca
2 changed files with 40 additions and 2 deletions
|
@ -541,13 +541,40 @@ module ActionView
|
|||
end
|
||||
end
|
||||
|
||||
def send_preload_links_header(preload_links)
|
||||
MAX_HEADER_SIZE = 8_000 # Some HTTP client and proxies have a 8kiB header limit
|
||||
def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)
|
||||
if respond_to?(:request) && request
|
||||
request.send_early_hints("Link" => preload_links.join("\n"))
|
||||
end
|
||||
|
||||
if respond_to?(:response) && response
|
||||
response.headers["Link"] = [response.headers["Link"].presence, *preload_links].compact.join(",")
|
||||
header = response.headers["Link"]
|
||||
header = header ? header.dup : +""
|
||||
|
||||
# rindex count characters not bytes, but we assume non-ascii characters
|
||||
# are rare in urls, and we have a 192 bytes margin.
|
||||
last_line_offset = header.rindex("\n")
|
||||
last_line_size = if last_line_offset
|
||||
header.bytesize - last_line_offset
|
||||
else
|
||||
header.bytesize
|
||||
end
|
||||
|
||||
preload_links.each do |link|
|
||||
if link.bytesize + last_line_size + 1 < max_header_size
|
||||
unless header.empty?
|
||||
header << ","
|
||||
last_line_size += 1
|
||||
end
|
||||
else
|
||||
header << "\n"
|
||||
last_line_size = 0
|
||||
end
|
||||
header << link
|
||||
last_line_size += link.bytesize
|
||||
end
|
||||
|
||||
response.headers["Link"] = header
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -537,6 +537,17 @@ class AssetTagHelperTest < ActionView::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_should_generate_links_under_the_max_size
|
||||
with_preload_links_header do
|
||||
100.times do |i|
|
||||
stylesheet_link_tag("http://example.com/style.css?#{i}")
|
||||
javascript_include_tag("http://example.com/all.js?#{i}")
|
||||
end
|
||||
lines = @response.headers["Link"].split("\n")
|
||||
assert_equal 2, lines.size
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_not_preload_links_with_defer
|
||||
with_preload_links_header do
|
||||
javascript_include_tag("http://example.com/all.js", defer: true)
|
||||
|
|
Loading…
Reference in a new issue