logstash-input-http 3.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -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