Class: DebugBundle::Relay::Handler

Inherits:
Object
  • Object
show all
Defined in:
lib/debugbundle/relay/handler.rb

Instance Method Summary collapse

Constructor Details

#initialize(project_mode: :connected, project_token: nil, endpoint: DebugBundle::Config::DEFAULT_ENDPOINT, local_events_dir: DebugBundle::Config::DEFAULT_LOCAL_EVENTS_DIR, spool_dir: DebugBundle::Config::DEFAULT_SPOOL_DIR, durable_write: true, service: nil, environment: nil, allowed_origins: nil, max_body_bytes: DEFAULT_MAX_BODY_BYTES, rate_limit_per_minute: DEFAULT_RATE_LIMIT_PER_MINUTE, rate_limit_store: nil, forward_transport: nil) ⇒ Handler

Returns a new instance of Handler.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/debugbundle/relay/handler.rb', line 22

def initialize(
  project_mode: :connected,
  project_token: nil,
  endpoint: DebugBundle::Config::DEFAULT_ENDPOINT,
  local_events_dir: DebugBundle::Config::DEFAULT_LOCAL_EVENTS_DIR,
  spool_dir: DebugBundle::Config::DEFAULT_SPOOL_DIR,
  durable_write: true,
  service: nil,
  environment: nil,
  allowed_origins: nil,
  max_body_bytes: DEFAULT_MAX_BODY_BYTES,
  rate_limit_per_minute: DEFAULT_RATE_LIMIT_PER_MINUTE,
  rate_limit_store: nil,
  forward_transport: nil
)
  @project_mode = project_mode.to_sym
  @project_token = project_token
  @endpoint = endpoint
  @local_events_dir = local_events_dir
  @spool_dir = spool_dir
  @durable_write = durable_write
  @service = service
  @environment = environment
  @allowed_origins = Array(allowed_origins).compact.map { |origin| normalize_origin(origin) }
  @max_body_bytes = max_body_bytes
  @rate_limit_per_minute = rate_limit_per_minute
  @rate_limit_store = rate_limit_store
  @forward_transport = forward_transport || Transport::HttpTransport.new(@endpoint)
  @rate_limit_state = Hash.new { |hash, key| hash[key] = [] }
end

Instance Method Details

#handle(request) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/debugbundle/relay/handler.rb', line 53

def handle(request)
  return Response.new(status: 405, body: nil) unless request.fetch(:method, 'POST').to_s.upcase == 'POST'

  headers = normalize_headers(request[:headers] || {})
  return Response.new(status: 403, body: nil) unless origin_allowed?(headers)
  unless json_content_type?(headers['content-type'])
    return Response.new(status: 400,
                        body: invalid_body('Relay requests must use Content-Type: application/json.'))
  end

  raw_body = request[:body].to_s
  return Response.new(status: 413, body: nil) if raw_body.bytesize > @max_body_bytes
  return Response.new(status: 429, body: nil) if rate_limited?(request[:ip_address] || request[:ip])

  decoded = JSON.parse(raw_body)
  batch = decoded.fetch('batch')
  unless batch.is_a?(Array)
    return Response.new(status: 400,
                        body: invalid_body('Relay request body must include a batch array.'))
  end

  accepted = []
  errors = []

  batch.each_with_index do |candidate, index|
    sanitized = sanitize_event(candidate)
    if sanitized
      accepted << sanitized
    else
      errors << "batch[#{index}]: Invalid browser relay event payload."
    end
  end

  deliver(accepted) unless accepted.empty?

  unless errors.empty?
    return Response.new(status: 400,
                        body: { 'accepted' => accepted.length,
                                'rejected' => errors.length, 'errors' => errors })
  end

  Response.new(status: 202, body: { 'accepted' => accepted.length, 'rejected' => 0, 'errors' => [] })
rescue JSON::ParserError
  Response.new(status: 400, body: invalid_body('Relay request body must be valid JSON.'))
rescue KeyError
  Response.new(status: 400, body: invalid_body('Relay request body must include a batch array.'))
rescue StandardError
  Response.new(status: 500, body: nil)
end