mirror of
https://github.com/discourse/discourse.git
synced 2025-05-30 07:11:34 +08:00

Follow up from https://github.com/discourse/discourse/pull/31559. We expect some standard headers to be added from `Rails.application.config.action_dispatch.default_headers` for responses, however these were found to be removed in some error paths. For more detail on this behaviour, refer to https://github.com/discourse/discourse/pull/31619#issuecomment-2699644232. This PR adds those headers back if they aren't there, with the caveats that we don't add headers that are irrelevant for non-HTML responses, and neither do we add X-Frame-Options which is intentionally removed for embeddables.
79 lines
2.6 KiB
Ruby
79 lines
2.6 KiB
Ruby
# frozen_string_literal: true
|
|
RSpec.describe Middleware::DefaultHeaders do
|
|
let(:mock_default_headers) do
|
|
{
|
|
"X-XSS-Protection" => "0",
|
|
"X-Content-Type-Options" => "nosniff",
|
|
"X-Permitted-Cross-Domain-Policies" => "none",
|
|
"Referrer-Policy" => "strict-origin-when-cross-origin",
|
|
}
|
|
end
|
|
|
|
let(:html_only_headers) { described_class::HTML_ONLY_HEADERS }
|
|
let(:universal_headers) { Set.new(mock_default_headers.keys) - html_only_headers }
|
|
|
|
before do
|
|
allow(Rails.application.config.action_dispatch).to receive(:default_headers).and_return(
|
|
mock_default_headers,
|
|
)
|
|
end
|
|
|
|
context "when a public exception(like RoutingError) is raised" do
|
|
context "when requesting an HTML page" do
|
|
let(:html_path) { "/nonexistent" }
|
|
|
|
it "sets the Cross-Origin-Opener-Policy header" do
|
|
SiteSetting.bootstrap_error_pages = true
|
|
get html_path # triggers a RoutingError, handled by the exceptions_app
|
|
expect(response.headers).to have_key("Cross-Origin-Opener-Policy")
|
|
expect(response.headers["Cross-Origin-Opener-Policy"]).to eq("same-origin-allow-popups")
|
|
end
|
|
|
|
it "sets all default Rails headers for HTML responses" do
|
|
get html_path
|
|
|
|
mock_default_headers.each { |name, value| expect(response.headers[name]).to eq(value) }
|
|
end
|
|
end
|
|
|
|
context "when requesting a JSON response for an invalid URL" do
|
|
let(:json_path) { "/nonexistent.json" }
|
|
|
|
it "adds only universal default headers to non-HTML responses" do
|
|
get json_path
|
|
|
|
universal_headers.each do |name|
|
|
expect(response.headers[name]).to eq(mock_default_headers[name])
|
|
end
|
|
html_only_headers.each { |name| expect(response.headers[name]).to be_nil }
|
|
expect(response.headers["Cross-Origin-Opener-Policy"]).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when a rescued exception is raised" do
|
|
before do
|
|
@old_logger = Rails.logger
|
|
@logs = StringIO.new
|
|
Rails.logger = Logger.new(@logs)
|
|
end
|
|
|
|
after { Rails.logger = @old_logger }
|
|
|
|
it "adds default headers to the response" do
|
|
bad_str = (+"d\xDE").force_encoding("utf-8")
|
|
expect(bad_str.valid_encoding?).to eq(false)
|
|
|
|
get "/latest", params: { test: bad_str }
|
|
|
|
log = @logs.string
|
|
expect(log).not_to include("exception app middleware")
|
|
|
|
expect(response.status).to eq(400)
|
|
expect(response.headers).to have_key("Cross-Origin-Opener-Policy")
|
|
expect(response.headers["Cross-Origin-Opener-Policy"]).to eq("same-origin-allow-popups")
|
|
mock_default_headers.each { |name, value| expect(response.headers[name]).to eq(value) }
|
|
end
|
|
end
|
|
end
|