logstash-input-akamai-siem 1.0.0

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,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LogStash::Inputs::AkamaiSiem::Headers < ::Hash
4
+ def self.from(value)
5
+ new(value)
6
+ end
7
+
8
+ def self.allocate
9
+ new_self = super
10
+ new_self.initialize_names
11
+ new_self
12
+ end
13
+
14
+ def initialize(hash = nil)
15
+ super()
16
+ @names = {}
17
+ update(hash || {})
18
+ end
19
+
20
+ def initialize_names
21
+ @names = {}
22
+ end
23
+
24
+ # on dup/clone, we need to duplicate @names hash
25
+ def initialize_copy(other)
26
+ super
27
+ @names = other.names.dup
28
+ end
29
+
30
+ # need to synchronize concurrent writes to the shared KeyMap
31
+ keymap_mutex = Mutex.new
32
+
33
+ # symbol -> string mapper + cache
34
+ KeyMap = Hash.new do |map, key|
35
+ value = if key.respond_to?(:to_str)
36
+ key
37
+ else
38
+ key.to_s.split('_') # user_agent: %w(user agent)
39
+ .each(&:capitalize!) # => %w(User Agent)
40
+ .join('-') # => "User-Agent"
41
+ end
42
+ keymap_mutex.synchronize { map[key] = value }
43
+ end
44
+ KeyMap[:etag] = 'ETag'
45
+
46
+ def [](key)
47
+ key = KeyMap[key]
48
+ super(key) || super(@names[key.downcase])
49
+ end
50
+
51
+ def []=(key, val)
52
+ key = KeyMap[key]
53
+ key = (@names[key.downcase] ||= key)
54
+ # join multiple values with a comma
55
+ val = val.to_ary.join(', ') if val.respond_to?(:to_ary)
56
+ super(key, val)
57
+ end
58
+
59
+ def fetch(key, ...)
60
+ key = KeyMap[key]
61
+ key = @names.fetch(key.downcase, key)
62
+ super(key, ...)
63
+ end
64
+
65
+ def delete(key)
66
+ key = KeyMap[key]
67
+ key = @names[key.downcase]
68
+ return unless key
69
+
70
+ @names.delete key.downcase
71
+ super(key)
72
+ end
73
+
74
+ def dig(key, *rest)
75
+ key = KeyMap[key]
76
+ key = @names.fetch(key.downcase, key)
77
+ super(key, *rest)
78
+ end
79
+
80
+ def include?(key)
81
+ @names.include? key.downcase
82
+ end
83
+
84
+ alias has_key? include?
85
+ alias member? include?
86
+ alias key? include?
87
+
88
+ def merge!(other)
89
+ other.each { |k, v| self[k] = v }
90
+ self
91
+ end
92
+
93
+ alias update merge!
94
+
95
+ def merge(other)
96
+ hash = dup
97
+ hash.merge! other
98
+ end
99
+
100
+ def replace(other)
101
+ clear
102
+ @names.clear
103
+ update other
104
+ self
105
+ end
106
+
107
+ def to_hash
108
+ {}.update(self)
109
+ end
110
+
111
+ def parse(header_string)
112
+ return unless header_string && !header_string.empty?
113
+
114
+ headers = header_string.split("\r\n")
115
+
116
+ # Find the last set of response headers.
117
+ start_index = headers.rindex { |x| x.start_with?('HTTP/') } || 0
118
+ last_response = headers.slice(start_index, headers.size)
119
+
120
+ last_response
121
+ .tap { |a| a.shift if a.first.start_with?('HTTP/') }
122
+ .map { |h| h.split(/:\s*/, 2) } # split key and value
123
+ .reject { |p| p[0].nil? } # ignore blank lines
124
+ .each { |key, value| add_parsed(key, value) }
125
+ end
126
+
127
+ protected
128
+
129
+ attr_reader :names
130
+
131
+ private
132
+
133
+ # Join multiple values with a comma.
134
+ def add_parsed(key, value)
135
+ if key?(key)
136
+ self[key] = self[key].to_s
137
+ self[key] << ', ' << value
138
+ else
139
+ self[key] = value
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'monitor'
4
+
5
+ module LogStash::Inputs::AkamaiSiem::MiddlewareRegistry
6
+ # Adds the ability for other modules to register and lookup
7
+ # middleware classes.
8
+ def registered_middleware
9
+ @registered_middleware ||= {}
10
+ end
11
+
12
+ # Register middleware class(es) on the current module.
13
+ #
14
+ # @param mappings [Hash] Middleware mappings from a lookup symbol to a middleware class.
15
+ # @return [void]
16
+ #
17
+ # @example Lookup by a constant
18
+ #
19
+ # module Faraday
20
+ # class Whatever < Middleware
21
+ # # Middleware looked up by :foo returns Faraday::Whatever::Foo.
22
+ # register_middleware(foo: Whatever)
23
+ # end
24
+ # end
25
+ def register_middleware(**mappings)
26
+ middleware_mutex do
27
+ registered_middleware.update(mappings)
28
+ end
29
+ end
30
+
31
+ # Unregister a previously registered middleware class.
32
+ #
33
+ # @param key [Symbol] key for the registered middleware.
34
+ def unregister_middleware(key)
35
+ registered_middleware.delete(key)
36
+ end
37
+
38
+ # Lookup middleware class with a registered Symbol shortcut.
39
+ #
40
+ # @param key [Symbol] key for the registered middleware.
41
+ # @return [Class] a middleware Class.
42
+ # @raise [Faraday::Error] if given key is not registered
43
+ #
44
+ # @example
45
+ #
46
+ # module Faraday
47
+ # class Whatever < Middleware
48
+ # register_middleware(foo: Whatever)
49
+ # end
50
+ # end
51
+ #
52
+ # Faraday::Middleware.lookup_middleware(:foo)
53
+ # # => Faraday::Whatever
54
+ def lookup_middleware(key)
55
+ load_middleware(key) ||
56
+ raise(Faraday::Error, "#{key.inspect} is not registered on #{self}")
57
+ end
58
+
59
+ private
60
+
61
+ def middleware_mutex(&block)
62
+ @middleware_mutex ||= Monitor.new
63
+ @middleware_mutex.synchronize(&block)
64
+ end
65
+
66
+ def load_middleware(key)
67
+ value = registered_middleware[key]
68
+ case value
69
+ when Module
70
+ value
71
+ when Symbol, String
72
+ middleware_mutex do
73
+ @registered_middleware[key] = const_get(value)
74
+ end
75
+ when Proc
76
+ middleware_mutex do
77
+ @registered_middleware[key] = value.call
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LogStash::Inputs::AkamaiSiem
4
+ Request = Struct.new(:http_method, :path, :headers, :body, :host, :url) do
5
+ extend MiddlewareRegistry
6
+ alias_method :member_get, :[]
7
+ private :member_get
8
+ alias_method :member_set, :[]=
9
+ private :member_set
10
+
11
+ # @param request_method [String]
12
+ # @yield [request] for block customization, if block given
13
+ # @yieldparam request [Request]
14
+ # @return [Request]
15
+ def self.create(request_method)
16
+ new(request_method).tap do |request|
17
+ yield(request) if block_given?
18
+ end
19
+ end
20
+
21
+ remove_method :headers=
22
+ # Replace request headers, preserving the existing hash type.
23
+ #
24
+ # @param hash [Hash] new headers
25
+ def headers=(hash)
26
+ if headers
27
+ headers.replace hash
28
+ else
29
+ member_set(:headers, hash)
30
+ end
31
+ end
32
+
33
+ def update_uri(url)
34
+ if url.respond_to? :query
35
+ if (query = url.query)
36
+ path = url.path = Addressable::URI.unencode(url.path.dup.gsub(/\/$/, ''))
37
+ end
38
+ else
39
+ anchor_index = path.index('#')
40
+ path = path.slice(0, anchor_index) unless anchor_index.nil?
41
+ path, query = path.split('?', 2)
42
+ end
43
+ self.host = url.host
44
+ self.path = path
45
+ self.url = url
46
+ end
47
+
48
+ # @param key [Object] key to look up in headers
49
+ # @return [Object] value of the given header name
50
+ def [](key)
51
+ headers[key]
52
+ end
53
+
54
+ # @param key [Object] key of header to write
55
+ # @param value [Object] value of header
56
+ def []=(key, value)
57
+ headers[key] = value
58
+ end
59
+
60
+ def to_a
61
+ [
62
+ self.http_method,
63
+ self.url.to_s,
64
+ headers: self.headers
65
+ ]
66
+ end
67
+
68
+ # Marshal serialization support.
69
+ #
70
+ # @return [Hash] the hash ready to be serialized in Marshal.
71
+ def marshal_dump
72
+ {
73
+ http_method: http_method,
74
+ body: body,
75
+ headers: headers,
76
+ path: path,
77
+ host: host
78
+ }
79
+ end
80
+
81
+ # Marshal serialization support.
82
+ # Restores the instance variables according to the +serialised+.
83
+ # @param serialised [Hash] the serialised object.
84
+ def marshal_load(serialised)
85
+ self.http_method = serialised[:http_method]
86
+ self.body = serialised[:body]
87
+ self.headers = serialised[:headers]
88
+ self.path = serialised[:path]
89
+ self.host = serialised[:host]
90
+ end
91
+ end
92
+ end