logstash-output-http 5.2.5 → 5.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bc2a004219fe6c466a5d60b24de18d1e70e8350da5f204279e43bdc0205b24a
4
- data.tar.gz: a3e44b45451030f4ba285df7875b418ef043df81e0689230b20a3de295484cde
3
+ metadata.gz: 6f8c174b5f5725b3dff206924edcff21ebc71899e386c1a301860dba438bbec5
4
+ data.tar.gz: dd6f158c15357a1dee6bfc3ad6e0faa4f6080c3fc2a89b6050b188bd3d016d4a
5
5
  SHA512:
6
- metadata.gz: d9d08edfc5f3cb590177d1b529b30fde4e7fc4ed3ee70bca99dcd2e0c4cdb01cb91f90d5deb0fb60efc6ce3e632ff7db2bcb82890c4f7ad6a08a576c209f9fd9
7
- data.tar.gz: 79c522bf0c7be7dd4d60abccef78eb52dd52f8f3a3cd30fd141941aef6e1288ea5e5249fe718fbf4452b2f81a8f09d168ffabba7ecc2a6b374a9f25cedf886a4
6
+ metadata.gz: 2d668381891939636b2462361fe0011d5ced8461b5a1a5e7f2662aa765e4672b6377e2dd37a05073eaa8e0602d60632496fa48ec9c42ab5063839f02214f2e9d
7
+ data.tar.gz: b3ff1de393aee131f18a1d8d75f05389f6a74642e695626b1e9b4b03eec99b7a26017cea50b97315f35594013650785a8b3e11bfcc7acd4e5d32ed118340f208
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 5.4.1
2
+ - Fix retry indefinitely in termination process. This feature requires Logstash 8.1 [#129](https://github.com/logstash-plugins/logstash-output-http/pull/129)
3
+ - Docs: Add retry policy description [#130](https://github.com/logstash-plugins/logstash-output-http/pull/130)
4
+
5
+ ## 5.4.0
6
+ - Introduce retryable unknown exceptions for "connection reset by peer" and "timeout" [#127](https://github.com/logstash-plugins/logstash-output-http/pull/127)
7
+
8
+ ## 5.3.0
9
+ - Feat: support ssl_verification_mode option [#126](https://github.com/logstash-plugins/logstash-output-http/pull/126)
10
+
1
11
  ## 5.2.5
2
12
  - Reduce amount of default logging on a failed request [#122](https://github.com/logstash-plugins/logstash-output-http/pull/122)
3
13
 
data/docs/index.asciidoc CHANGED
@@ -31,6 +31,40 @@ guaranteed!
31
31
 
32
32
  Beware, this gem does not yet support codecs. Please use the 'format' option for now.
33
33
 
34
+ [id="plugins-{type}s-{plugin}-retry_policy"]
35
+ ==== Retry policy
36
+
37
+ This output has two levels of retry: library and plugin.
38
+
39
+ [id="plugins-{type}s-{plugin}-library_retry"]
40
+ ===== Library retry
41
+
42
+ The library retry applies to IO related failures.
43
+ Non retriable errors include SSL related problems, unresolvable hosts,
44
+ connection issues, and OS/JVM level interruptions happening during a request.
45
+
46
+ The options for library retry are:
47
+
48
+ * <<plugins-{type}s-{plugin}-automatic_retries,`automatic_retries`>>.
49
+ Controls the number of times the plugin should retry after failures at the library level.
50
+ * <<plugins-{type}s-{plugin}-retry_non_idempotent,`retry_non_idempotent`>>.
51
+ When set to `false`, GET, HEAD, PUT, DELETE, OPTIONS, and TRACE requests will be
52
+ retried.
53
+
54
+ [id="plugins-{type}s-{plugin}-plugin_retry"]
55
+ ===== Plugin retry
56
+
57
+ The options for plugin level retry are:
58
+
59
+ * <<plugins-{type}s-{plugin}-retry_failed,`retry_failed`>>.
60
+ When set to `true`, the plugin retries indefinitely for HTTP error response codes defined
61
+ in the <<plugins-{type}s-{plugin}-retryable_codes,`retryable_codes`>> option
62
+ (429, 500, 502, 503, 504) and retryable exceptions (socket timeout/ error, DNS resolution failure and client protocol exception).
63
+ * <<plugins-{type}s-{plugin}-retryable_codes,`retryable_codes`>>.
64
+ Sets http response codes that trigger a retry.
65
+
66
+ NOTE: The `retry_failed` option does not control the library level retry.
67
+
34
68
  [id="plugins-{type}s-{plugin}-options"]
35
69
  ==== Http Output Configuration Options
36
70
 
@@ -66,6 +100,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ
66
100
  | <<plugins-{type}s-{plugin}-retry_non_idempotent>> |<<boolean,boolean>>|No
67
101
  | <<plugins-{type}s-{plugin}-retryable_codes>> |<<number,number>>|No
68
102
  | <<plugins-{type}s-{plugin}-socket_timeout>> |<<number,number>>|No
103
+ | <<plugins-{type}s-{plugin}-ssl_verification_mode>> |<<string,string>>|No
69
104
  | <<plugins-{type}s-{plugin}-truststore>> |a valid filesystem path|No
70
105
  | <<plugins-{type}s-{plugin}-truststore_password>> |<<password,password>>|No
71
106
  | <<plugins-{type}s-{plugin}-truststore_type>> |<<string,string>>|No
@@ -84,12 +119,10 @@ output plugins.
84
119
  * Value type is <<number,number>>
85
120
  * Default value is `1`
86
121
 
87
- How many times should the client retry a failing URL. We highly recommend NOT setting this value
88
- to zero if keepalive is enabled. Some servers incorrectly end keepalives early requiring a retry!
89
- Only IO related failures will be retried, such as connection timeouts and unreachable hosts.
90
- Valid but non 2xx HTTP responses will always be retried, regardless of the value of this setting,
91
- unless `retry_failed` is set.
92
- Note: if `retry_non_idempotent` is NOT set only GET, HEAD, PUT, DELETE, OPTIONS, and TRACE requests will be retried.
122
+ How many times should the client retry a failing URL. We recommend setting this option
123
+ to a value other than zero if the <<plugins-{type}s-{plugin}-keepalive,`keepalive` option>> is enabled.
124
+ Some servers incorrectly end keepalives early, requiring a retry.
125
+ See <<plugins-{type}s-{plugin}-retry_policy,Retry Policy>> for more information.
93
126
 
94
127
  [id="plugins-{type}s-{plugin}-cacert"]
95
128
  ===== `cacert`
@@ -310,7 +343,12 @@ Timeout (in seconds) for the entire request
310
343
  * Value type is <<boolean,boolean>>
311
344
  * Default value is `true`
312
345
 
313
- Set this to false if you don't want this output to retry failed requests
346
+ Note that this option controls plugin-level retries only.
347
+ It has no affect on library-level retries.
348
+
349
+ Set this option to `false` if you want to disable infinite retries for HTTP error response codes defined in the <<plugins-{type}s-{plugin}-retryable_codes,`retryable_codes`>> or
350
+ retryable exceptions (Timeout, SocketException, ClientProtocolException, ResolutionFailure and SocketTimeout).
351
+ See <<plugins-{type}s-{plugin}-retry_policy,Retry policy>> for more information.
314
352
 
315
353
  [id="plugins-{type}s-{plugin}-retry_non_idempotent"]
316
354
  ===== `retry_non_idempotent`
@@ -318,8 +356,10 @@ Set this to false if you don't want this output to retry failed requests
318
356
  * Value type is <<boolean,boolean>>
319
357
  * Default value is `false`
320
358
 
321
- If `automatic_retries` is enabled this will cause non-idempotent HTTP verbs (such as POST) to be retried.
322
- This only affects connectivity related errors (see related `automatic_retries` setting).
359
+ When this option is set to `false` and `automatic_retries` is enabled, GET, HEAD, PUT, DELETE, OPTIONS, and TRACE requests will be retried.
360
+
361
+ When set to `true` and `automatic_retries` is enabled, this will cause non-idempotent HTTP verbs (such as POST) to be retried.
362
+ See <<plugins-{type}s-{plugin}-retry_policy,Retry Policy>> for more information.
323
363
 
324
364
  [id="plugins-{type}s-{plugin}-retryable_codes"]
325
365
  ===== `retryable_codes`
@@ -327,7 +367,8 @@ This only affects connectivity related errors (see related `automatic_retries` s
327
367
  * Value type is <<number,number>>
328
368
  * Default value is `[429, 500, 502, 503, 504]`
329
369
 
330
- If encountered as response codes this plugin will retry these requests
370
+ If the plugin encounters these response codes, the plugin will retry indefinitely.
371
+ See <<plugins-{type}s-{plugin}-retry_policy,Retry Policy>> for more information.
331
372
 
332
373
  [id="plugins-{type}s-{plugin}-socket_timeout"]
333
374
  ===== `socket_timeout`
@@ -337,6 +378,22 @@ If encountered as response codes this plugin will retry these requests
337
378
 
338
379
  Timeout (in seconds) to wait for data on the socket. Default is `10s`
339
380
 
381
+ [id="plugins-{type}s-{plugin}-ssl_verification_mode"]
382
+ ===== `ssl_verification_mode`
383
+
384
+ * Value type is <<string,string>>
385
+ * Supported values are: `full`, `none`
386
+ * Default value is `full`
387
+
388
+ Controls the verification of server certificates.
389
+ The `full` option verifies that the provided certificate is signed by a trusted authority (CA)
390
+ and also that the server’s hostname (or IP address) matches the names identified within the certificate.
391
+
392
+ The `none` setting performs no verification of the server’s certificate.
393
+ This mode disables many of the security benefits of SSL/TLS and should only be used after cautious consideration.
394
+ It is primarily intended as a temporary diagnostic mechanism when attempting to resolve TLS errors.
395
+ Using `none` in production environments is strongly discouraged.
396
+
340
397
  [id="plugins-{type}s-{plugin}-truststore"]
341
398
  ===== `truststore`
342
399
 
@@ -388,4 +445,4 @@ See https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache
388
445
  [id="plugins-{type}s-{plugin}-common-options"]
389
446
  include::{include_path}/{type}.asciidoc[]
390
447
 
391
- :default_codec!:
448
+ :default_codec!:
@@ -23,6 +23,13 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
23
23
  ::Manticore::SocketTimeout
24
24
  ]
25
25
 
26
+ RETRYABLE_UNKNOWN_EXCEPTION_STRINGS = [
27
+ /Connection reset by peer/i,
28
+ /Read Timed out/i
29
+ ]
30
+
31
+ class PluginInternalQueueLeftoverError < StandardError; end
32
+
26
33
  # This output lets you send events to a
27
34
  # generic HTTP(S) endpoint
28
35
  #
@@ -138,10 +145,11 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
138
145
  end
139
146
 
140
147
  def log_retryable_response(response)
148
+ retry_msg = @retry_failed ? 'will retry' : "won't retry"
141
149
  if (response.code == 429)
142
- @logger.debug? && @logger.debug("Encountered a 429 response, will retry. This is not serious, just flow control via HTTP")
150
+ @logger.debug? && @logger.debug("Encountered a 429 response, #{retry_msg}. This is not serious, just flow control via HTTP")
143
151
  else
144
- @logger.warn("Encountered a retryable HTTP request in HTTP output, will retry", :code => response.code, :body => response.body)
152
+ @logger.warn("Encountered a retryable HTTP request in HTTP output, #{retry_msg}", :code => response.code, :body => response.body)
145
153
  end
146
154
  end
147
155
 
@@ -172,6 +180,9 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
172
180
 
173
181
  event, attempt = popped
174
182
 
183
+ raise PluginInternalQueueLeftoverError.new("Received pipeline shutdown request but http output has unfinished events. " \
184
+ "If persistent queue is enabled, events will be retried.") if attempt > 2 && pipeline_shutdown_requested?
185
+
175
186
  action, event, attempt = send_event(event, attempt)
176
187
  begin
177
188
  action = :failure if action == :retry && !@retry_failed
@@ -216,6 +227,11 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
216
227
  raise e
217
228
  end
218
229
 
230
+ def pipeline_shutdown_requested?
231
+ return super if defined?(super) # since LS 8.1.0
232
+ nil
233
+ end
234
+
219
235
  def sleep_for_attempt(attempt)
220
236
  sleep_for = attempt**2
221
237
  sleep_for = sleep_for <= 60 ? sleep_for : 60
@@ -294,12 +310,21 @@ class LogStash::Outputs::Http < LogStash::Outputs::Base
294
310
  end
295
311
 
296
312
  def retryable_exception?(exception)
297
- RETRYABLE_MANTICORE_EXCEPTIONS.any? {|me| exception.is_a?(me) }
313
+ retryable_manticore_exception?(exception) || retryable_unknown_exception?(exception)
314
+ end
315
+
316
+ def retryable_manticore_exception?(exception)
317
+ RETRYABLE_MANTICORE_EXCEPTIONS.any? {|me| exception.is_a?(me)}
318
+ end
319
+
320
+ def retryable_unknown_exception?(exception)
321
+ exception.is_a?(::Manticore::UnknownException) &&
322
+ RETRYABLE_UNKNOWN_EXCEPTION_STRINGS.any? { |snippet| exception.message =~ snippet }
298
323
  end
299
324
 
300
325
  # This is split into a separate method mostly to help testing
301
326
  def log_failure(message, opts)
302
- @logger.error("[HTTP Output Failure] #{message}", opts)
327
+ @logger.error(message, opts)
303
328
  end
304
329
 
305
330
  # Format the HTTP body
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-output-http'
3
- s.version = '5.2.5'
3
+ s.version = '5.4.1'
4
4
  s.licenses = ['Apache License (2.0)']
5
5
  s.summary = "Sends events to a generic HTTP or HTTPS endpoint"
6
6
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
 
21
21
  # Gem dependencies
22
22
  s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
23
- s.add_runtime_dependency "logstash-mixin-http_client", ">= 6.0.0", "< 8.0.0"
23
+ s.add_runtime_dependency "logstash-mixin-http_client", ">= 7.1.0", "< 8.0.0"
24
24
 
25
25
  s.add_development_dependency 'logstash-devutils'
26
26
  s.add_development_dependency 'sinatra'
@@ -3,6 +3,9 @@ require "logstash/outputs/http"
3
3
  require "logstash/codecs/plain"
4
4
  require "thread"
5
5
  require "sinatra"
6
+ require "webrick"
7
+ require "webrick/https"
8
+ require 'openssl'
6
9
  require_relative "../supports/compressed_requests"
7
10
 
8
11
  PORT = rand(65535-1024) + 1025
@@ -22,9 +25,20 @@ class TestApp < Sinatra::Base
22
25
  # on the fly uncompress gzip content
23
26
  use CompressedRequests
24
27
 
25
- # disable WEBrick logging
28
+ set :environment, :production
29
+ set :sessions, false
30
+
31
+ @@server_settings = {
32
+ :AccessLog => [], # disable WEBrick logging
33
+ :Logger => WEBrick::BasicLog::new(nil, WEBrick::BasicLog::FATAL)
34
+ }
35
+
26
36
  def self.server_settings
27
- { :AccessLog => [], :Logger => WEBrick::BasicLog::new(nil, WEBrick::BasicLog::FATAL) }
37
+ @@server_settings
38
+ end
39
+
40
+ def self.server_settings=(settings)
41
+ @@server_settings = settings
28
42
  end
29
43
 
30
44
  def self.multiroute(methods, path, &block)
@@ -72,31 +86,22 @@ class TestApp < Sinatra::Base
72
86
  end
73
87
  end
74
88
 
75
- RSpec.configure do |config|
89
+ RSpec.configure do
76
90
  #http://stackoverflow.com/questions/6557079/start-and-call-ruby-http-server-in-the-same-script
77
- def sinatra_run_wait(app, opts)
91
+ def start_app_and_wait(app, opts = {})
78
92
  queue = Queue.new
79
93
 
80
- t = java.lang.Thread.new(
81
- proc do
82
- begin
83
- app.run!(opts) do |server|
84
- queue.push("started")
85
- end
86
- rescue => e
87
- puts "Error in webserver thread #{e}"
88
- # ignore
94
+ Thread.start do
95
+ begin
96
+ app.start!({ server: 'WEBrick', port: PORT }.merge opts) do |server|
97
+ queue.push(server)
89
98
  end
99
+ rescue => e
100
+ warn "Error starting app: #{e.inspect}" # ignore
90
101
  end
91
- )
92
- t.daemon = true
93
- t.start
94
- queue.pop # blocks until the run! callback runs
95
- end
102
+ end
96
103
 
97
- config.before(:suite) do
98
- sinatra_run_wait(TestApp, :port => PORT, :server => 'webrick')
99
- puts "Test webserver on port #{PORT}"
104
+ queue.pop # blocks until the start! callback runs
100
105
  end
101
106
  end
102
107
 
@@ -104,6 +109,15 @@ describe LogStash::Outputs::Http do
104
109
  # Wait for the async request to finish in this spinlock
105
110
  # Requires pool_max to be 1
106
111
 
112
+ before(:all) do
113
+ @server = start_app_and_wait(TestApp)
114
+ end
115
+
116
+ after(:all) do
117
+ @server.shutdown # WEBrick::HTTPServer
118
+ TestApp.stop! rescue nil
119
+ end
120
+
107
121
  let(:port) { PORT }
108
122
  let(:event) {
109
123
  LogStash::Event.new({"message" => "hi"})
@@ -112,6 +126,44 @@ describe LogStash::Outputs::Http do
112
126
  let(:method) { "post" }
113
127
 
114
128
  shared_examples("verb behavior") do |method|
129
+
130
+ shared_examples("failure log behaviour") do
131
+ it "logs failure" do
132
+ expect(subject).to have_received(:log_failure).with(any_args)
133
+ end
134
+
135
+ it "does not log headers" do
136
+ expect(subject).to have_received(:log_failure).with(anything, hash_not_including(:headers))
137
+ end
138
+
139
+ it "does not log the message body" do
140
+ expect(subject).to have_received(:log_failure).with(anything, hash_not_including(:body))
141
+ end
142
+
143
+ context "with debug log level" do
144
+ before :all do
145
+ @current_log_level = LogStash::Logging::Logger.get_logging_context.get_root_logger.get_level.to_s.downcase
146
+ LogStash::Logging::Logger.configure_logging "debug"
147
+ end
148
+ after :all do
149
+ LogStash::Logging::Logger.configure_logging @current_log_level
150
+ end
151
+
152
+ it "logs a failure" do
153
+ expect(subject).to have_received(:log_failure).with(any_args)
154
+ end
155
+
156
+ it "logs headers" do
157
+ expect(subject).to have_received(:log_failure).with(anything, hash_including(:headers))
158
+ end
159
+
160
+ it "logs the body" do
161
+ expect(subject).to have_received(:log_failure).with(anything, hash_including(:body))
162
+ end
163
+ end
164
+
165
+ end
166
+
115
167
  let(:verb_behavior_config) { {"url" => url, "http_method" => method, "pool_max" => 1} }
116
168
  subject { LogStash::Outputs::Http.new(verb_behavior_config) }
117
169
 
@@ -199,44 +251,96 @@ describe LogStash::Outputs::Http do
199
251
  end
200
252
  end
201
253
 
202
- context "on exception" do
254
+ context "on retryable unknown exception" do
203
255
  before :each do
204
- allow(subject.client).to receive(:send).and_raise RuntimeError
256
+ raised = false
257
+ original_method = subject.client.method(:send)
258
+ allow(subject).to receive(:send_event).and_call_original
259
+ expect(subject.client).to receive(:send) do |*args|
260
+ unless raised
261
+ raised = true
262
+ raise ::Manticore::UnknownException.new("Read timed out")
263
+ end
264
+ original_method.call(args)
265
+ end
205
266
  subject.multi_receive([event])
206
267
  end
207
268
 
208
- it "should not log headers" do
209
- expect(subject).to have_received(:log_failure).with(anything, hash_not_including(:headers))
210
- end
269
+ include_examples("failure log behaviour")
211
270
 
212
- it "should not log the body" do
213
- expect(subject).to have_received(:log_failure).with(anything, hash_not_including(:body))
271
+ it "retries" do
272
+ expect(subject).to have_received(:send_event).exactly(2).times
214
273
  end
274
+ end
215
275
 
216
- context "with debug log level" do
217
- before :all do
218
- @current_log_level = LogStash::Logging::Logger.get_logging_context.get_root_logger.get_level.to_s.downcase
219
- LogStash::Logging::Logger.configure_logging "debug"
220
- end
221
- after :all do
222
- LogStash::Logging::Logger.configure_logging @current_log_level
276
+ context "on non-retryable unknown exception" do
277
+ before :each do
278
+ raised = false
279
+ original_method = subject.client.method(:send)
280
+ allow(subject).to receive(:send_event).and_call_original
281
+ expect(subject.client).to receive(:send) do |*args|
282
+ unless raised
283
+ raised = true
284
+ raise ::Manticore::UnknownException.new("broken")
285
+ end
286
+ original_method.call(args)
223
287
  end
288
+ subject.multi_receive([event])
289
+ end
224
290
 
225
- it "should log a failure" do
226
- expect(subject).to have_received(:log_failure).with(any_args)
227
- end
291
+ include_examples("failure log behaviour")
228
292
 
229
- it "should not log headers" do
230
- expect(subject).to have_received(:log_failure).with(anything, hash_including(:headers))
293
+ it "does not retry" do
294
+ expect(subject).to have_received(:send_event).exactly(1).times
295
+ end
296
+ end
297
+
298
+ context "on non-retryable exception" do
299
+ before :each do
300
+ raised = false
301
+ original_method = subject.client.method(:send)
302
+ allow(subject).to receive(:send_event).and_call_original
303
+ expect(subject.client).to receive(:send) do |*args|
304
+ unless raised
305
+ raised = true
306
+ raise RuntimeError.new("broken")
307
+ end
308
+ original_method.call(args)
231
309
  end
310
+ subject.multi_receive([event])
311
+ end
232
312
 
233
- it "should not log the body" do
234
- expect(subject).to have_received(:log_failure).with(anything, hash_including(:body))
313
+ include_examples("failure log behaviour")
314
+
315
+ it "does not retry" do
316
+ expect(subject).to have_received(:send_event).exactly(1).times
317
+ end
318
+ end
319
+
320
+ context "on retryable exception" do
321
+ before :each do
322
+ raised = false
323
+ original_method = subject.client.method(:send)
324
+ allow(subject).to receive(:send_event).and_call_original
325
+ expect(subject.client).to receive(:send) do |*args|
326
+ unless raised
327
+ raised = true
328
+ raise ::Manticore::Timeout.new("broken")
329
+ end
330
+ original_method.call(args)
235
331
  end
332
+ subject.multi_receive([event])
236
333
  end
334
+
335
+ it "retries" do
336
+ expect(subject).to have_received(:send_event).exactly(2).times
337
+ end
338
+
339
+ include_examples("failure log behaviour")
237
340
  end
238
341
  end
239
342
 
343
+
240
344
  LogStash::Outputs::Http::VALID_METHODS.each do |method|
241
345
  context "when using '#{method}'" do
242
346
  include_examples("verb behavior", method)
@@ -397,4 +501,93 @@ describe LogStash::Outputs::Http do
397
501
  let(:base_config) { { "http_compression" => true } }
398
502
  end
399
503
  end
504
+
505
+ describe "retryable error in termination" do
506
+ let(:url) { "http://localhost:#{port-1}/invalid" }
507
+ let(:events) { [event] }
508
+ let(:config) { {"url" => url, "http_method" => "get", "pool_max" => 1} }
509
+
510
+ subject { LogStash::Outputs::Http.new(config) }
511
+
512
+ before do
513
+ subject.register
514
+ allow(subject).to receive(:pipeline_shutdown_requested?).and_return(true)
515
+ end
516
+
517
+ it "raise exception to exit indefinitely retry" do
518
+ expect { subject.multi_receive(events) }.to raise_error(LogStash::Outputs::Http::PluginInternalQueueLeftoverError)
519
+ end
520
+ end
521
+ end
522
+
523
+ describe LogStash::Outputs::Http do # different block as we're starting web server with TLS
524
+
525
+ @@default_server_settings = TestApp.server_settings.dup
526
+
527
+ before do
528
+ cert, key = WEBrick::Utils.create_self_signed_cert 2048, [["CN", ssl_cert_host]], "Logstash testing"
529
+ TestApp.server_settings = @@default_server_settings.merge({
530
+ :SSLEnable => true,
531
+ :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
532
+ :SSLCertificate => cert,
533
+ :SSLPrivateKey => key
534
+ })
535
+
536
+ TestApp.last_request = nil
537
+
538
+ @server = start_app_and_wait(TestApp)
539
+ end
540
+
541
+ after do
542
+ @server.shutdown # WEBrick::HTTPServer
543
+
544
+ TestApp.stop! rescue nil
545
+ TestApp.server_settings = @@default_server_settings
546
+ end
547
+
548
+ let(:ssl_cert_host) { 'localhost' }
549
+
550
+ let(:port) { PORT }
551
+ let(:url) { "https://localhost:#{port}/good" }
552
+ let(:method) { "post" }
553
+
554
+ let(:config) { { "url" => url, "http_method" => method } }
555
+
556
+ subject { LogStash::Outputs::Http.new(config) }
557
+
558
+ before { subject.register }
559
+ after { subject.close }
560
+
561
+ let(:last_request) { TestApp.last_request }
562
+ let(:last_request_body) { last_request.body.read }
563
+
564
+ let(:event) { LogStash::Event.new("message" => "hello!") }
565
+
566
+ context 'with default (full) verification' do
567
+
568
+ let(:config) { super() } # 'ssl_verification_mode' => 'full'
569
+
570
+ it "does NOT process the request (due client protocol exception)" do
571
+ # Manticore's default verification does not accept self-signed certificates!
572
+ Thread.start do
573
+ subject.multi_receive [ event ]
574
+ end
575
+ sleep 1.5
576
+
577
+ expect(last_request).to be nil
578
+ end
579
+
580
+ end
581
+
582
+ context 'with verification disabled' do
583
+
584
+ let(:config) { super().merge 'ssl_verification_mode' => 'none' }
585
+
586
+ it "should process the request" do
587
+ subject.multi_receive [ event ]
588
+ expect(last_request_body).to include '"message":"hello!"'
589
+ end
590
+
591
+ end
592
+
400
593
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-output-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.5
4
+ version: 5.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-27 00:00:00.000000000 Z
11
+ date: 2022-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -35,7 +35,7 @@ dependencies:
35
35
  requirements:
36
36
  - - ">="
37
37
  - !ruby/object:Gem::Version
38
- version: 6.0.0
38
+ version: 7.1.0
39
39
  - - "<"
40
40
  - !ruby/object:Gem::Version
41
41
  version: 8.0.0
@@ -46,7 +46,7 @@ dependencies:
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 6.0.0
49
+ version: 7.1.0
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: 8.0.0
@@ -132,8 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
132
  - !ruby/object:Gem::Version
133
133
  version: '0'
134
134
  requirements: []
135
- rubyforge_project:
136
- rubygems_version: 2.6.13
135
+ rubygems_version: 3.1.6
137
136
  signing_key:
138
137
  specification_version: 4
139
138
  summary: Sends events to a generic HTTP or HTTPS endpoint