Skip to content

Commit cf5c162

Browse files
authored
Merge pull request #2112 from tf/additional-headers
Allow registering additional headers for published entries
2 parents 9c80702 + 5b09a97 commit cf5c162

File tree

6 files changed

+167
-10
lines changed

6 files changed

+167
-10
lines changed

app/controllers/pageflow/entries_controller.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,22 +84,29 @@ def delegate_to_entry_type_frontend_app!(entry)
8484
EntriesControllerEnvHelper.add_entry_info_to_env(request.env, entry: entry, mode: :published)
8585

8686
delegate_to_rack_app!(entry.entry_type.frontend_app) do |_status, headers, _body|
87+
config = Pageflow.config_for(entry)
88+
8789
allow_iframe_for_embed(headers)
88-
apply_cache_control(entry, headers)
90+
apply_additional_headers(entry, config, headers)
91+
apply_cache_control(entry, config, headers)
8992
end
9093
end
9194

9295
def allow_iframe_for_embed(headers)
9396
headers.except!('X-Frame-Options') if params[:embed]
9497
end
9598

96-
def apply_cache_control(entry, headers)
97-
config = Pageflow.config_for(entry)
98-
99+
def apply_cache_control(entry, config, headers)
99100
return if config.public_entry_cache_control_header.blank?
100101
return if entry.password_protected?
101102

102103
headers['Cache-Control'] = config.public_entry_cache_control_header
103104
end
105+
106+
def apply_additional_headers(entry, config, headers)
107+
headers.merge!(
108+
config.additional_public_entry_headers.for(entry, request)
109+
)
110+
end
104111
end
105112
end

entry_types/scrolled/lib/pageflow_scrolled/configuration.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Configuration
1010
# @example
1111
#
1212
# config.additional_frontend_packs.register(
13-
# pageflow-scrolled/contentElements/some-pack',
13+
# 'pageflow-scrolled/contentElements/some-pack',
1414
# content_element_type_names: ['someType']
1515
# )
1616
#
@@ -23,7 +23,7 @@ class Configuration
2323
# @example
2424
#
2525
# config.additional_editor_packs.register(
26-
# pageflow-scrolled/contentElements/some-pack'
26+
# 'pageflow-scrolled/contentElements/some-pack'
2727
# )
2828
#
2929
# @return [AdditionalPacks]
@@ -36,8 +36,8 @@ class Configuration
3636
# @example
3737
#
3838
# config.additional_frontend_seed_data.register(
39-
# pageflow-scrolled/contentElements/some-pack',
40-
# ->(entry, request) { {some: 'data'}}
39+
# 'someData',
40+
# ->(entry:, request:, **) { {some: 'data'}}
4141
# )
4242
#
4343
# @return [AdditionalSeedData]

lib/pageflow/additional_headers.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module Pageflow
2+
# Register additional response headers for published entries.
3+
class AdditionalHeaders
4+
# @api private
5+
def initialize
6+
@headers = []
7+
end
8+
9+
# Either a hash of name values pair or a callable taking a
10+
# {PublishedEntry} record and an {ActionDispatch::Request} object
11+
# and returns a hash.
12+
def register(headers)
13+
@headers << headers
14+
end
15+
16+
# @api private
17+
def for(entry, request)
18+
@headers.map { |headers|
19+
if headers.respond_to?(:call)
20+
headers.call(entry, request)
21+
else
22+
headers
23+
end
24+
}.reduce({}, :merge)
25+
end
26+
end
27+
end

lib/pageflow/configuration.rb

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ class Configuration
187187
attr_accessor :public_entry_request_scope
188188

189189
# Either a lambda or an object with a `call` method taking an
190-
# {Entry} record and an {ActionDispatch::Request} object and
191-
# returning `nil` or a path to redirect to. Can be used in
190+
# {PublishedEntry} record and an {ActionDispatch::Request} object
191+
# and returning `nil` or a path to redirect to. Can be used in
192192
# conjuction with {PrimaryDomainEntryRedirect} to make sure
193193
# entries are accessed via their account's configured cname.
194194
#
@@ -208,6 +208,24 @@ class Configuration
208208
# @return [String]
209209
attr_accessor :public_entry_cache_control_header
210210

