logstash-input-http 3.1.0-java → 3.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 445d3da2f390e8891b32e2090945f28677d6257018545983859c26665c21af84
4
- data.tar.gz: 585afff812773b166fd44370764bd0837958218dd994335da024216faf2cd352
3
+ metadata.gz: dd4ab63a8da778ab6b98669f405773f04defba698bef77a3430d0ea4eb778cf0
4
+ data.tar.gz: 8bc8d4d7909fa768424d63142198644bb97e6b8ea44bef779288267d48044052
5
5
  SHA512:
6
- metadata.gz: a9915f4e38147a0b97c2376b9fda49412b9c2aa995d2a6d5f4b5153a957b54baaa045375a0cbc8ef53d32cd3b1f97731729b73aee3b5cd34dbda4dfa468afc0d
7
- data.tar.gz: cf4d9aa38eda357bf7bba97c6f696221eaf2d09f990eb36ff9e1857c26f6fb96118905fc0e4aff16ce583476af9e095d9a0121e15884b7d34449e1d99cb36c1e
6
+ metadata.gz: 91ee9ad30eaf383efbf38b2f8a6720a3a9bba045ed7dda602734600dfa63b6d7c532bbee12b078a6c1444632e7edb3afe19569d72e9f2f4e94405092849d4a6c
7
+ data.tar.gz: b09f089df723d4240a6a89d8c78cb46c54a914784d8a15491604be7b31238c4f668044ea15f3cceb74e557f70678783ff0b4c9444ba8d61c56d55f0f8bd844c8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 3.2.0
2
+ - Add `request_headers_target_field` and `remote_host_target_field` configuration options with default to `host` and `headers` respectively #68
3
+ - Sanitize content-type header with getMimeType #87
4
+ - Move most message handling code to java #85
5
+ - Fix: respond with correct http protocol version #84
6
+
1
7
  ## 3.1.0
2
8
  - Replace Puma web server with Netty
3
9
  - Support crt/key certificates
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.0
1
+ 3.2.0
data/docs/index.asciidoc CHANGED
@@ -184,6 +184,22 @@ Persistent Queue for the logstash pipeline.
184
184
 
185
185
  specify a custom set of response headers
186
186
 
187
+ [id="plugins-{type}s-{plugin}-remote_host_target_field"]
188
+ ===== `remote_host_target_field`
189
+
190
+ * Value type is <<string,string>>
191
+ * Default value is `"host"`
192
+
193
+ specify a target field for the client host of the http request
194
+
195
+ [id="plugins-{type}s-{plugin}-request_headers_target_field"]
196
+ ===== `request_headers_target_field`
197
+
198
+ * Value type is <<string,string>>
199
+ * Default value is `"headers"`
200
+
201
+ specify target field for the client host of the http request
202
+
187
203
  [id="plugins-{type}s-{plugin}-ssl"]
188
204
  ===== `ssl`
189
205
 
@@ -4,4 +4,4 @@ require 'jar_dependencies'
4
4
  require_jar('io.netty', 'netty-all', '4.1.18.Final')
5
5
  require_jar('io.netty', 'netty-tcnative-boringssl-static', '2.0.7.Final')
6
6
  require_jar('org.apache.logging.log4j', 'log4j-api', '2.6.2')
7
- require_jar('org.logstash.plugins.input.http', 'logstash-input-http', '3.1.0')
7
+ require_jar('org.logstash.plugins.input.http', 'logstash-input-http', '3.2.0')
@@ -4,6 +4,8 @@ require "logstash/namespace"
4
4
  require "stud/interval"
5
5
  require "logstash-input-http_jars"
6
6
 
7
+ java_import "io.netty.handler.codec.http.HttpUtil"
8
+
7
9
  # Using this input you can receive single or multiline events over http(s).
8
10
  # Applications can send a HTTP POST request with a body to the endpoint started by this
9
11
  # input and Logstash will convert it into an event for subsequent processing. Users
@@ -101,6 +103,12 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base
101
103
  # specify a custom set of response headers
102
104
  config :response_headers, :validate => :hash, :default => { 'Content-Type' => 'text/plain' }
103
105
 
