New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent ActionDispatch::ServerTiming from overwriting existing header value #45615
Prevent ActionDispatch::ServerTiming from overwriting existing header value #45615
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
f1b7b37
to
dee65a3
Compare
Done, and, not sure if there can ever be no ActiveSupport Notification events in a response, but I changed the code slightly to handle that too. |
This comment was marked as resolved.
This comment was marked as resolved.
@@ -22,10 +22,12 @@ def call(env) | |||
ActiveSupport::Notifications.unsubscribe(subscriber) | |||
end | |||
|
|||
header_info = events.group_by(&:name).map do |event_name, events_collection| | |||
our_server_timings = events.group_by(&:name).map do |event_name, events_collection| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's keep this name.
our_server_timings = events.group_by(&:name).map do |event_name, events_collection| | |
header_info = events.group_by(&:name).map do |event_name, events_collection| |
headers[SERVER_TIMING_HEADER] = | ||
[headers[SERVER_TIMING_HEADER]].concat(our_server_timings).map(&:to_s).map(&:strip).reject(&:empty?).join(", ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be doing a bit more work than before. Would the following also work?
headers[SERVER_TIMING_HEADER] = | |
[headers[SERVER_TIMING_HEADER]].concat(our_server_timings).map(&:to_s).map(&:strip).reject(&:empty?).join(", ") | |
header_info.prepend(headers[SERVER_TIMING_HEADER]) if headers[SERVER_TIMING_HEADER].present? | |
headers[SERVER_TIMING_HEADER] = header_info.join(", ") |
|
||
def call(env) | ||
status, headers, body = @app.call(env) | ||
headers["Server-Timing"] = [headers["Server-Timing"], %w(entry;desc="description")].compact.join(", ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%w()
creates an array, whereas %()
quotes a string.
headers["Server-Timing"] = [headers["Server-Timing"], %w(entry;desc="description")].compact.join(", ") | |
headers["Server-Timing"] = [headers["Server-Timing"], %(entry;desc="description")].compact.join(", ") |
@@ -52,7 +72,7 @@ def create | |||
end | |||
|
|||
private | |||
def with_test_route_set | |||
def with_test_route_set(later_middlewares: []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This kwarg feels somewhat out of place to me. What do you think about setting up a @middlewares
array (which matches @app
), and appending to that?
index bb581e51e0..ada355be38 100644
--- a/actionpack/test/dispatch/server_timing_test.rb
+++ b/actionpack/test/dispatch/server_timing_test.rb
@@ -22,6 +22,10 @@ def create
end
end
+ setup do
+ @middlewares = [ActionDispatch::ServerTiming]
+ end
+
test "server timing header is included in the response" do
with_test_route_set do
get "/"
@@ -45,7 +49,7 @@ def create
end
test "does not overwrite existing header values" do
- class DummyServerTiming
+ @middlewares << Class.new do
def initialize(app)
@app = app
end
@@ -57,7 +61,7 @@ def call(env)
end
end
- with_test_route_set(later_middlewares: [DummyServerTiming]) do
+ with_test_route_set do
get "/"
assert_match(/entry;desc="description"/, @response.headers["Server-Timing"])
assert_match(/start_processing.action_controller;dur=\w+/, @response.headers["Server-Timing"])
@@ -72,7 +76,7 @@ def call(env)
end
private
- def with_test_route_set(later_middlewares: [])
+ def with_test_route_set
with_routing do |set|
set.draw do
get "/", to: ::ServerTimingTest::TestController.action(:index)
@@ -81,8 +85,7 @@ def with_test_route_set(later_middlewares: [])
end
@app = self.class.build_app(set) do |middleware|
- middleware.use ActionDispatch::ServerTiming
- later_middlewares.each(&middleware.method(:use))
+ @middlewares.each { |m| middleware.use m }
end
yield
dee65a3
to
f075e0c
Compare
@jonathanhefner All the suggestions were great, thanks for reviewing. |
Thank you, @jtmalinowski! 😃 (Backported to |
Prevent ActionDispatch::ServerTiming from overwriting existing header value (cherry picked from commit 9e0fe8e)
Summary
Fixes #45607
Tiny fix, if a middleware adds anything to the
Server-Timing
header, and is down the chain fromActionDispatch::ServerTiming
, the value it set will be overwritten, this PR changes this behaviour, so thatActionDispatch::ServerTiming
appends its entries instead.