logstash-input-http 3.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,33 @@
1
+ HTTP_INPUT_VERSION = File.read(File.expand_path(File.join(File.dirname(__FILE__), "VERSION"))).strip unless defined?(HTTP_INPUT_VERSION)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'logstash-input-http'
5
+ s.version = HTTP_INPUT_VERSION
6
+ s.licenses = ['Apache License (2.0)']
7
+ s.summary = "Receives events over HTTP or HTTPS"
8
+ 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"
9
+ s.authors = ["Elastic"]
10
+ s.email = 'info@elastic.co'
11
+ s.homepage = "http://www.elastic.co/guide/en/logstash/current/index.html"
12
+ s.require_paths = ["lib", "vendor/jar-dependencies"]
13
+
14
+ # Files
15
+ s.files = Dir["lib/**/*","spec/**/*","*.gemspec","*.md","CONTRIBUTORS","Gemfile","LICENSE","NOTICE.TXT", "vendor/jar-dependencies/**/*.jar", "vendor/jar-dependencies/**/*.rb", "VERSION", "docs/**/*"]
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency "logstash-core-plugin-api", ">= 1.60", "<= 2.99"
24
+ s.add_runtime_dependency 'logstash-codec-plain'
25
+ s.add_runtime_dependency 'jar-dependencies', '~> 0.3.4'
26
+
27
+ s.add_development_dependency 'logstash-devutils'
28
+ s.add_development_dependency 'logstash-codec-json'
29
+ s.add_development_dependency 'logstash-codec-json_lines'
30
+ s.add_development_dependency 'manticore'
31
+
32
+ s.platform = "java"
33
+ end
@@ -0,0 +1,277 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require "logstash/inputs/http"
3
+ require "json"
4
+ require "manticore"
5
+ require "stud/temporary"
6
+ require "zlib"
7
+ require "stringio"
8
+
9
+ describe LogStash::Inputs::Http do
10
+
11
+ before do
12
+ srand(RSpec.configuration.seed)
13
+ end
14
+
15
+ let(:client) { Manticore::Client.new(client_options) }
16
+ let(:client_options) { { } }
17
+ let(:logstash_queue) { Queue.new }
18
+ let(:port) { rand(5000) + 1025 }
19
+
20
+ it_behaves_like "an interruptible input plugin" do
21
+ let(:config) { { "port" => port } }
22
+ end
23
+
24
+ after :each do
25
+ client.clear_pending
26
+ client.close
27
+ subject.stop
28
+ end
29
+
30
+ describe "request handling" do
31
+ subject { LogStash::Inputs::Http.new("port" => port) }
32
+ before :each do
33
+ subject.register
34
+ t = Thread.new { subject.run(logstash_queue) }
35
+ ok = false
36
+ until ok
37
+ begin
38
+ client.post("http://127.0.0.1:#{port}", :body => '{}').call
39
+ rescue => e
40
+ # retry
41
+ else
42
+ ok = true
43
+ end
44
+ sleep 0.01
45
+ end
46
+ logstash_queue.pop if logstash_queue.size == 1 # pop test event
47
+ end
48
+
49
+ describe "handling overflowing requests with a 429" do
50
+ let(:logstash_queue_size) { rand(10) + 1 }
51
+ let(:max_pending_requests) { rand(5) + 1 }
52
+ let(:threads) { rand(4) + 1 }
53
+ let(:logstash_queue) { SizedQueue.new(logstash_queue_size) }
54
+ let(:client_options) { {
55
+ "request_timeout" => 0.1,
56
+ "connect_timeout" => 3,
57
+ "socket_timeout" => 0.1
58
+ } }
59
+
60
+ subject { described_class.new("port" => port, "threads" => threads, "max_pending_requests" => max_pending_requests) }
61
+
62
+ context "when sending more requests than queue slots" do
63
+ it "should block when the queue is full" do
64
+ # these will queue and return 200
65
+ logstash_queue_size.times.each do |i|
66
+ response = client.post("http://127.0.0.1:#{port}", :body => '{}').call
67
+ expect(response.code).to eq(200)
68
+ end
69
+
70
+ # these will block
71
+ (threads + max_pending_requests).times.each do |i|
72
+ expect {
73
+ client.post("http://127.0.0.1:#{port}", :body => '{}').call
74
+ }.to raise_error(Manticore::SocketTimeout)
75
+ end
76
+
77
+ # by now we should be rejecting with 429
78
+ response = client.post("http://127.0.0.1:#{port}", :body => '{}').call
79
+ expect(response.code).to eq(429)
80
+ end
81
+ end
82
+ end
83
+
84
+ it "should include remote host in \"host\" property" do
85
+ client.post("http://127.0.0.1:#{port}/meh.json",
86
+ :headers => { "content-type" => "text/plain" },
87
+ :body => "hello").call
88
+ event = logstash_queue.pop
89
+ expect(event.get("host")).to eq("127.0.0.1")
90
+ end
91
+
92
+ context "with default codec" do
93
+ subject { LogStash::Inputs::Http.new("port" => port) }
94
+ context "when receiving a text/plain request" do
95
+ it "should process the request normally" do
96
+ client.post("http://127.0.0.1:#{port}/meh.json",
97
+ :headers => { "content-type" => "text/plain" },
98
+ :body => "hello").call
99
+ event = logstash_queue.pop
100
+ expect(event.get("message")).to eq("hello")
101
+ end
102
+ end
103
+ context "when receiving a deflate compressed text/plain request" do
104
+ it "should process the request normally" do
105
+ client.post("http://127.0.0.1:#{port}/meh.json",
106
+ :headers => { "content-type" => "text/plain", "content-encoding" => "deflate" },
107
+ :body => Zlib::Deflate.deflate("hello")).call
108
+ event = logstash_queue.pop
109
+ expect(event.get("message")).to eq("hello")
110
+ end
111
+ end
112
+ context "when receiving a deflate text/plain request that cannot be decompressed" do
113
+ let(:response) do
114
+ response = client.post("http://127.0.0.1:#{port}/meh.json",
115
+ :headers => { "content-type" => "text/plain", "content-encoding" => "deflate" },
116
+ :body => "hello").call
117
+ end
118
+ it "should respond with 400" do
119
+ expect(response.code).to eq(400)
120
+ end
121
+ end
122
+ context "when receiving a gzip compressed text/plain request" do
123
+ it "should process the request normally" do
124
+ wio = StringIO.new("w")
125
+ z = Zlib::GzipWriter.new(wio)
126
+ z.write("hello")
127
+ z.close
128
+ entity = org.apache.http.entity.ByteArrayEntity.new(wio.string.to_java_bytes)
129
+ response = client.post("http://127.0.0.1:#{port}",
130
+ :headers => { "Content-Encoding" => "gzip" },
131
+ :entity => entity).call
132
+ expect(response.code).to eq(200)
133
+ event = logstash_queue.pop
134
+ expect(event.get("message")).to eq("hello")
135
+ end
136
+ end
137
+ context "when receiving a gzip text/plain request that cannot be decompressed" do
138
+ let(:response) do
139
+ client.post("http://127.0.0.1:#{port}",
140
+ :headers => { "Content-Encoding" => "gzip" },
141
+ :body => Zlib::Deflate.deflate("hello")).call
142
+ end
143
+ it "should respond with 400" do
144
+ expect(response.code).to eq(400)
145
+ end
146
+ end
147
+ context "when receiving an application/json request" do
148
+ it "should parse the json body" do
149
+ client.post("http://127.0.0.1:#{port}/meh.json",
150
+ :headers => { "content-type" => "application/json" },
151
+ :body => { "message_body" => "Hello" }.to_json).call
152
+ event = logstash_queue.pop
153
+ expect(event.get("message_body")).to eq("Hello")
154
+ end
155
+ end
156
+ end
157
+
158
+ context "with json codec" do
159
+ subject { LogStash::Inputs::Http.new("port" => port, "codec" => "json") }
160
+ it "should parse the json body" do
161
+ response = client.post("http://127.0.0.1:#{port}/meh.json", :body => { "message" => "Hello" }.to_json).call
162
+ event = logstash_queue.pop
163
+ expect(event.get("message")).to eq("Hello")
164
+ end
165
+ end
166
+
167
+ context "with json_lines codec without final delimiter" do
168
+ subject { LogStash::Inputs::Http.new("port" => port, "codec" => "json_lines") }
169
+ let(:line1) { '{"foo": 1}' }
170
+ let(:line2) { '{"foo": 2}' }
171
+ it "should parse all json_lines in body including last one" do
172
+ client.post("http://localhost:#{port}/meh.json", :body => "#{line1}\n#{line2}").call
173
+ expect(logstash_queue.size).to eq(2)
174
+ event = logstash_queue.pop
175
+ expect(event.get("foo")).to eq(1)
176
+ event = logstash_queue.pop
177
+ expect(event.get("foo")).to eq(2)
178
+ end
179
+ end
180
+
181
+ context "when using a custom codec mapping" do
182
+ subject { LogStash::Inputs::Http.new("port" => port,
183
+ "additional_codecs" => { "application/json" => "plain" }) }
184
+ it "should decode the message accordingly" do
185
+ body = { "message" => "Hello" }.to_json
186
+ client.post("http://127.0.0.1:#{port}/meh.json",
187
+ :headers => { "content-type" => "application/json" },
188
+ :body => body).call
189
+ event = logstash_queue.pop
190
+ expect(event.get("message")).to eq(body)
191
+ end
192
+ end
193
+
194
+ context "when using custom headers" do
195
+ let(:custom_headers) { { 'access-control-allow-origin' => '*' } }
196
+ subject { LogStash::Inputs::Http.new("port" => port, "response_headers" => custom_headers) }
197
+
198
+ describe "the response" do
199
+ it "should include the custom headers" do
200
+ response = client.post("http://127.0.0.1:#{port}/meh", :body => "hello")
201
+ expect(response.headers.to_hash).to include(custom_headers)
202
+ end
203
+ end
204
+ end
205
+ describe "basic auth" do
206
+ user = "test"; password = "pwd"
207
+ subject { LogStash::Inputs::Http.new("port" => port, "user" => user, "password" => password) }
208
+ let(:auth_token) { Base64.strict_encode64("#{user}:#{password}") }
209
+ context "when client doesn't present auth token" do
210
+ let!(:response) { client.post("http://127.0.0.1:#{port}/meh", :body => "hi").call }
211
+ it "should respond with 401" do
212
+ expect(response.code).to eq(401)
213
+ end
214
+ it "should not generate an event" do
215
+ expect(logstash_queue).to be_empty
216
+ end
217
+ end
218
+ context "when client presents incorrect auth token" do
219
+ let!(:response) do
220
+ client.post("http://127.0.0.1:#{port}/meh",
221
+ :headers => {
222
+ "content-type" => "text/plain",
223
+ "authorization" => "Basic meh"
224
+ },
225
+ :body => "hi").call
226
+ end
227
+ it "should respond with 401" do
228
+ expect(response.code).to eq(401)
229
+ end
230
+ it "should not generate an event" do
231
+ expect(logstash_queue).to be_empty
232
+ end
233
+ end
234
+ context "when client presents correct auth token" do
235
+ let!(:response) do
236
+ client.post("http://127.0.0.1:#{port}/meh",
237
+ :headers => {
238
+ "content-type" => "text/plain",
239
+ "authorization" => "Basic #{auth_token}"
240
+ }, :body => "hi").call
241
+ end
242
+ it "should respond with 200" do
243
+ expect(response.code).to eq(200)
244
+ end
245
+ it "should generate an event" do
246
+ expect(logstash_queue).to_not be_empty
247
+ end
248
+ end
249
+ end
250
+
251
+ end
252
+
253
+ context "with :ssl => false" do
254
+ subject { LogStash::Inputs::Http.new("port" => port, "ssl" => false) }
255
+ it "should not raise exception" do
256
+ expect { subject.register }.to_not raise_exception
257
+ end
258
+ end
259
+ context "with :ssl => true" do
260
+ context "without :ssl_certificate" do
261
+ subject { LogStash::Inputs::Http.new("port" => port, "ssl" => true) }
262
+ it "should raise exception" do
263
+ expect { subject.register }.to raise_exception(LogStash::ConfigurationError)
264
+ end
265
+ end
266
+ context "with :ssl_certificate" do
267
+ let(:ssl_certificate) { Stud::Temporary.file }
268
+ let(:ssl_key) { Stud::Temporary.file }
269
+ subject { LogStash::Inputs::Http.new("port" => port, "ssl" => true,
270
+ "ssl_certificate" => ssl_certificate.path,
271
+ "ssl_key" => ssl_key.path) }
272
+ it "should not raise exception" do
273
+ expect { subject.register }.to_not raise_exception
274
+ end
275
+ end
276
+ end
277
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-input-http
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.1.0
5
+ platform: java
6
+ authors:
7
+ - Elastic
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.60'
19
+ - - "<="
20
+ - !ruby/object:Gem::Version
21
+ version: '2.99'
22
+ name: logstash-core-plugin-api
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.60'
30
+ - - "<="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.99'
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ name: logstash-codec-plain
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: 0.3.4
53
+ name: jar-dependencies
54
+ prerelease: false
55
+ type: :runtime
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.3.4
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ name: logstash-devutils
68
+ prerelease: false
69
+ type: :development
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ name: logstash-codec-json
82
+ prerelease: false
83
+ type: :development
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ name: logstash-codec-json_lines
96
+ prerelease: false
97
+ type: :development
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ name: manticore
110
+ prerelease: false
111
+ type: :development
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ description: This gem is a Logstash plugin required to be installed on top of the
118
+ Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This
119
+ gem is not a stand-alone program
120
+ email: info@elastic.co
121
+ executables: []
122
+ extensions: []
123
+ extra_rdoc_files: []
124
+ files:
125
+ - CHANGELOG.md
126
+ - DEVELOPER.md
127
+ - Gemfile
128
+ - LICENSE
129
+ - NOTICE.TXT
130
+ - README.md
131
+ - VERSION
132
+ - docs/index.asciidoc
133
+ - lib/logstash-input-http_jars.rb
134
+ - lib/logstash/inputs/http.rb
135
+ - lib/logstash/inputs/http/message_handler.rb
136
+ - lib/logstash/inputs/http/tls.rb
137
+ - lib/logstash/util/http_compressed_requests.rb
138
+ - lib/tasks/build.rake
139
+ - logstash-input-http.gemspec
140
+ - spec/inputs/http_spec.rb
141
+ - vendor/jar-dependencies/io/netty/netty-all/4.1.18.Final/netty-all-4.1.18.Final.jar
142
+ - vendor/jar-dependencies/io/netty/netty-tcnative-boringssl-static/2.0.7.Final/netty-tcnative-boringssl-static-2.0.7.Final.jar
143
+ - vendor/jar-dependencies/org/apache/logging/log4j/log4j-api/2.6.2/log4j-api-2.6.2.jar
144
+ - vendor/jar-dependencies/org/logstash/plugins/input/http/logstash-input-http/3.1.0/logstash-input-http-3.1.0.jar
145
+ homepage: http://www.elastic.co/guide/en/logstash/current/index.html
146
+ licenses:
147
+ - Apache License (2.0)
148
+ metadata:
149
+ logstash_plugin: 'true'
150
+ logstash_group: input
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ - vendor/jar-dependencies
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubyforge_project:
168
+ rubygems_version: 2.6.11
169
+ signing_key:
170
+ specification_version: 4
171
+ summary: Receives events over HTTP or HTTPS
172
+ test_files:
173
+ - spec/inputs/http_spec.rb