Class: Sqreen::Frameworks::GenericFramework
- Inherits:
-
Object
- Object
- Sqreen::Frameworks::GenericFramework
- Includes:
- RequestRecorder
- Defined in:
- lib/sqreen/frameworks/generic.rb
Overview
This is the base class for framework specific code
Direct Known Subclasses
Constant Summary collapse
- PREFERRED_IP_HEADERS =
%w[HTTP_X_FORWARDED_FOR HTTP_X_REAL_IP HTTP_CLIENT_IP HTTP_X_FORWARDED HTTP_X_CLUSTER_CLIENT_IP HTTP_FORWARDED_FOR HTTP_FORWARDED HTTP_VIA].freeze
- TRUSTED_PROXIES =
Sourced from rack:Request#trusted_proxy?
/\A127\.0\.0\.1\Z|\A(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|\A::1\Z|\Afd[0-9a-f]{2}:.+|\Alocalhost\Z|\Aunix\Z|\Aunix:/i
- LOCALHOST =
/\A127\.0\.0\.1\Z|\A::1\Z|\Alocalhost\Z|\Aunix\Z|\Aunix:/i
- P_FORM =
'form'.freeze
- P_RACK =
'rack'.freeze
- P_QUERY =
'query'.freeze
- P_COOKIE =
'cookies'.freeze
- P_GRAPE =
'grape_params'.freeze
- P_RACK_ROUTING =
'rack_routing'.freeze
Instance Attribute Summary collapse
-
#req_end_cb ⇒ Object
writeonly
Sets the attribute req_end_cb.
-
#req_start_cb ⇒ Object
writeonly
Sets the attribute req_start_cb.
-
#sqreen_configuration ⇒ Object
Returns the value of attribute sqreen_configuration.
Class Method Summary collapse
- .cookies_params(request) ⇒ Object
- .form_params(request) ⇒ Object
- .parameters_from_request(request) ⇒ Object
- .query_params(request) ⇒ Object
- .rack_params(request) ⇒ Object
Instance Method Summary collapse
- #application_name ⇒ Object
- #body ⇒ Object
-
#clean_request ⇒ Object
Cleanup request context.
-
#client_ip ⇒ Object
What is the current client IP.
-
#client_user_agent ⇒ Object
request user agent.
-
#cwd ⇒ Object
Expose current working directory.
- #datadog_span ⇒ Object
- #datadog_trace ⇒ Object
-
#db_settings(_options = {}) ⇒ Object
What kind of database is this.
- #development? ⇒ Boolean
- #filtered_request_params ⇒ Object
-
#framework_infos ⇒ Object
More information about the current framework.
-
#full_params_include?(value, params = nil) ⇒ Boolean
Does the parameters key/value include this value.
- #graphql_args=(args) ⇒ Object
-
#header(name) ⇒ Object
Get a header by name.
- #hostname ⇒ Object
- #http_headers ⇒ Object
-
#initialize ⇒ GenericFramework
constructor
A new instance of GenericFramework.
-
#instrument_when_ready!(instrumentor, rules) ⇒ Object
Instrument with our rules when the framework as finished loading.
- #ip_headers ⇒ Object
- #mark_request_overtime! ⇒ Object
-
#params_include?(value, params = nil) ⇒ Boolean
Does the parameters value include this value.
-
#prevent_startup ⇒ Object
Should the agent not be starting up?.
-
#rack_client_ip ⇒ Object
What is the current client IP as seen by rack.
- #remaining_perf_budget ⇒ Object
- #remaining_perf_budget=(value) ⇒ Object
- #remote_addr ⇒ Object
-
#request ⇒ Object
Get the currently stored request.
- #request_id ⇒ Object
-
#request_infos ⇒ Object
Summary of known request infos.
- #request_params ⇒ Object
-
#request_path ⇒ Object
Request URL path.
- #response ⇒ Object
- #response_infos ⇒ Object
-
#root ⇒ Object
Application root.
-
#store_request(object) ⇒ Object
Fetch and store the current request object Nota: cleanup should be performed at end of request (see clean_request).
- #store_response(rv, _env) ⇒ Object
- #test? ⇒ Boolean
-
#whitelisted_ip ⇒ Object
Returns the current path that whitelist the request.
-
#whitelisted_match ⇒ Object
Return the current item that whitelist this request returns nil if request is not whitelisted.
-
#whitelisted_path ⇒ Object
Returns the current path that whitelist the request.
- #xss_params(regexp = nil) ⇒ Object
Methods included from RequestRecorder
#clean_request_record, #close_request_record, #observe, #observed_items, #observed_items=, #only_metric_observation, #only_metric_observation=, #payload_requests, #payload_requests=
Constructor Details
#initialize ⇒ GenericFramework
Returns a new instance of GenericFramework.
27 28 29 30 31 32 33 34 35 36 |
# File 'lib/sqreen/frameworks/generic.rb', line 27 def initialize clean_request_record # for notifying the ecosystem of request boundaries # XXX: this should be refactored. It shouldn't be # the framework doing these notifications to the ecosystem # Probably the rule callback should do it itself @req_start_cb = Proc.new {} @req_end_cb = Proc.new {} end |
Instance Attribute Details
#req_end_cb=(value) ⇒ Object (writeonly)
Sets the attribute req_end_cb
25 26 27 |
# File 'lib/sqreen/frameworks/generic.rb', line 25 def req_end_cb=(value) @req_end_cb = value end |
#req_start_cb=(value) ⇒ Object (writeonly)
Sets the attribute req_start_cb
25 26 27 |
# File 'lib/sqreen/frameworks/generic.rb', line 25 def req_start_cb=(value) @req_start_cb = value end |
#sqreen_configuration ⇒ Object
Returns the value of attribute sqreen_configuration.
23 24 25 |
# File 'lib/sqreen/frameworks/generic.rb', line 23 def sqreen_configuration @sqreen_configuration end |
Class Method Details
.cookies_params(request) ⇒ Object
383 384 385 386 387 388 389 390 391 |
# File 'lib/sqreen/frameworks/generic.rb', line 383 def self.(request) return nil unless request begin request. rescue => e Sqreen.log.debug("cookies are invalid #{e.inspect}") nil end end |
.form_params(request) ⇒ Object
363 364 365 366 367 368 369 370 371 |
# File 'lib/sqreen/frameworks/generic.rb', line 363 def self.form_params(request) return nil unless request begin request.POST rescue => e Sqreen.log.debug("POST Parameters are invalid #{e.inspect}") nil end end |
.parameters_from_request(request) ⇒ Object
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'lib/sqreen/frameworks/generic.rb', line 407 def self.parameters_from_request(request) return {} unless request r = { P_FORM => form_params(request), P_QUERY => query_params(request), P_COOKIE => (request), } if (p = rack_params(request)) r[P_RACK] = p end p = request.env['sqreen.request.graphql_args'] r['graphql'] = p if p # Add grape parameters if seen p = request.env['grape.request.params'] r[P_GRAPE] = p if p p = request.env['rack.routing_args'] if p r[P_RACK_ROUTING] = p.dup r[P_RACK_ROUTING].delete :route_info r[P_RACK_ROUTING].delete :version end r end |
.query_params(request) ⇒ Object
393 394 395 396 397 398 399 400 401 |
# File 'lib/sqreen/frameworks/generic.rb', line 393 def self.query_params(request) return nil unless request begin request.GET rescue => e Sqreen.log.debug("GET Parameters are invalid #{e.inspect}") nil end end |
.rack_params(request) ⇒ Object
373 374 375 376 377 378 379 380 381 |
# File 'lib/sqreen/frameworks/generic.rb', line 373 def self.rack_params(request) return nil unless request begin request.params rescue => e Sqreen.log.debug("Rack Parameters are invalid #{e.inspect}") nil end end |
Instance Method Details
#application_name ⇒ Object
238 239 240 |
# File 'lib/sqreen/frameworks/generic.rb', line 238 def application_name nil end |
#body ⇒ Object
432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/sqreen/frameworks/generic.rb', line 432 def body return nil unless request.respond_to?(:body) return nil unless request.body.respond_to?(:read) return nil unless request.body.respond_to?(:rewind) body_io = request.body body = body_io.read(4096) body_io.rewind body end |
#clean_request ⇒ Object
Cleanup request context
320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/sqreen/frameworks/generic.rb', line 320 def clean_request payload_creator = Sqreen::PayloadCreator.new(self) close_request_record(Sqreen.queue, Sqreen.observations_queue, payload_creator) self.remaining_perf_budget = nil SharedStorage.set(:request, nil) SharedStorage.set(:response, nil) SharedStorage.set(:xss_params, nil) SharedStorage.set(:whitelisted, nil) SharedStorage.set(:request_overtime, nil) @req_end_cb.call end |
#client_ip ⇒ Object
What is the current client IP
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/sqreen/frameworks/generic.rb', line 106 def client_ip req = request return nil unless req # Look for an external address being forwarded split_ips = [] preferred_ip_headers.each do |header_name| forwarded = req.env[header_name] ips = split_ip_addresses(forwarded) lip = ips.find { |ip| (ip !~ TRUSTED_PROXIES) && valid_ip?(ip) } split_ips << ips unless ips.empty? return lip unless lip.nil? end # Else fall back to declared remote addr r = req.env['REMOTE_ADDR'] # If this is localhost get the last hop before if r.nil? || r =~ LOCALHOST split_ips.each do |ips| lip = ips.find { |ip| (ip !~ LOCALHOST) && valid_ip?(ip) } return lip unless lip.nil? end end r end |
#client_user_agent ⇒ Object
request user agent
227 228 229 230 231 |
# File 'lib/sqreen/frameworks/generic.rb', line 227 def client_user_agent req = request return nil unless req req.env['HTTP_USER_AGENT'] end |
#cwd ⇒ Object
Expose current working directory
445 446 447 |
# File 'lib/sqreen/frameworks/generic.rb', line 445 def cwd Dir.getwd end |
#datadog_span ⇒ Object
184 185 186 187 188 189 190 191 192 |
# File 'lib/sqreen/frameworks/generic.rb', line 184 def datadog_span return unless defined?(Datadog) if defined?(Datadog::Tracing) && Datadog::Tracing.respond_to?(:active_span) Datadog::Tracing.active_span elsif Datadog.respond_to?(:tracer) && Datadog.tracer Datadog.tracer.active_span end end |
#datadog_trace ⇒ Object
194 195 196 197 198 199 200 |
# File 'lib/sqreen/frameworks/generic.rb', line 194 def datadog_trace return unless defined?(Datadog) if defined?(Datadog::Tracing) && Datadog::Tracing.respond_to?(:active_trace) Datadog::Tracing.active_trace end end |
#db_settings(_options = {}) ⇒ Object
What kind of database is this
39 40 41 |
# File 'lib/sqreen/frameworks/generic.rb', line 39 def db_settings( = {}) raise Sqreen::NotImplementedYet end |
#development? ⇒ Boolean
53 54 55 |
# File 'lib/sqreen/frameworks/generic.rb', line 53 def development? ENV['RACK_ENV'] == 'development' end |
#filtered_request_params ⇒ Object
344 345 346 347 348 |
# File 'lib/sqreen/frameworks/generic.rb', line 344 def filtered_request_params params = request_params params.delete('cookies') params end |
#framework_infos ⇒ Object
More information about the current framework
44 45 46 47 48 49 50 51 |
# File 'lib/sqreen/frameworks/generic.rb', line 44 def framework_infos raise Sqreen::NotImplementedYet unless ensure_rack_loaded { :framework_type => 'Rack', :framework_version => Rack.version, :environment => ENV['RACK_ENV'], } end |
#full_params_include?(value, params = nil) ⇒ Boolean
Does the parameters key/value include this value
275 276 277 278 279 280 281 282 |
# File 'lib/sqreen/frameworks/generic.rb', line 275 def full_params_include?(value, params = nil) params = request_params if params.nil? return false if params.nil? each_key_value_for_hash(params) do |param| return true if param == value end false end |
#graphql_args=(args) ⇒ Object
403 404 405 |
# File 'lib/sqreen/frameworks/generic.rb', line 403 def graphql_args=(args) request.env['sqreen.request.graphql_args'] = args if request end |
#header(name) ⇒ Object
Get a header by name
131 132 133 134 135 |
# File 'lib/sqreen/frameworks/generic.rb', line 131 def header(name) req = request return nil unless req req.env[name] end |
#hostname ⇒ Object
145 146 147 148 149 150 151 |
# File 'lib/sqreen/frameworks/generic.rb', line 145 def hostname req = request return nil unless req http_host = req.env['HTTP_HOST'] return http_host if http_host && !http_host.empty? req.env['SERVER_NAME'] end |
#http_headers ⇒ Object
137 138 139 140 141 142 143 |
# File 'lib/sqreen/frameworks/generic.rb', line 137 def http_headers req = request return nil unless req # dup to avoid potential error because of change (in another thread) # during iteration req.env.dup.select { |k, _| k.to_s.start_with?('HTTP_') } end |
#instrument_when_ready!(instrumentor, rules) ⇒ Object
Instrument with our rules when the framework as finished loading
260 261 262 |
# File 'lib/sqreen/frameworks/generic.rb', line 260 def instrument_when_ready!(instrumentor, rules) instrumentor.instrument!(rules, self) end |
#ip_headers ⇒ Object
81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/sqreen/frameworks/generic.rb', line 81 def ip_headers req = request return [] unless req ips = [] (preferred_ip_headers + ['REMOTE_ADDR']).each do |header| v = req.env[header] ips << [header, v] unless v.nil? end ips << ['rack.ip', req.ip] if req.respond_to?(:ip) ips end |
#mark_request_overtime! ⇒ Object
284 285 286 287 288 289 |
# File 'lib/sqreen/frameworks/generic.rb', line 284 def mark_request_overtime! over = SharedStorage.get(:request_overtime) return false if over SharedStorage.set(:request_overtime, true) true end |
#params_include?(value, params = nil) ⇒ Boolean
Does the parameters value include this value
265 266 267 268 269 270 271 272 |
# File 'lib/sqreen/frameworks/generic.rb', line 265 def params_include?(value, params = nil) params = request_params if params.nil? return false if params.nil? each_value_for_hash(params) do |param| return true if param == value end false end |
#prevent_startup ⇒ Object
Should the agent not be starting up?
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/sqreen/frameworks/generic.rb', line 243 def prevent_startup # SQREEN-880 - prevent Sqreen startup on Sidekiq workers return :sidekiq_cli if defined?(Sidekiq::CLI) return :delayed_job if defined?(Delayed::Command) # Prevent Sqreen startup on rake tasks - unless this is a Sqreen test run_in_test = sqreen_configuration.get(:run_in_test) return :rake if !run_in_test && $0.end_with?('rake') return :irb if $0 == 'irb' return if sqreen_configuration.nil? disable = sqreen_configuration.get(:disable) return :config_disable if disable == true || disable.to_s.to_i == 1 end |
#rack_client_ip ⇒ Object
What is the current client IP as seen by rack
94 95 96 97 98 99 |
# File 'lib/sqreen/frameworks/generic.rb', line 94 def rack_client_ip req = request return nil unless req return req.ip if req.respond_to?(:ip) req.env['REMOTE_ADDR'] end |
#remaining_perf_budget ⇒ Object
332 333 334 |
# File 'lib/sqreen/frameworks/generic.rb', line 332 def remaining_perf_budget SharedStorage.get(:performance_budget) end |
#remaining_perf_budget=(value) ⇒ Object
336 337 338 |
# File 'lib/sqreen/frameworks/generic.rb', line 336 def remaining_perf_budget=(value) SharedStorage.set(:performance_budget, value) end |
#remote_addr ⇒ Object
474 475 476 477 |
# File 'lib/sqreen/frameworks/generic.rb', line 474 def remote_addr return nil unless request request.env['REMOTE_ADDR'] end |
#request ⇒ Object
Get the currently stored request
311 312 313 |
# File 'lib/sqreen/frameworks/generic.rb', line 311 def request SharedStorage.get(:request) end |
#request_id ⇒ Object
153 154 155 156 157 |
# File 'lib/sqreen/frameworks/generic.rb', line 153 def request_id req = request return nil unless req req.env['HTTP_X_REQUEST_ID'] end |
#request_infos ⇒ Object
Summary of known request infos
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/sqreen/frameworks/generic.rb', line 160 def request_infos req = request return {} unless req # FIXME: Use frozen string keys { :rid => request_id, :user_agent => client_user_agent, :scheme => req.scheme, :verb => req.env['REQUEST_METHOD'], :host => hostname, :port => req.env['SERVER_PORT'], :referer => req.env['HTTP_REFERER'], :path => request_path, :remote_port => req.env['REMOTE_PORT'], :remote_ip => remote_addr, :client_ip => client_ip, }.tap do |h| h.merge!( :datadog_trace_id => datadog_span.trace_id, :datadog_span_id => datadog_span.span_id, ) if datadog_span end end |
#request_params ⇒ Object
340 341 342 |
# File 'lib/sqreen/frameworks/generic.rb', line 340 def request_params self.class.parameters_from_request(request) end |
#request_path ⇒ Object
Request URL path
220 221 222 223 224 |
# File 'lib/sqreen/frameworks/generic.rb', line 220 def request_path req = request return nil unless req req.script_name + req.path_info end |
#response ⇒ Object
315 316 317 |
# File 'lib/sqreen/frameworks/generic.rb', line 315 def response SharedStorage.get(:response) end |
#response_infos ⇒ Object
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/sqreen/frameworks/generic.rb', line 202 def response_infos return {} if response.nil? content_type = response.header['Content-Type'] content_length = begin Integer(response.header['Content-Length']) rescue ArgumentError, TypeError nil end { :status => response.status, :content_type => content_type, :content_length => content_length, } end |
#root ⇒ Object
Application root
234 235 236 |
# File 'lib/sqreen/frameworks/generic.rb', line 234 def root nil end |
#store_request(object) ⇒ Object
Fetch and store the current request object Nota: cleanup should be performed at end of request (see clean_request)
293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/sqreen/frameworks/generic.rb', line 293 def store_request(object) return unless ensure_rack_loaded rack_req = Rack::Request.new(object) @req_start_cb.call(rack_req) self.remaining_perf_budget = Sqreen.performance_budget SharedStorage.set(:request, rack_req) SharedStorage.set(:xss_params, nil) SharedStorage.set(:whitelisted, nil) SharedStorage.set(:request_overtime, nil) end |
#store_response(rv, _env) ⇒ Object
306 307 308 |
# File 'lib/sqreen/frameworks/generic.rb', line 306 def store_response(rv, _env) SharedStorage.set(:response, Rack::Response.new([], rv[0], rv[1])) end |
#test? ⇒ Boolean
57 58 59 |
# File 'lib/sqreen/frameworks/generic.rb', line 57 def test? ENV['RACK_ENV'] == 'test' end |
#whitelisted_ip ⇒ Object
Returns the current path that whitelist the request
466 467 468 469 470 471 472 |
# File 'lib/sqreen/frameworks/generic.rb', line 466 def whitelisted_ip ip = client_ip return nil unless ip find_whitelisted_ip(ip) rescue nil end |
#whitelisted_match ⇒ Object
Return the current item that whitelist this request returns nil if request is not whitelisted
451 452 453 454 455 456 |
# File 'lib/sqreen/frameworks/generic.rb', line 451 def whitelisted_match return nil unless request whitelisted = whitelisted_ip || whitelisted_path SharedStorage.set(:whitelisted, !whitelisted.nil?) whitelisted end |
#whitelisted_path ⇒ Object
Returns the current path that whitelist the request
459 460 461 462 463 |
# File 'lib/sqreen/frameworks/generic.rb', line 459 def whitelisted_path path = request_path return nil unless path find_whitelisted_path(path) end |
#xss_params(regexp = nil) ⇒ Object
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
# File 'lib/sqreen/frameworks/generic.rb', line 480 def xss_params(regexp = nil) p = SharedStorage.get(:xss_params) return p unless p.nil? p = request_params parm = Set.new each_key_value_for_hash(p) do |value| next unless value.is_a?(String) next if value.size < 5 value = value.dup.force_encoding(Encoding::ISO_8859_1).encode(Encoding::UTF_8) unless value.valid_encoding? next if regexp && !regexp.match?(value) parm << value end p = parm.to_a Sqreen.log.debug { "Filtered XSS params: #{p.inspect}" } SharedStorage.set(:xss_params, p) p end |