106
+ # target field for the client host of the http request
107
+ config :remote_host_target_field, :validate => :string, :default => "host"
108
+
109
+ # target field for the client host of the http request
110
+ config :request_headers_target_field, :validate => :string, :default => "headers"
111
+
104
112
  config :threads, :validate => :number, :required => false, :default => ::LogStash::Config::CpuCoreStrategy.maximum
105
113
 
106
114
  config :max_pending_requests, :validate => :number, :required => false, :default => 200
@@ -133,7 +141,7 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base
133
141
  end
134
142
 
135
143
  require "logstash/inputs/http/message_handler"
136
- message_handler = MessageHandler.new(self, @codec, @codecs)
144
+ message_handler = MessageHandler.new(self, @codec, @codecs, @auth_token)
137
145
  @http_server = create_http_server(message_handler)
138
146
  end # def register
139
147
 
@@ -151,23 +159,12 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base
151
159
  @http_server.close() rescue nil
152
160
  end
153
161
 
154
- def decode_body(remote_address, http_full_request, default_codec, additional_codecs)
155
- body = read_bytes(http_full_request.content)
156
- headers = {}
157
-
158
- http_full_request.headers.each do |header|
159
- headers[header.key.downcase.tr('-', '_')] = header.value
160
- end
161
- headers["request_method"] = http_full_request.getMethod.name
162
- headers["request_path"] = http_full_request.getUri
163
- headers["http_version"] = http_full_request.getProtocolVersion.text
164
- headers["http_accept"] = headers.delete("accept")
165
- headers["http_host"] = headers.delete("host")
166
- headers["http_user_agent"] = headers.delete("user_agent")
167
- codec = additional_codecs.fetch(headers["content_type"], default_codec)
162
+ def decode_body(headers, remote_address, body, default_codec, additional_codecs)
163
+ content_type = headers.fetch("content_type", "")
164
+ codec = additional_codecs.fetch(HttpUtil.getMimeType(content_type), default_codec)
168
165
  codec.decode(body) { |event| push_decoded_event(headers, remote_address, event) }
169
166
  codec.flush { |event| push_decoded_event(headers, remote_address, event) }
170
- [200, @response_headers, 'ok']
167
+ true
171
168
  rescue => e
172
169
  @logger.error(
173
170
  "unable to process event.",
@@ -175,31 +172,16 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base
175
172
  :class => e.class.name,
176
173
  :backtrace => e.backtrace
177
174
  )
178
- [500, @response_headers, 'internal error']
175
+ false
179
176
  end
180
177
 
181
178
  def push_decoded_event(headers, remote_address, event)
182
- event.set("headers", headers)
183
- event.set("host", remote_address)
179
+ event.set(@request_headers_target_field, headers)
180
+ event.set(@remote_host_target_field, remote_address)
184
181
  decorate(event)
185
182
  @queue << event
186
183
  end
187
184
 
188
- def valid_auth?(token)
189
- if @auth_token
190
- @auth_token == token
191
- else
192
- true
193
- end
194
- end
195
-
196
- private
197
- def read_bytes(bytebuffer)
198
- bytes = Java::byte[bytebuffer.readableBytes].new
199
- bytebuffer.getBytes(0, bytes)
200
- String.from_java_bytes(bytes, "ASCII-8BIT")
201
- end
202
-
203
185
  def validate_ssl_settings!
204
186
  if !@ssl
205
187
  @logger.warn("SSL Certificate will not be used") if @ssl_certificate
@@ -14,37 +14,27 @@ module LogStash module Inputs class Http
14
14
 
15
15
  attr_reader :input
16
16
 
17
- def initialize(input, default_codec, additional_codecs)
17
+ def initialize(input, default_codec, additional_codecs, auth_token)
18
18
  @input = input
19
19
  @default_codec = default_codec
20
20
  @additional_codecs = additional_codecs
21
+ @auth_token = auth_token
21
22
  end
22
23
 
23
- def onNewMessage(remote_address, message)
24
- if valid_auth?(message)
25
- message.headers.remove(HttpHeaderNames::AUTHORIZATION)
26
- status, headers, content = @input.decode_body(remote_address, message, @default_codec, @additional_codecs)
24
+ def validates_token(token)
25
+ if @auth_token
26
+ @auth_token == token
27
27
  else
