diff options
Diffstat (limited to 'lib/unicorn')
-rw-r--r-- | lib/unicorn/configurator.rb | 9 | ||||
-rw-r--r-- | lib/unicorn/http_server.rb | 31 |
2 files changed, 38 insertions, 2 deletions
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb index c3a4f2d..b0606af 100644 --- a/lib/unicorn/configurator.rb +++ b/lib/unicorn/configurator.rb @@ -276,6 +276,15 @@ class Unicorn::Configurator set_bool(:default_middleware, bool) end + # sets whether to enable the proposed early hints Rack API. + # If enabled, Rails 5.2+ will automatically send a 103 Early Hint + # for all the `javascript_include_tag` and `stylesheet_link_tag` + # in your response. See: https://api.rubyonrails.org/v5.2/classes/ActionDispatch/Request.html#method-i-send_early_hints + # See also https://tools.ietf.org/html/rfc8297 + def early_hints(bool) + set_bool(:early_hints, bool) + end + # sets listeners to the given +addresses+, replacing or augmenting the # current set. This is for the global listener pool shared by all # worker processes. For per-worker listeners, see the after_fork example diff --git a/lib/unicorn/http_server.rb b/lib/unicorn/http_server.rb index 45a2e97..05dad99 100644 --- a/lib/unicorn/http_server.rb +++ b/lib/unicorn/http_server.rb @@ -15,7 +15,7 @@ class Unicorn::HttpServer :before_fork, :after_fork, :before_exec, :listener_opts, :preload_app, :orig_app, :config, :ready_pipe, :user, - :default_middleware + :default_middleware, :early_hints attr_writer :after_worker_exit, :after_worker_ready, :worker_exec attr_reader :pid, :logger @@ -588,6 +588,25 @@ class Unicorn::HttpServer rescue end + def e103_response_write(client, headers) + response = if @request.response_start_sent + "103 Early Hints\r\n" + else + "HTTP/1.1 103 Early Hints\r\n" + end + + headers.each_pair do |k, vs| + next if !vs || vs.empty? + values = vs.to_s.split("\n".freeze) + values.each do |v| + response << "#{k}: #{v}\r\n" + end + end + response << "\r\n".freeze + response << "HTTP/1.1 ".freeze if @request.response_start_sent + client.write(response) + end + def e100_response_write(client, env) # We use String#freeze to avoid allocations under Ruby 2.1+ # Not many users hit this code path, so it's better to reduce the @@ -602,7 +621,15 @@ class Unicorn::HttpServer # once a client is accepted, it is processed in its entirety here # in 3 easy steps: read request, call app, write app response def process_client(client) - status, headers, body = @app.call(env = @request.read(client)) + env = @request.read(client) + + if early_hints + env["rack.early_hints"] = lambda do |headers| + e103_response_write(client, headers) + end + end + + status, headers, body = @app.call(env) begin return if @request.hijacked? |