hoss-agent 1.0.1

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