Skip to content

Commit

Permalink
Add an option event_headers_style to PostAgent
Browse files Browse the repository at this point in the history
It is defaulted to `capitalized`, normalizing emitted headers by
capitalizing the names so downstream agents don't need to bother with
the letter cases.

Previously, the style of header names in an emitted event would vary
depending on the server and the backend HTTP library.  Most notably, the
`net_http` backend downcases header names whereas other backends do not.

For backward compatibility, preexisting PostAgents are automatically
configured to have `event_headers_style` set to `raw` via migration.
  • Loading branch information
knu committed Apr 5, 2016
1 parent feeb3d8 commit dce5bfc
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
46 changes: 45 additions & 1 deletion app/models/agents/post_agent.rb
Expand Up @@ -25,6 +25,13 @@ class PostAgent < Agent
If `emit_events` is set to `true`, the server response will be emitted as an Event and can be fed to a WebsiteAgent for parsing (using its `data_from_event` and `type` options). No data processing
will be attempted by this Agent, so the Event's "body" value will always be raw text.
The Event will also have a "headers" hash and a "status" integer value.
Set `event_headers_style` to one of the following values to normalize the keys of "headers" for downstream agents' convenience:
* `capitalized` (default) - Header names are capitalized; e.g. "Content-Type"
* `downcased` - Header names are downcased; e.g. "content-type"
* `snakecased` - Header names are snakecased; e.g. "content_type"
* `raw` - Backward compatibility option to leave them unmodified from what the underlying HTTP library returns.
Other Options:
Expand Down Expand Up @@ -92,6 +99,12 @@ def validate_options
errors.add(:base, "if provided, emit_events must be true or false")
end

begin
normalize_response_headers({})
rescue ArgumentError => e
errors.add(:base, e.message)
end

unless %w[post get put delete patch].include?(method)
errors.add(:base, "method must be 'post', 'get', 'put', 'delete', or 'patch'")
end
Expand Down Expand Up @@ -124,6 +137,33 @@ def check

private

def normalize_response_headers(headers)
case interpolated['event_headers_style']
when nil, '', 'capitalized'
normalize = ->name {
name.gsub(/(?:\A|(?<=-))([[:alpha:]])|([[:alpha:]]+)/) {
$1 ? $1.upcase : $2.downcase
}
}
when 'downcased'
normalize = :downcase.to_proc
when 'snakecased', nil
normalize = ->name { name.tr('A-Z-', 'a-z_') }
when 'raw'
if Object.method_defined?(:itself) # Ruby >= 2.2
normalize = :itself.to_proc
else
normalize = ->name { name }
end
else
raise ArgumentError, "if provided, event_headers_style must be 'capitalized', 'downcased', 'snakecased' or 'raw'"
end

headers.each_with_object({}) { |(key, value), hash|
hash[normalize[key]] = value
}
end

def handle(data, payload = {})
url = interpolated(payload)[:post_url]
headers = headers()
Expand Down Expand Up @@ -156,7 +196,11 @@ def handle(data, payload = {})
}

if boolify(interpolated['emit_events'])
create_event payload: { body: response.body, headers: response.headers, status: response.status }
create_event payload: {
body: response.body,
headers: normalize_response_headers(response.headers),
status: response.status
}
end
end
end
Expand Down
11 changes: 11 additions & 0 deletions db/migrate/20160405072512_post_agent_set_event_header_style.rb
@@ -0,0 +1,11 @@
class PostAgentSetEventHeaderStyle < ActiveRecord::Migration
def up
Agent.of_type("Agents::PostAgent").each do |post_agent|
if post_agent.send(:boolify, post_agent.options['emit_events']) &&
!post_agent.options.key?('event_headers_style')
post_agent.options['event_headers_style'] = 'raw'
post_agent.save!
end
end
end
end
22 changes: 20 additions & 2 deletions spec/models/agents/post_agent_spec.rb
Expand Up @@ -52,7 +52,7 @@
raise "unexpected Content-Type: #{content_type}"
end
end
{ status: 200, body: "<html>a webpage!</html>", headers: { 'Content-Type' => 'text/html' } }
{ status: 200, body: "<html>a webpage!</html>", headers: { 'Content-type' => 'text/html' } }
}
end

Expand Down Expand Up @@ -226,10 +226,28 @@
expect(@checker.events.last.payload['body']).to eq '<html>a webpage!</html>'
end

it "emits the response headers" do
it "emits the response headers capitalized by default" do
@checker.check
expect(@checker.events.last.payload['headers']).to eq({ 'Content-Type' => 'text/html' })
end

it "emits the response headers capitalized" do
@checker.options['event_headers_style'] = 'capitalized'
@checker.check
expect(@checker.events.last.payload['headers']).to eq({ 'Content-Type' => 'text/html' })
end

it "emits the response headers downcased" do
@checker.options['event_headers_style'] = 'downcased'
@checker.check
expect(@checker.events.last.payload['headers']).to eq({ 'content-type' => 'text/html' })
end

it "emits the response headers snakecased" do
@checker.options['event_headers_style'] = 'snakecased'
@checker.check
expect(@checker.events.last.payload['headers']).to eq({ 'content_type' => 'text/html' })
end
end
end
end
Expand Down

0 comments on commit dce5bfc

Please sign in to comment.