aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
authoreileencodes <eileencodes@gmail.com>2017-09-26 13:27:53 -0400
committereileencodes <eileencodes@gmail.com>2017-10-04 09:17:21 -0400
commit59a02fb7bcbe68f26e1e7fdcec45c00c66e4a065 (patch)
treef455ef1b6fa18c6cdc11540d0af365937e8a7b35 /actionpack
parentf1e89628fe3d18427e3b6644b1e7f3ef965ecd5b (diff)
downloadrails-59a02fb7bcbe68f26e1e7fdcec45c00c66e4a065.tar.gz
rails-59a02fb7bcbe68f26e1e7fdcec45c00c66e4a065.tar.bz2
rails-59a02fb7bcbe68f26e1e7fdcec45c00c66e4a065.zip
Implement H2 Early Hints for Rails
When puma/puma#1403 is merged Puma will support the Early Hints status code for sending assets before a request has finished. While the Early Hints spec is still in draft, this PR prepares Rails to allowing this status code. If the proxy server supports Early Hints, it will send H2 pushes to the client. This PR adds a method for setting Early Hints Link headers via Rails, and also automatically sends Early Hints if supported from the `stylesheet_link_tag` and the `javascript_include_tag`. Once puma supports Early Hints the `--early-hints` argument can be passed to the server to enable this or set in the puma config with `early_hints(true)`. Note that for Early Hints to work in the browser the requirements are 1) a proxy that can handle H2, and 2) HTTPS. To start the server with Early Hints enabled pass `--early-hints` to `rails s`. This has been verified to work with h2o, Puma, and Rails with Chrome. The commit adds a new option to the rails server to enable early hints for Puma. Early Hints spec: https://tools.ietf.org/html/draft-ietf-httpbis-early-hints-04 [Eileen M. Uchitelle, Aaron Patterson]
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md8
-rw-r--r--actionpack/lib/action_dispatch/http/request.rb17
-rw-r--r--actionpack/test/dispatch/request_test.rb15
3 files changed, 40 insertions, 0 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 16090e7946..adb86aad9f 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,11 @@
+* Add ability to enable Early Hints for HTTP/2
+
+ If supported by the server, and enabled in Puma this allows H2 Early Hints to be used.
+
+ The `javascript_include_tag` and the `stylesheet_link_tag` automatically add Early Hints if requested.
+
+ *Eileen M. Uchitelle*, *Aaron Patterson*
+
* Simplify cookies middleware with key rotation support
Use the `rotate` method for both `MessageEncryptor` and
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index dee7be184a..5c172aecad 100644
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -199,6 +199,23 @@ module ActionDispatch
@headers ||= Http::Headers.new(self)
end
+ # Early Hints is an HTTP/2 status code that indicates hints to help a client start
+ # making preparations for processing the final response.
+ #
+ # If the env contains +rack.early_hints+ then the server accepts HTTP2 push for Link headers.
+ #
+ # The +send_early_hints+ method accepts an hash of links as follows:
+ #
+ # send_early_hints("Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload")
+ #
+ # If you are using +javascript_include_tag+ or +stylesheet_link_tag+ the
+ # Early Hints headers are included by default if supported.
+ def send_early_hints(links)
+ return unless env["rack.early_hints"]
+
+ env["rack.early_hints"].call(links)
+ end
+
# Returns a +String+ with the last requested path including their params.
#
# # get '/foo'
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 68c6d26364..2a18395aac 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -1304,3 +1304,18 @@ class RequestFormData < BaseRequestTest
assert !request.form_data?
end
end
+
+class EarlyHintsRequestTest < BaseRequestTest
+ def setup
+ super
+ @env["rack.early_hints"] = lambda { |links| links }
+ @request = stub_request
+ end
+
+ test "when early hints is set in the env link headers are sent" do
+ early_hints = @request.send_early_hints("Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload")
+ expected_hints = { "Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload" }
+
+ assert_equal expected_hints, early_hints
+ end
+end