1
0
Fork 0
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:
Jean Boussier 2021-05-01 17:43:58 +02:00 committed by GitHub
commit 08e3e663ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 2 deletions

View file

@ -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

View file

@ -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)