hoss-agent 1.0.1

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.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/Bug_report.md +40 -0
  3. data/.github/ISSUE_TEMPLATE/Feature_request.md +17 -0
  4. data/.github/PULL_REQUEST_TEMPLATE.md +60 -0
  5. data/.gitignore +27 -0
  6. data/.rspec +2 -0
  7. data/Dockerfile +43 -0
  8. data/Gemfile +105 -0
  9. data/LICENSE +201 -0
  10. data/hoss-agent.gemspec +42 -0
  11. data/lib/hoss/agent.rb +231 -0
  12. data/lib/hoss/central_config/cache_control.rb +51 -0
  13. data/lib/hoss/central_config.rb +184 -0
  14. data/lib/hoss/child_durations.rb +64 -0
  15. data/lib/hoss/config/bytes.rb +42 -0
  16. data/lib/hoss/config/duration.rb +40 -0
  17. data/lib/hoss/config/options.rb +154 -0
  18. data/lib/hoss/config/regexp_list.rb +30 -0
  19. data/lib/hoss/config/wildcard_pattern_list.rb +54 -0
  20. data/lib/hoss/config.rb +304 -0
  21. data/lib/hoss/context/request/socket.rb +36 -0
  22. data/lib/hoss/context/request/url.rb +59 -0
  23. data/lib/hoss/context/request.rb +28 -0
  24. data/lib/hoss/context/response.rb +47 -0
  25. data/lib/hoss/context/user.rb +59 -0
  26. data/lib/hoss/context.rb +64 -0
  27. data/lib/hoss/context_builder.rb +112 -0
  28. data/lib/hoss/deprecations.rb +39 -0
  29. data/lib/hoss/error/exception.rb +70 -0
  30. data/lib/hoss/error/log.rb +41 -0
  31. data/lib/hoss/error.rb +49 -0
  32. data/lib/hoss/error_builder.rb +90 -0
  33. data/lib/hoss/event.rb +131 -0
  34. data/lib/hoss/instrumenter.rb +107 -0
  35. data/lib/hoss/internal_error.rb +23 -0
  36. data/lib/hoss/logging.rb +70 -0
  37. data/lib/hoss/metadata/process_info.rb +35 -0
  38. data/lib/hoss/metadata/service_info.rb +76 -0
  39. data/lib/hoss/metadata/system_info/container_info.rb +136 -0
  40. data/lib/hoss/metadata/system_info.rb +47 -0
  41. data/lib/hoss/metadata.rb +36 -0
  42. data/lib/hoss/naively_hashable.rb +38 -0
  43. data/lib/hoss/rails.rb +68 -0
  44. data/lib/hoss/railtie.rb +42 -0
  45. data/lib/hoss/report.rb +9 -0
  46. data/lib/hoss/sinatra.rb +53 -0
  47. data/lib/hoss/spies/faraday.rb +102 -0
  48. data/lib/hoss/spies/http.rb +81 -0
  49. data/lib/hoss/spies/net_http.rb +97 -0
  50. data/lib/hoss/spies.rb +104 -0
  51. data/lib/hoss/stacktrace/frame.rb +66 -0
  52. data/lib/hoss/stacktrace.rb +33 -0
  53. data/lib/hoss/stacktrace_builder.rb +124 -0
  54. data/lib/hoss/transport/base.rb +191 -0
  55. data/lib/hoss/transport/connection/http.rb +139 -0
  56. data/lib/hoss/transport/connection/proxy_pipe.rb +94 -0
  57. data/lib/hoss/transport/connection.rb +55 -0
  58. data/lib/hoss/transport/filters/hash_sanitizer.rb +77 -0
  59. data/lib/hoss/transport/filters/secrets_filter.rb +48 -0
  60. data/lib/hoss/transport/filters.rb +60 -0
  61. data/lib/hoss/transport/headers.rb +74 -0
  62. data/lib/hoss/transport/serializers/context_serializer.rb +112 -0
  63. data/lib/hoss/transport/serializers/error_serializer.rb +92 -0
  64. data/lib/hoss/transport/serializers/event_serializer.rb +73 -0
  65. data/lib/hoss/transport/serializers/metadata_serializer.rb +92 -0
  66. data/lib/hoss/transport/serializers/report_serializer.rb +33 -0
  67. data/lib/hoss/transport/serializers.rb +113 -0
  68. data/lib/hoss/transport/user_agent.rb +48 -0
  69. data/lib/hoss/transport/worker.rb +319 -0
  70. data/lib/hoss/util/inflector.rb +110 -0
  71. data/lib/hoss/util/lru_cache.rb +65 -0
  72. data/lib/hoss/util/throttle.rb +52 -0
  73. data/lib/hoss/util.rb +54 -0
  74. data/lib/hoss/version.rb +22 -0
  75. data/lib/hoss-agent.rb +210 -0
  76. data/lib/hoss.rb +21 -0
  77. metadata +147 -0
