@@ -2,6 +2,8 @@ module Agents |
||
| 2 | 2 |
class PostAgent < Agent |
| 3 | 3 |
include WebRequestConcern |
| 4 | 4 |
|
| 5 |
+ MIME_RE = /\A\w+\/.+\z/ |
|
| 6 |
+ |
|
| 5 | 7 |
can_dry_run! |
| 6 | 8 |
no_bulk_receive! |
| 7 | 9 |
default_schedule "never" |
@@ -13,7 +15,13 @@ module Agents |
||
| 13 | 15 |
|
| 14 | 16 |
The `method` used can be any of `get`, `post`, `put`, `patch`, and `delete`. |
| 15 | 17 |
|
| 16 |
- By default, non-GETs will be sent with form encoding (`application/x-www-form-urlencoded`). Change `content_type` to `json` to send JSON instead. Change `content_type` to `xml` to send XML, where the name of the root element may be specified using `xml_root`, defaulting to `post`. |
|
| 18 |
+ By default, non-GETs will be sent with form encoding (`application/x-www-form-urlencoded`). |
|
| 19 |
+ |
|
| 20 |
+ Change `content_type` to `json` to send JSON instead. |
|
| 21 |
+ |
|
| 22 |
+ Change `content_type` to `xml` to send XML, where the name of the root element may be specified using `xml_root`, defaulting to `post`. |
|
| 23 |
+ |
|
| 24 |
+ When `content_type` contains a [MIME](https://en.wikipedia.org/wiki/Media_type) type, and `payload` is a string, its interpolated value will be sent as a string in the HTTP request's body and the request's `Content-Type` HTTP header will be set to `content_type`. When `payload` is a string `no_merge` has to be set to `true`. |
|
| 17 | 25 |
|
| 18 | 26 |
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 |
| 19 | 27 |
will be attempted by this Agent, so the Event's "body" value will always be raw text. |
@@ -49,7 +57,8 @@ module Agents |
||
| 49 | 57 |
'something' => 'the event contained {{ somekey }}'
|
| 50 | 58 |
}, |
| 51 | 59 |
'headers' => {},
|
| 52 |
- 'emit_events' => 'false' |
|
| 60 |
+ 'emit_events' => 'false', |
|
| 61 |
+ 'no_merge' => 'false' |
|
| 53 | 62 |
} |
| 54 | 63 |
end |
| 55 | 64 |
|
@@ -66,10 +75,19 @@ module Agents |
||
| 66 | 75 |
errors.add(:base, "post_url and expected_receive_period_in_days are required fields") |
| 67 | 76 |
end |
| 68 | 77 |
|
| 69 |
- if options['payload'].present? && !options['payload'].is_a?(Hash) |
|
| 78 |
+ if options['payload'].present? && %w[get delete].include?(method) && !options['payload'].is_a?(Hash) |
|
| 70 | 79 |
errors.add(:base, "if provided, payload must be a hash") |
| 71 | 80 |
end |
| 72 | 81 |
|
| 82 |
+ if options['payload'].present? && %w[post put patch].include?(method) |
|
| 83 |
+ if !options['payload'].is_a?(Hash) && options['content_type'] !~ MIME_RE |
|
| 84 |
+ errors.add(:base, "if provided, payload must be a hash") |
|
| 85 |
+ end |
|
| 86 |
+ if options['content_type'] =~ MIME_RE && options['payload'].is_a?(String) && boolify(options['no_merge']) != true |
|
| 87 |
+ errors.add(:base, "when the payload is a string, `no_merge` has to be set to `true`") |
|
| 88 |
+ end |
|
| 89 |
+ end |
|
| 90 |
+ |
|
| 73 | 91 |
if options.has_key?('emit_events') && boolify(options['emit_events']).nil?
|
| 74 | 92 |
errors.add(:base, "if provided, emit_events must be true or false") |
| 75 | 93 |
end |
@@ -116,13 +134,16 @@ module Agents |
||
| 116 | 134 |
when 'post', 'put', 'patch' |
| 117 | 135 |
params = nil |
| 118 | 136 |
|
| 119 |
- case interpolated(payload)['content_type'] |
|
| 137 |
+ case (content_type = interpolated(payload)['content_type']) |
|
| 120 | 138 |
when 'json' |
| 121 | 139 |
headers['Content-Type'] = 'application/json; charset=utf-8' |
| 122 | 140 |
body = data.to_json |
| 123 | 141 |
when 'xml' |
| 124 | 142 |
headers['Content-Type'] = 'text/xml; charset=utf-8' |
| 125 | 143 |
body = data.to_xml(root: (interpolated(payload)[:xml_root] || 'post')) |
| 144 |
+ when MIME_RE |
|
| 145 |
+ headers['Content-Type'] = content_type |
|
| 146 |
+ body = data.to_s |
|
| 126 | 147 |
else |
| 127 | 148 |
body = data |
| 128 | 149 |
end |
@@ -46,6 +46,8 @@ describe Agents::PostAgent do |
||
| 46 | 46 |
req.data = ActiveSupport::JSON.decode(request.body) |
| 47 | 47 |
when 'text/xml' |
| 48 | 48 |
req.data = Hash.from_xml(request.body) |
| 49 |
+ when Agents::PostAgent::MIME_RE |
|
| 50 |
+ req.data = request.body |
|
| 49 | 51 |
else |
| 50 | 52 |
raise "unexpected Content-Type: #{content_type}"
|
| 51 | 53 |
end |
@@ -187,6 +189,16 @@ describe Agents::PostAgent do |
||
| 187 | 189 |
expect(@sent_requests[:get][0].data).to eq(@checker.options['payload'].to_query) |
| 188 | 190 |
end |
| 189 | 191 |
|
| 192 |
+ it "sends options['payload'] as a string POST request when content-type continas a MIME type" do |
|
| 193 |
+ @checker.options['payload'] = '<test>hello</test>' |
|
| 194 |
+ @checker.options['content_type'] = 'application/xml' |
|
| 195 |
+ expect {
|
|
| 196 |
+ @checker.check |
|
| 197 |
+ }.to change { @sent_requests[:post].length }.by(1)
|
|
| 198 |
+ |
|
| 199 |
+ expect(@sent_requests[:post][0].data).to eq('<test>hello</test>')
|
|
| 200 |
+ end |
|
| 201 |
+ |
|
| 190 | 202 |
describe "emitting events" do |
| 191 | 203 |
context "when emit_events is not set to true" do |
| 192 | 204 |
it "does not emit events" do |
@@ -304,6 +316,25 @@ describe Agents::PostAgent do |
||
| 304 | 316 |
expect(@checker).to be_valid |
| 305 | 317 |
end |
| 306 | 318 |
|
| 319 |
+ it "should not validate payload as a hash if content_type includes a MIME type and method is not get or delete" do |
|
| 320 |
+ @checker.options['no_merge'] = 'true' |
|
| 321 |
+ @checker.options['content_type'] = 'text/xml' |
|
| 322 |
+ @checker.options['payload'] = "test" |
|
| 323 |
+ expect(@checker).to be_valid |
|
| 324 |
+ |
|
| 325 |
+ @checker.options['method'] = 'get' |
|
| 326 |
+ expect(@checker).not_to be_valid |
|
| 327 |
+ |
|
| 328 |
+ @checker.options['method'] = 'delete' |
|
| 329 |
+ expect(@checker).not_to be_valid |
|
| 330 |
+ end |
|
| 331 |
+ |
|
| 332 |
+ it "requires `no_merge` to be set to true when content_type contains a MIME type" do |
|
| 333 |
+ @checker.options['content_type'] = 'text/xml' |
|
| 334 |
+ @checker.options['payload'] = "test" |
|
| 335 |
+ expect(@checker).not_to be_valid |
|
| 336 |
+ end |
|
| 337 |
+ |
|
| 307 | 338 |
it "requires headers to be a hash, if present" do |
| 308 | 339 |
@checker.options['headers'] = [1,2,3] |
| 309 | 340 |
expect(@checker).not_to be_valid |