Class: Jets::Mega::Request

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Defined in:
lib/jets/mega/request.rb,
lib/jets/mega/request/source.rb

Defined Under Namespace

Classes: Source

Constant Summary collapse

JETS_OUTPUT =
"/tmp/jets-output.log"

Instance Method Summary collapse

Constructor Details

#initialize(event, controller) ⇒ Request

Returns a new instance of Request.



10
11
12
13
# File 'lib/jets/mega/request.rb', line 10

def initialize(event, controller)
  @event = event
  @controller = controller # Jets::Controller instance
end

Instance Method Details

#get_encoding(content_type) ⇒ Object



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

def get_encoding(content_type)
  default = Jets.config.encoding.default
  return default unless content_type

  md = content_type.match(/charset=(.+)/)
  return default unless md

  md[1]
end

#get_uriObject



103
104
105
106
107
108
109
110
111
# File 'lib/jets/mega/request.rb', line 103

def get_uri
  url = "http://localhost:9292#{@controller.request.path}" # local rack server
  unless @controller.query_parameters.empty?
    # Thanks: https://stackoverflow.com/questions/798710/ruby-how-to-turn-a-hash-into-http-parameters
    query_string = Rack::Utils.build_nested_query(@controller.query_parameters)
    url += "?#{query_string}"
  end
  URI(url)
end

#http_classObject

Rails sets _method=patch or _method=put as workaround Falls back to GET when testing in lambda console @event is GET, POST, PUT, DELETE, etc



121
122
123
124
125
# File 'lib/jets/mega/request.rb', line 121

def http_class
  http_class = params['_method'] || @event['httpMethod'] || 'GET'
  http_class.capitalize!
  http_class
end

#paramsObject



127
128
129
# File 'lib/jets/mega/request.rb', line 127

def params
  @controller.params(raw: true, path_parameters: false, body_parameters: true)
end

#proxyObject



15
16
17
18
19
20
21
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
52
53
54
55
56
57
58
59
# File 'lib/jets/mega/request.rb', line 15

def proxy
  http_method = @event['httpMethod'] # GET, POST, PUT, DELETE, etc
  params = @controller.params(raw: true, path_parameters: false)

  uri = get_uri

  http = Net::HTTP.new(uri.host, uri.port)
  http.open_timeout = http.read_timeout = 60

  # Rails sets _method=patch or _method=put as workaround
  # Falls back to GET when testing in lambda console
  http_class = params['_method'] || http_method || 'GET'
  http_class.capitalize!

  request_class = "Net::HTTP::#{http_class}".constantize # IE: Net::HTTP::Get
  request = request_class.new(uri)

  # Set form data
  if %w[Post Patch Put].include?(http_class)
    params = HashConverter.encode(params)
    request.set_form_data(params)
  end

  # Set body info
  request.body = source.body
  request.content_length = source.content_length

  # Need to set headers after body and form_data for some reason
  request = set_headers!(request)

  # Make request
  response = send_request(http, request)

  puts_rack_output

  status = response.code.to_i
  headers = response.each_header.to_h
  encoding = get_encoding(headers['content-type'])
  body = response.body&.force_encoding(encoding)
  {
    status: status,
    headers: headers,
    body: body,
  }
end

#puts_rack_outputObject

Grab the rack output from the /tmp/jets-output.log and puts it back in the main process’ stdout



97
98
99
100
101
# File 'lib/jets/mega/request.rb', line 97

def puts_rack_output
  return unless File.exist?(JETS_OUTPUT)
  puts IO.readlines(JETS_OUTPUT)
  File.truncate(JETS_OUTPUT, 0)
end

#send_request(http, request) ⇒ Object

Adds error handling in case the rack server has gone down. Will try to start the server back up if needed. Search CloudWatch logs for ‘Unable to send request’ to find for indication of this.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/jets/mega/request.rb', line 63

def send_request(http, request)
  retries = 0
  max_retries = 30 # 15 seconds at a delay of 0.5s
  delay = 0.5

  begin
    http.request(request) # response
  rescue Errno::ECONNREFUSED, Errno::EAFNOSUPPORT
    puts "Unable to send request to localhost:9292. Will try to start the server with a delay of #{delay} and try again."
    Jets.start_rack_server

    sleep(delay)
    retries += 1
    if retries < max_retries
      retry
    else
      puts "Giving up on trying to send request to localhost:9292"
      raise # re-raise error
    end
  end
end

#set_headers!(request) ⇒ Object

Set request headers. Forwards original request info from remote API gateway. By this time, the server/api_gateway.rb middleware.



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/jets/mega/request.rb', line 134

def set_headers!(request)
  headers = @event['headers'] # from api gateway
  if headers # remote API Gateway
    # Forward headers from API Gateway over to the sub http request.
    # It's important to forward the headers. Here are some examples:
    #
    #   "Turbolinks-Referrer"=>"http://localhost:8888/posts/122",
    #   "Referer"=>"http://localhost:8888/posts/122",
    #   "Accept-Encoding"=>"gzip, deflate",
    #   "Accept-Language"=>"en-US,en;q=0.9,pt;q=0.8",
    #   "Cookie"=>"_demo_session=...",
    #   "If-None-Match"=>"W/\"9fa479205fc6d24ca826d46f1f6cf461\"",
    headers.each do |k,v|
      request[k] = v
    end

    # Note by the time headers get to rack later in the they get changed to:
    #
    #   request['X-Forwarded-Host'] vs env['HTTP_X_FORWARDED_HOST']
    #
    request['X-Forwarded-For'] = headers['X-Forwarded-For'] # "1.1.1.1, 2.2.2.2" # can be comma separated list
    request['X-Forwarded-Host'] = headers['Host'] # uhghn8z6t1.execute-api.us-east-1.amazonaws.com
    request['X-Forwarded-Port'] = headers['X-Forwarded-Port'] # 443
    request['X-Forwarded-Proto'] = headers['X-Forwarded-Proto'] # https # scheme
  end

  request
end

#sourceObject



113
114
115
# File 'lib/jets/mega/request.rb', line 113

def source
  Source.new(@event)
end