28
- status, headers, content = 401, {}, 'failed to authenticate'
28
+ true
29
29
  end
30
- generate_response(status, headers, content)
31
30
  end
32
31
 
33
- private
34
- def generate_response(status, headers, content)
35
- payload = Unpooled.copiedBuffer(content.to_java_string, CharsetUtil::UTF_8)
36
- response = DefaultFullHttpResponse.new(
37
- HttpVersion::HTTP_1_1,
38
- HttpResponseStatus.valueOf(status),
39
- payload)
40
- response.headers().set(HttpHeaderNames::CONTENT_LENGTH, payload.readable_bytes());
41
- response.headers().set(HttpHeaderNames::CONTENT_TYPE, "text/plain");
42
- headers.each { |k, v| response.headers().set(k, v) }
43
- response
32
+ def onNewMessage(remote_address, headers, body)
33
+ @input.decode_body(headers, remote_address, body, @default_codec, @additional_codecs)
44
34
  end
45
35
 
46
36
  def copy
47
- MessageHandler.new(@input, @default_codec.clone, clone_additional_codecs())
37
+ MessageHandler.new(@input, @default_codec.clone, clone_additional_codecs(), @auth_token)
48
38
  end
49
39
 
50
40
  def clone_additional_codecs
@@ -55,8 +45,8 @@ module LogStash module Inputs class Http
55
45
  clone_additional_codecs
56
46
  end
57
47
 
58
- def valid_auth?(message)
59
- @input.valid_auth?(message.headers.get(HttpHeaderNames::AUTHORIZATION))
48
+ def response_headers
49
+ @input.response_headers
60
50
  end
61
51
  end
62
52
  end; end; end
@@ -29,6 +29,7 @@ describe LogStash::Inputs::Http do
29
29
 
30
30
  describe "request handling" do
31
31
  subject { LogStash::Inputs::Http.new("port" => port) }
32
+
32
33
  before :each do
33
34
  subject.register
34
35
  t = Thread.new { subject.run(logstash_queue) }
@@ -81,6 +82,57 @@ describe LogStash::Inputs::Http do
81
82
  end
82
83
  end
83
84
 
85
+ describe "remote host" do
86
+ subject { LogStash::Inputs::Http.new(config.merge("port" => port)) }
87
+ context "by default" do
88
+ let(:config) { {} }
89
+ it "is written to the \"host\" field" do
90
+ client.post("http://localhost:#{port}/meh.json",
91
+ :headers => { "content-type" => "text/plain" },
92
+ :body => "hello").call
93
+ event = logstash_queue.pop
94
+ expect(event.get("host")).to eq("127.0.0.1")
95
+ end
96
+ end
97
+
98
+ context "when using remote_host_target_field" do
99
+ let(:config) { { "remote_host_target_field" => "remote_host" } }
100
+ it "is written to the value of \"remote_host_target_field\" property" do
101
+ client.post("http://localhost:#{port}/meh.json",
102
+ :headers => { "content-type" => "text/plain" },
103
+ :body => "hello").call
104
+ event = logstash_queue.pop
105
+ expect(event.get("remote_host")).to eq("127.0.0.1")
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "request headers" do
111
+ subject { LogStash::Inputs::Http.new(config.merge("port" => port)) }
112
+ context "by default" do
113
+ let(:config) { {} }
114
+ it "are written to the \"headers\" field" do
115
+ client.post("http://localhost:#{port}/meh.json",
116
+ :headers => { "content-type" => "text/plain" },
117
+ :body => "hello").call
118
+ event = logstash_queue.pop
119
+ expect(event.get("headers")).to be_a(Hash)
120
+ expect(event.get("headers")).to include("request_method" => "POST")
121
+ end
122
+ end
123
+ context "when using request_headers_target_field" do
124
+ let(:config) { { "request_headers_target_field" => "request_headers" } }
125
+ it "are written to the field set in \"request_headers_target_field\"" do
126
+ client.post("http://localhost:#{port}/meh.json",
127
+ :headers => { "content-type" => "text/plain" },
128
+ :body => "hello").call
129
+ event = logstash_queue.pop
130
+ expect(event.get("request_headers")).to be_a(Hash)
131
+ expect(event.get("request_headers")).to include("request_method" => "POST")
132
+ end
133
+ end
134
+ end
135
+
84
136
  it "should include remote host in \"host\" property" do
