-
Notifications
You must be signed in to change notification settings - Fork 380
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
[APPSEC-9936] Update AppSec response content_type resolution #2900
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,30 +36,34 @@ def negotiate(env) | |
Response.new( | ||
status: 403, | ||
headers: { 'Content-Type' => content_type }, | ||
body: [Datadog::AppSec::Assets.blocked(format: FORMAT_MAP[content_type])] | ||
body: [Datadog::AppSec::Assets.blocked(format: CONTENT_TYPE_TO_FORMAT[content_type])] | ||
) | ||
end | ||
|
||
private | ||
|
||
FORMAT_MAP = { | ||
'text/plain' => :text, | ||
'text/html' => :html, | ||
CONTENT_TYPE_TO_FORMAT = { | ||
'application/json' => :json, | ||
'text/html' => :html, | ||
'text/plain' => :text, | ||
}.freeze | ||
|
||
DEFAULT_CONTENT_TYPE = 'text/plain' | ||
DEFAULT_CONTENT_TYPE = 'application/json' | ||
|
||
def content_type(env) | ||
return DEFAULT_CONTENT_TYPE unless env.key?('HTTP_ACCEPT') | ||
|
||
accepted = env['HTTP_ACCEPT'].split(',').map { |m| Utils::HTTP::MediaRange.new(m) }.sort!.reverse! | ||
accept_types = env['HTTP_ACCEPT'].split(',').map(&:strip) | ||
|
||
accepted.each_with_object(DEFAULT_CONTENT_TYPE) do |range, _default| | ||
match = FORMAT_MAP.keys.find { |type| range === type } | ||
accepted = accept_types.map { |m| Utils::HTTP::MediaRange.new(m) }.sort!.reverse! | ||
|
||
return match if match | ||
accepted.each do |range| | ||
type_match = CONTENT_TYPE_TO_FORMAT.keys.find { |type| range === type } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good 😄 |
||
|
||
return type_match if type_match | ||
end | ||
|
||
DEFAULT_CONTENT_TYPE | ||
rescue Datadog::AppSec::Utils::HTTP::MediaRange::ParseError | ||
DEFAULT_CONTENT_TYPE | ||
end | ||
|
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.
accepted.each_with_object(DEFAULT_CONTENT_TYPE)
was making it so it returnsDEFAULT_CONTENT_TYPE
when no match has occured.accepted.each
now instead returnsaccepted
, which is an array ofMediaRange
, so:content_type
is now inconsistent: when a match is found it returns a content type but when none is found it returns an array ofMediaRange
FORMAT_MAP[content_type]
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.
Excellent point and catch @lloeki
I decided to know use
each_with_object
because I believe it doesn't express as clearly the intent of returningDEFAULT_CONTENT_TYPE
as having an explicit return value at the end of the loop.I added the necessary code and specs to make sure we do not introduce any regression on this code here:
fe93a72