Class: Immunio::Request

Inherits:
Object
  • Object
show all
Defined in:
lib/immunio/request.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env) ⇒ Request

Returns a new instance of Request.



12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/immunio/request.rb', line 12

def initialize(env)
  @env = env
  @data = {
    "type" => "engine.http_request",
    "request_id" => id,
    "start_time" => Time.now.utc.iso8601(6),
  }
  @timings = Hash.new { |h, name| h[name] = { count: 0, total_duration: 0 } }
  @paused_times = {}
  @start_time = Time.now

  Immunio.logger.debug { "Created new Request #{id} with data #{@data}" }
end

Instance Attribute Details

#dataObject

Data sent to the server



6
7
8
# File 'lib/immunio/request.rb', line 6

def data
  @data
end

#vmObject

We keep the VM and hook handlers in the request to ensure all hooks for this request use the same handlers.



6
7
8
# File 'lib/immunio/request.rb', line 6

def vm
  @vm
end

Class Method Details

.currentObject



95
96
97
# File 'lib/immunio/request.rb', line 95

def self.current
  Thread.current["immunio.request"]
end

.current=(request) ⇒ Object



99
100
101
102
# File 'lib/immunio/request.rb', line 99

def self.current=(request)
  Thread.current["immunio.request"] = request
  Immunio.logger.debug { "Setting current request for thread #{Thread.current.object_id} to #{request && request.id || nil}" }
end

.pause(type, name, &block) ⇒ Object



119
120
121
122
123
124
125
# File 'lib/immunio/request.rb', line 119

def self.pause(type, name, &block)
  if Request.current
    Request.current.pause(type, name, &block)
  else
    self.stack_shim(&block)
  end
end

.stack_shimObject

This shim exists to preserve the stack depth into hooks when self.time and self.pause are called. Otherwise the number of immunio frames will vary based on the state of the request object



106
107
108
# File 'lib/immunio/request.rb', line 106

def self.stack_shim()
  yield
end

.time(type, name, &block) ⇒ Object



110
111
112
113
114
115
116
117
# File 'lib/immunio/request.rb', line 110

def self.time(type, name, &block)
  if Request.current
    Request.current.time(type, name, &block)
  else
    Immunio.logger.debug { "Starting request time for #{type} #{name}" }
    self.stack_shim(&block)
  end
end

Instance Method Details

#encodeObject

Encode the request data to send it to the channel.



86
87
88
89
90
91
92
93
# File 'lib/immunio/request.rb', line 86

def encode
  if @data.is_a? Hash
    @data.to_msgpack
  else # Lua table
    # Encode the data in Lua to avoid pulling a huge Lua table out of the VM, which is slow.
    @vm.unsafe_call_by_name 'encode', @data
  end
end

#idObject



26
27
28
# File 'lib/immunio/request.rb', line 26

def id
  @env["action_dispatch.request_id"] || internal_id
end

#pause(type, name) ⇒ Object

Pause execution timing while executing block



52
53
54
55
56
57
58
# File 'lib/immunio/request.rb', line 52

def pause(type, name)
  key = {type: type, name: name}
  start = Time.now
  yield
ensure
  @paused_times[key]+= (Time.now - start) * 1000
end

#should_report?Boolean

Returns:

  • (Boolean)


77
78
79
80
81
82
83
# File 'lib/immunio/request.rb', line 77

def should_report?
  result = Immunio.run_hook "request", "should_report"
  # If the hook doesn't exist, turn a nil report value into a false value
  report = !!result["report"]
  Immunio.logger.debug { "Report request: #{report}" }
  report
end

#time(type, name) ⇒ Object

Time the execution of a block and stores it in the request’s ‘timings`.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/immunio/request.rb', line 31

def time(type, name)
  Immunio.logger.debug { "Starting request time for #{type} #{name}" }
  start = Time.now
  key = {type: type, name: name}
  nested = false
  if @paused_times[key]
    nested = true
  else
    @paused_times[key] = 0
  end
  yield
ensure
    timing = @timings[key]
    timing[:count] += 1
    timing[:total_duration] += (Time.now - start) * 1000
  if !nested
    timing[:total_duration] -= @paused_times.delete(key)
  end
end

#timingsObject



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/immunio/request.rb', line 60

def timings
  total_key = {type: "request", name: "total"}
  timing = @timings[total_key]
  timing[:count] = 1
  timing[:total_duration] = (Time.now - @start_time) * 1000

  split_timings = {}
  @timings.each do |key, value|
    # Round to microsecond precision
    value[:total_duration] = value[:total_duration].round(3)

    split_timings[key[:type]] ||= {}
    split_timings[key[:type]][key[:name]] = value
  end
  split_timings
end