@@ -0,0 +1,154 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Config
22
+ # @api private
23
+ module Options
24
+ # @api private
25
+ class Option
26
+ def initialize(
27
+ key,
28
+ value: nil,
29
+ type: :string,
30
+ default: nil,
31
+ converter: nil
32
+ )
33
+ @key = key
34
+ @type = type
35
+ @default = default
36
+ @converter = converter
37
+
38
+ set(value || default)
39
+ end
40
+
41
+ attr_reader :key, :value, :default, :type
42
+
43
+ def set(value)
44
+ @value = normalize(value)
45
+ end
46
+
47
+ def env_key
48
+ "HOSS_#{key.upcase}"
49
+ end
50
+
51
+ private
52
+
53
+ # rubocop:disable Metrics/CyclomaticComplexity
54
+ def normalize(val)
55
+ return if val.nil?
56
+
57
+ if @converter
58
+ return @converter.call(val)
59
+ end
60
+
61
+ case type
62
+ when :string then val.to_s
63
+ when :int then val.to_i
64
+ when :float then val.to_f
65
+ when :bool then normalize_bool(val)
66
+ when :list then normalize_list(val)
67
+ when :dict then normalize_dict(val)
68
+ when :url then normalize_url(val)
69
+ else
70
+ # raise "Unknown options type '#{type.inspect}'"
71
+ val
72
+ end
73
+ end
74
+ # rubocop:enable Metrics/CyclomaticComplexity
75
+
76
+ def normalize_bool(val)
77
+ return val unless val.is_a?(String)
78
+ !%w[0 false].include?(val.strip.downcase)
79
+ end
80
+
81
+ def normalize_list(val)
82
+ return Array(val) unless val.is_a?(String)
83
+ val.split(/[ ,]/)
84
+ end
85
+
86
+ def normalize_dict(val)
87
+ return val unless val.is_a?(String)
88
+ Hash[val.split(/[&,]/).map { |kv| kv.split('=') }]
89
+ end
90
+
91
+ def normalize_url(val)
92
+ val = val.to_s
93
+ val.end_with?('/') ? val.chomp('/') : val
94
+ end
95
+ end
96
+
97
+ # @api private
98
+ module ClassMethods
99
+ def schema
100
+ @schema ||= {}
101
+ end
102
+
103
+ def option(key, **args)
104
+ schema[key] = args
105
+ end
106
+ end
107
+
108
+ # @api private
109
+ module InstanceMethods
110
+ def load_schema
111
+ Hash[self.class.schema.map do |key, args|
112
+ [key, Option.new(key, **args)]
113
+ end]
114
+ end
115
+
116
+ def method_missing(name, *value)
117
+ name_str = name.to_s
118
+
119
+ if name_str.end_with?('=')
120
+ key = name_str[0...-1].to_sym
121
+ set(key, value.first)
122
+
123
+ elsif name_str.end_with?('?')
124
+ key = name_str[0...-1].to_sym
125
+ options.key?(key) ? options[key].value : super
126
+
127
+ elsif options.key?(name)
128
+ options.fetch(name).value
129
+
130
+ else
131
+ super
132
+ end
133
+ end
134
+
135
+ def [](key)
136
+ options[key]
137
+ end
138
+ alias :get :[]
139
+
140
+ def set(key, value)
141
+ options.fetch(key.to_sym).set(value)
142
+ rescue KeyError
143
+ warn format("Unknown option '%s'", key)
144
+ nil
145
+ end
146
+ end
147
+
148
+ def self.extended(kls)
149
+ kls.instance_eval { extend ClassMethods }
150
+ kls.class_eval { include InstanceMethods }
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,30 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Config
22
+ # @api private
23
+ class RegexpList
24
+ def call(value)
25
+ value = value.is_a?(String) ? value.split(',') : Array(value)
26
+ value.map(&Regexp.method(:new))
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,54 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Config
22
+ # @api private
23
+ class WildcardPatternList
24
+ # @api private
25
+ class WildcardPattern
26
+ def initialize(str)
27
+ @pattern = convert(str)
28
+ end
29
+
30
+ def match?(other)
31
+ !!@pattern.match(other)
32
+ end
33
+
34
+ alias :match :match?
35
+
36
+ private
37
+
38
+ def convert(str)
39
+ parts =
40
+ str.chars.each_with_object([]) do |char, arr|
41
+ arr << (char == '*' ? '.*' : Regexp.escape(char))
42
+ end
43
+
44
+ Regexp.new('\A' + parts.join + '\Z', Regexp::IGNORECASE)
45
+ end
46
+ end
47
+
48
+ def call(value)
49
+ value = value.is_a?(String) ? value.split(',') : Array(value)
50
+ value.map(&WildcardPattern.method(:new))
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,304 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ require 'hoss/config/options'
21
+ require 'hoss/config/duration'
22
+ require 'hoss/config/bytes'
23
+ require 'hoss/config/regexp_list'
24
+ require 'hoss/config/wildcard_pattern_list'
25
+
26
+ module Hoss
27
+ # @api private
28
+ class Config
29
+ extend Options
30
+
31
+ DEPRECATED_OPTIONS = %i[].freeze
32
+
33
+ # rubocop:disable Metrics/LineLength, Layout/ExtraSpacing
34
+ option :config_file, type: :string, default: 'config/hoss.yml'
35
+ option :api_host, type: :url, default: ENV['HOSS_API_HOST'] || 'https://app.hoss.com'
36
+ option :api_key, type: :string
37
+ option :ingress_host, type: :string, default: ENV['HOSS_INGRESS_HOST'] || 'https://ingress.hoss.com/v1'
38
+ option :max_queue_size, type: :int, default: 3000
39
+ option :batch_size, type: :int, default: ENV['HOSS_BATCH_SIZE'] || 512000
40
+ option :max_event_retries, type: :int, default: 100
41
+ option :remote_config_fetch_interval, type: :int, default: 300
42
+ option :agentConfig, type: :dict
43
+
44
+
45
+ option :central_config, type: :bool, default: true
46
+ option :capture_body, type: :string, default: 'off'
47
+ option :capture_headers, type: :bool, default: true
48
+ option :capture_env, type: :bool, default: true
49
+ option :current_user_email_method, type: :string, default: 'email'
50
+ option :current_user_id_method, type: :string, default: 'id'
51
+ option :current_user_username_method, type: :string, default: 'username'
52
+ option :custom_key_filters, type: :list, default: [], converter: RegexpList.new
53
+ option :default_labels, type: :dict, default: {}
54
+ option :disable_start_message, type: :bool, default: false
55
+ option :disable_instrumentations, type: :list, default: %w[]
56
+ option :enabled, type: :bool, default: true
57
+ option :environment, type: :string, default: ENV['RAILS_ENV'] || ENV['RACK_ENV']
58
+ option :framework_name, type: :string
59
+ option :framework_version, type: :string
60
+ option :filter_exception_types, type: :list, default: []
61
+ option :global_labels, type: :dict
62
+ option :hostname, type: :string
63
+ option :http_compression, type: :bool, default: true
64
+ option :instrument, type: :bool, default: true
65
+ option :log_level, type: :int, default: Logger::DEBUG
66
+ option :log_path, type: :string, default: '-'
67
+ option :pool_size, type: :int, default: 1
68
+ option :proxy_address, type: :string
69
+ option :proxy_headers, type: :dict
70
+ option :proxy_password, type: :string
71
+ option :proxy_port, type: :int
72
+ option :proxy_username, type: :string
73
+ option :recording, type: :bool, default: true
74
+ option :sanitize_field_names, type: :list, default: [], converter: WildcardPatternList.new
75
+ option :server_ca_cert, type: :string
76
+ option :service_name, type: :string
77
+ option :service_node_name, type: :string
78
+ option :service_version, type: :string
79
+ option :span_frames_min_duration, type: :float, default: '5ms', converter: Duration.new(default_unit: 'ms')
80
+ option :stack_trace_limit, type: :int, default: 999_999
81
+ option :verify_server_cert, type: :bool, default: true
82
+
83
+ # rubocop:enable Metrics/LineLength, Layout/ExtraSpacing
84
+ def initialize(options = {})
85
+ @options = load_schema
86
+
87
+ if options.is_a? String
88
+ assign(api_key: options)
89
+ else
90
+ assign(options)
91
+ end
92
+
93
+ # Pick out config_file specifically as we need it now to load it,
94
+ # but still need the other env vars to have precedence
95
+ env = load_env
96
+ if (env_config_file = env.delete(:config_file))
97
+ self.config_file = env_config_file
98
+ end
99
+
100
+ assign(load_config_file)
101
+ assign(env)
102
+
103
+ warn '[HOSS] No API Key provided' unless self.api_key
104
+
105
+ yield self if block_given?
106
+
107
+ self.logger ||= build_logger
108
+
109
+ @__view_paths ||= []
110
+ @__root_path ||= Dir.pwd
111
+ end
112
+
113
+ attr_accessor :__view_paths, :__root_path
114
+ attr_accessor :logger
115
+
116
+ attr_reader :options
117
+
118
+ def assign(update)
119
+ return unless update
120
+ update.each { |key, value| send(:"#{key}=", value) }
121
+ end
122
+
123
+ def available_instrumentations
124
+ %w[
125
+ http
126
+ net_http
127
+ faraday
128
+ ]
129
+ end
130
+
131
+ def enabled_instrumentations
132
+ available_instrumentations - disable_instrumentations
133
+ end
134
+
135
+ def method_missing(name, *args)
136
+ return super unless DEPRECATED_OPTIONS.include?(name)
137
+ warn "The option `#{name}' has been removed."
138
+ end
139
+
140
+ def replace_options(new_options)
141
+ return if new_options.nil? || new_options.empty?
142
+ options_copy = @options.dup
143
+ new_options.each do |key, value|
144
+ options_copy.fetch(key.to_sym).set(value)
145
+ end
146
+ @options = options_copy
147
+ end
148
+
149
+ def app=(app)
150
+ case app_type?(app)
151
+ when :sinatra
152
+ set_sinatra(app)
153
+ when :rails
154
+ set_rails(app)
155
+ else
156
+ self.service_name = 'ruby'
157
+ end
158
+ end
159
+
160
+ def use_ssl?
161
+ api_host.start_with?('https')
162
+ end
163
+
164
+ def span_frames_min_duration?
165
+ span_frames_min_duration != 0
166
+ end
167
+
168
+ def span_frames_min_duration=(value)
169
+ super
170
+ @span_frames_min_duration_us = nil
171
+ end
172
+
173
+ def span_frames_min_duration_us
174
+ @span_frames_min_duration_us ||= span_frames_min_duration * 1_000_000
175
+ end
176
+
177
+ def ssl_context
178
+ return unless use_ssl?
179
+
180
+ @ssl_context ||=
181
+ OpenSSL::SSL::SSLContext.new.tap do |context|
182
+ if server_ca_cert
183
+ context.ca_file = server_ca_cert
184
+ else
185
+ context.cert_store =
186
+ OpenSSL::X509::Store.new.tap(&:set_default_paths)
187
+ end
188
+
189
+ context.verify_mode =
190
+ if verify_server_cert
191
+ OpenSSL::SSL::VERIFY_PEER
192
+ else
193
+ OpenSSL::SSL::VERIFY_NONE
194
+ end
195
+ end
196
+ end
197
+
198
+ def inspect
199
+ super.split.first + '>'
200
+ end
201
+
202
+ # Deprecations
203
+
204
+ def default_tags=(value)
205
+ warn '[DEPRECATED] The option default_tags has been renamed to ' \
206
+ 'default_labels.'
207
+ self.default_labels = value
208
+ end
209
+
210
+ def custom_key_filters=(value)
211
+ unless value == self.class.schema[:custom_key_filters][:default]
212
+ warn '[DEPRECATED] The option custom_key_filters is being removed. ' \
213
+ 'See sanitize_field_names for an alternative.'
214
+ end
215
+
216
+ set(:custom_key_filters, value)
217
+ end
218
+
219
+ def disabled_instrumentations
220
+ disable_instrumentations
221
+ end
222
+
223
+ def active
224
+ enabled
225
+ end
226
+ alias active? active
227
+
228
+ def disabled_instrumentations=(value)
229
+ warn '[DEPRECATED] The option disabled_instrumentations has been ' \
230
+ 'renamed to disable_instrumentations to align with other agents.'
231
+ self.disable_instrumentations = value
232
+ end
233
+
234
+ def active=(value)
235
+ warn '[DEPRECATED] The option active has been renamed to enabled ' \
236
+ 'to align with other agents and with the remote config.'
237
+ self.enabled = value
238
+ end
239
+
240
+ private
241
+
242
+ def load_config_file
243
+ filename = File.join(@__root_path || Dir.pwd, config_file)
244
+ return unless File.exist?(filename)
245
+ read = File.read(filename)
246
+ evaled = ERB.new(read).result
247
+ YAML.safe_load(evaled)
248
+ end
249
+
250
+ def load_env
251
+ @options.values.each_with_object({}) do |option, opts|
252
+ next unless (value = ENV[option.env_key])
253
+ opts[option.key] = value
254
+ end
255
+ end
256
+
257
+ def build_logger
258
+ Logger.new(log_path == '-' ? STDOUT : log_path).tap do |logger|
259
+ logger.level = log_level
260
+ end
261
+ end
262
+
263
+ def app_type?(app)
264
+ if defined?(::Rails::Application) && app.is_a?(::Rails::Application)
265
+ return :rails
266
+ end
267
+
268
+ if app.is_a?(Class) && app.superclass.to_s == 'Sinatra::Base'
269
+ return :sinatra
270
+ end
271
+
272
+ nil
273
+ end
274
+
275
+ def set_sinatra(app)
276
+ self.service_name = format_name(service_name || app.to_s)
277
+ self.framework_name = framework_name || 'Sinatra'
278
+ self.framework_version = framework_version || ::Sinatra::VERSION
279
+ self.__root_path = Dir.pwd
280
+ end
281
+
282
+ def set_rails(app)
283
+ self.service_name ||= format_name(service_name || rails_app_name(app))
284
+ self.framework_name ||= 'Ruby on Rails'
285
+ self.framework_version ||= ::Rails::VERSION::STRING
286
+ self.logger ||= ::Rails.logger
287
+
288
+ self.__root_path = ::Rails.root.to_s
289
+ self.__view_paths = app.config.paths['app/views'].existent
290
+ end
291
+
292
+ def rails_app_name(app)
293
+ if ::Rails::VERSION::MAJOR >= 6
294
+ app.class.module_parent_name
295
+ else
296
+ app.class.parent_name
297
+ end
298
+ end
299
+
300
+ def format_name(str)
301
+ str&.gsub('::', '_')
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,36 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ # @api private
22
+ class Context
23
+ # @api private
24
+ class Request
25
+ # @api private
26
+ class Socket
27
+ def initialize(req)
28
+ @remote_addr = req.env['REMOTE_ADDR']
29
+ @encrypted = req.scheme == 'https'
30
+ end
31
+
32
+ attr_reader :remote_addr, :encrypted
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,59 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ # @api private
22
+ class Context
23
+ # @api private
24
+ class Request
25
+ # @api private
26
+ class Url
27
+ SKIPPED_PORTS = {
28
+ 'http' => 80,
29
+ 'https' => 443
30
+ }.freeze
31
+
32
+ def initialize(req)
33
+ @protocol = req.scheme
34
+ @hostname = req.host
35
+ @port = req.port.to_s
36
+ @pathname = req.path
37
+ @search = req.query_string
38
+ @hash = nil
39
+ @full = build_full_url req
40
+ end
41
+
42
+ attr_reader :protocol, :hostname, :port, :pathname, :search, :hash,
43
+ :full
44
+
45
+ private
46
+
47
+ def build_full_url(req)
48
+ url = "#{req.scheme}://#{req.host}"
49
+
50
+ if req.port != SKIPPED_PORTS[req.scheme]
51
+ url += ":#{req.port}"
52
+ end
53
+
54
+ url + req.fullpath
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,28 @@
1
+ # Licensed to Elasticsearch B.V. under one or more contributor
2
+ # license agreements. See the NOTICE file distributed with
3
+ # this work for additional information regarding copyright
4
+ # ownership. Elasticsearch B.V. licenses this file to you under
5
+ # the Apache License, Version 2.0 (the "License"); you may
6
+ # not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing,
12
+ # software distributed under the License is distributed on an
13
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
+ # KIND, either express or implied. See the License for the
15
+ # specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ # frozen_string_literal: true
19
+
20
+ module Hoss
21
+ class Context
22
+ # @api private
23
+ class Request
24
+ attr_accessor :body, :cookies, :env, :headers, :http_version, :method,
25
+ :socket, :url
26
+ end
27
+ end
28
+ end