85
137
  client.post("http://127.0.0.1:#{port}/meh.json",
86
138
  :headers => { "content-type" => "text/plain" },
@@ -190,6 +242,19 @@ describe LogStash::Inputs::Http do
190
242
  expect(event.get("message")).to eq(body)
191
243
  end
192
244
  end
245
+
246
+ context "when receiving a content-type with a charset" do
247
+ subject { LogStash::Inputs::Http.new("port" => port,
248
+ "additional_codecs" => { "application/json" => "plain" }) }
249
+ it "should decode the message accordingly" do
250
+ body = { "message" => "Hello" }.to_json
251
+ client.post("http://127.0.0.1:#{port}/meh.json",
252
+ :headers => { "content-type" => "application/json; charset=utf-8" },
253
+ :body => body).call
254
+ event = logstash_queue.pop
255
+ expect(event.get("message")).to eq(body)
256
+ end
257
+ end
193
258
 
194
259
  context "when using custom headers" do
195
260
  let(:custom_headers) { { 'access-control-allow-origin' => '*' } }
@@ -197,7 +262,7 @@ describe LogStash::Inputs::Http do
197
262
 
198
263
  describe "the response" do
199
264
  it "should include the custom headers" do
200
- response = client.post("http://127.0.0.1:#{port}/meh", :body => "hello")
265
+ response = client.post("http://127.0.0.1:#{port}/meh", :body => "hello").call
201
266
  expect(response.headers.to_hash).to include(custom_headers)
202
267
  end
203
268
  end
@@ -248,6 +313,32 @@ describe LogStash::Inputs::Http do
248
313
  end
249
314
  end
250
315
 
316
+ describe "HTTP Protocol Handling" do
317
+ context "when an HTTP1.1 request is made" do
318
+ let(:protocol_version) do
319
+ Java::OrgApacheHttp::HttpVersion::HTTP_1_1
320
+ end
321
+ it "responds with a HTTP1.1 response" do
322
+ response = client.post("http://127.0.0.1:#{port}", :body => "hello")
323
+ response.request.set_protocol_version(protocol_version)
324
+ response.call
325
+ response_protocol_version = response.instance_variable_get(:@response).get_protocol_version
326
+ expect(response_protocol_version).to eq(protocol_version)
327
+ end
328
+ end
329
+ context "when an HTTP1.0 request is made" do
330
+ let(:protocol_version) do
331
+ Java::OrgApacheHttp::HttpVersion::HTTP_1_0
332
+ end
333
+ it "responds with a HTTP1.0 response" do
334
+ response = client.post("http://127.0.0.1:#{port}", :body => "hello")
335
+ response.request.set_protocol_version(protocol_version)
336
+ response.call
337
+ response_protocol_version = response.instance_variable_get(:@response).get_protocol_version
338
+ expect(response_protocol_version).to eq(protocol_version)
339
+ end
340
+ end
341
+ end
251
342
  end
252
343
 
253
344
  context "with :ssl => false" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.0
5
5
  platform: java
6
6
  authors:
7
7
  - Elastic
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-26 00:00:00.000000000 Z
11
+ date: 2018-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -141,7 +141,7 @@ files:
141
141
  - vendor/jar-dependencies/io/netty/netty-all/4.1.18.Final/netty-all-4.1.18.Final.jar
142
142
  - vendor/jar-dependencies/io/netty/netty-tcnative-boringssl-static/2.0.7.Final/netty-tcnative-boringssl-static-2.0.7.Final.jar
143
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
144
+ - vendor/jar-dependencies/org/logstash/plugins/input/http/logstash-input-http/3.2.0/logstash-input-http-3.2.0.jar
145
145
  homepage: http://www.elastic.co/guide/en/logstash/current/index.html
146
146
  licenses:
147
147
  - Apache License (2.0)
@@ -165,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
165
  version: '0'
166
166
  requirements: []
167
167
  rubyforge_project:
168
- rubygems_version: 2.6.11
168
+ rubygems_version: 2.6.13
169
169
  signing_key:
170
170
  specification_version: 4
171
171
  summary: Receives events over HTTP or HTTPS