211+
# Provide additional response headers for published entries.
212+
#
213+
# @example
214+
#
215+
# config.additional_public_entry_headers.register(
216+
# {'Some' => 'value'}
217+
# )
218+
#
219+
# config.additional_public_entry_headers.register(
220+
# lambda do |_entry, request|
221+
# {'Some' => request.headers['Other']}
222+
# end
223+
# )
224+
#
225+
# @return [AdditionalHeaders]
226+
# @since edge
227+
attr_reader :additional_public_entry_headers
228+
211229
# Either a lambda or an object with a `call` method taking a
212230
# {Site} as paramater and returing a hash of options used to
213231
# construct the url of a published entry.
@@ -435,6 +453,7 @@ def initialize(target_type_name = nil)
435453
@site_request_scope = CnameSiteRequestScope.new
436454
@public_entry_request_scope = lambda { |entries, request| entries }
437455
@public_entry_redirect = ->(_entry, _request) { nil }
456+
@additional_public_entry_headers = AdditionalHeaders.new
438457
@public_entry_url_options = Pageflow::SitesHelper::DEFAULT_PUBLIC_ENTRY_OPTIONS
439458
@entry_embed_url_options = {protocol: 'https'}
440459

@@ -578,6 +597,7 @@ def enable_all_features
578597
delegate :themes, to: :config
579598
delegate :widget_types, to: :config
580599
delegate :public_entry_cache_control_header=, to: :config
600+
delegate :additional_public_entry_headers, to: :config
581601

582602
delegate :for_entry_type, to: :config
583603
end
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
require 'spec_helper'
2+
3+
module Pageflow
4+
describe AdditionalHeaders do
5+
it 'returns empty hash by default' do
6+
additional_headers = AdditionalHeaders.new
7+
entry = create(:published_entry)
8+
9+
result = additional_headers.for(entry, request)
10+
11+
expect(result).to eq({})
12+
end
13+
14+
it 'merges multiple registered hashes of headers' do
15+
additional_headers = AdditionalHeaders.new
16+
entry = create(:published_entry)
17+
18+
additional_headers.register('Some' => 'value')
19+
additional_headers.register('Other' => 'header')
20+
additional_headers.register(proc { {'Dynamic' => 'header'} })
21+
result = additional_headers.for(entry, request)
22+
23+
expect(result).to eq('Some' => 'value',
24+
'Other' => 'header',
25+
'Dynamic' => 'header')
26+
end
27+
28+
def request(uri = 'https://example.com')
29+
ActionDispatch::Request.new(Rack::MockRequest.env_for(uri))
30+
end
31+
end
32+
end

spec/requests/pageflow/entries_show_request_spec.rb

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,77 @@ module Pageflow
395395
expect(response.headers['Cache-Control']).to eq('public, max-age=3600')
396396
end
397397
end
398+
399+
describe 'with additional headers' do
400+
it 'adds headers to responds' do
401+
pageflow_configure do |config|
402+
config.additional_public_entry_headers.register('X-Some' => 'value')
403+
end
404+
405+
entry = create(:entry, :published,
406+
type_name: 'test')
407+
408+
get(short_entry_url(entry))
409+
410+
expect(response.status).to eq(200)
411+
expect(response.headers['X-Some']).to eq('value')
412+
end
413+
414+
it 'passes entry and request to callable' do
415+
pageflow_configure do |config|
416+
config.additional_public_entry_headers.register(
417+
lambda do |entry, request|
418+
{
419+
'X-From-Entry' => entry.type_name,
420+
'X-From-Request' => request.subdomain
421+
}
422+
end
423+
)
424+
end
425+
426+
entry = create(:entry, :published,
427+
type_name: 'test')
428+
429+
get(short_entry_url(entry), headers: {'HTTP_HOST' => 'news.example.com'})
430+
431+
expect(response.status).to eq(200)
432+
expect(response.headers['X-From-Entry']).to eq('test')
433+
expect(response.headers['X-From-Request']).to eq('news')
434+
end
435+
436+
it 'does not use headers registered in feature flag by default' do
437+
pageflow_configure do |config|
438+
config.features.register('some_header') do |feature_config|
439+
feature_config.additional_public_entry_headers.register('X-Some' => 'value')
440+
end
441+
end
442+
443+
entry = create(:entry, :published,
444+
type_name: 'test')
445+
446+
get(short_entry_url(entry))
447+
448+
expect(response.status).to eq(200)
449+
expect(response.headers).not_to have_key('X-Some')
450+
end
451+
452+
it 'uses headers registered in enabled feature flag' do
453+
pageflow_configure do |config|
454+
config.features.register('some_header') do |feature_config|
455+
feature_config.additional_public_entry_headers.register('X-Some' => 'value')
456+
end
457+
end
458+
459+
entry = create(:entry, :published,
460+
type_name: 'test',
461+
with_feature: 'some_header')
462+
463+
get(short_entry_url(entry))
464+
465+
expect(response.status).to eq(200)
466+
expect(response.headers['X-Some']).to eq('value')
467+
end
468+
end
398469
end
399470
end
400471
end

0 commit comments

Comments
 (0)