Class: Jets::Shim::Adapter::Web

Inherits:
Base
  • Object
show all
Defined in:
lib/jets/shim/adapter/web.rb

Overview

Not named Rack to avoid confusion with the Rack gem

Direct Known Subclasses

Apigw, Lambda

Instance Attribute Summary

Attributes inherited from Base

#context, #event, #target

Instance Method Summary collapse

Methods inherited from Base

#initialize

Methods included from Util::Logging

#log

Constructor Details

This class inherits a constructor from Jets::Shim::Adapter::Base

Instance Method Details

#base_envObject



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/jets/shim/adapter/web.rb', line 65

def base_env
  # 'rack.input' - Even if not set, Rack always assigns an StringIO.
  {
    "CONTENT_LENGTH" => content_length,
    "HTTP_COOKIE" => http_cookie,
    "lambda.context" => context,
    "lambda.event" => event,
    "rack.input" => StringIO.new(body || ""),
    "REMOTE_ADDR" => remote_addr,
    "REMOTE_HOST" => host,
    "REQUEST_URI" => request_uri
  }
end

#bodyObject

Decoding base64 from API Gateaway if necessary Rack will be none the wiser



110
111
112
113
114
115
116
# File 'lib/jets/shim/adapter/web.rb', line 110

def body
  if event["isBase64Encoded"]
    Base64.decode64(event["body"])
  else
    event["body"]
  end
end

#content_lengthObject



98
99
100
101
# File 'lib/jets/shim/adapter/web.rb', line 98

def content_length
  bytesize = body.bytesize.to_s if body
  headers["Content-Length"] || bytesize
end

#handleObject



7
8
9
10
11
12
# File 'lib/jets/shim/adapter/web.rb', line 7

def handle
  env = to_rack_env
  app = Jets::Shim.config.app
  triplet = app.call(env)
  translate_response(triplet)
end

#headersObject



118
119
120
# File 'lib/jets/shim/adapter/web.rb', line 118

def headers
  event["headers"] || {}
end

#headers_envObject



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/jets/shim/adapter/web.rb', line 34

def headers_env
  env = {}
  headers.each do |k, v|
    key = k.tr("-", "_").upcase
    http_key = "HTTP_#{key}" # IE: User-Agent => HTTP_USER_AGENT

    # specially handle host since it can be overridden with JETS_SHIM_HOST
    next if http_key == "HTTP_HOST"

    if special_headers.include?(key)
      env[special_headers[key]] = v
    else
      env[http_key] ||= v
    end
  end
  env
end

#hostObject



122
123
124
125
126
127
128
129
# File 'lib/jets/shim/adapter/web.rb', line 122

def host
  # Host: apigw
  # host: lambda and alb
  ENV["JETS_SHIM_HOST"] ||
    shim_host ||
    headers["Host"] ||
    headers["host"]
end


81
82
83
# File 'lib/jets/shim/adapter/web.rb', line 81

def http_cookie
  event["cookies"]&.join("; ")
end

#httpsObject



138
139
140
141
142
143
# File 'lib/jets/shim/adapter/web.rb', line 138

def https
  # X-Forwarded-Proto: apigw
  # x-forwarded-proto: lambda and alb
  proto = headers["X-Forwarded-Proto"] || headers["x-forwarded-proto"]
  (proto == "https") ? "on" : "off"
end

#remote_addrObject



85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/jets/shim/adapter/web.rb', line 85

def remote_addr
  # X-Forwarded-For: client, proxy1, proxy2
  # X-Forwarded-For:
  #   The originating IP address of the client connecting to the ALB.
  #   This is used to capture the client IP address for requests that are sent to a proxy chain or a load balancer
  #   before they reach your server.
  #   If the X-Forwarded-For header is not present in the request, the remote IP address from the transport layer,
  #   such as the TCP connection, is used instead.
  #   https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html#access-log-entry-format
  addr = headers["X-Forwarded-For"] || headers["x-forwarded-for"] || headers["REMOTE_ADDR"]
  addr.split(",").first.strip if addr
end

#request_uriObject



103
104
105
106
# File 'lib/jets/shim/adapter/web.rb', line 103

def request_uri
  # IE: /foo?bar=1
  "#{path_info}?#{query_string}"
end

#shim_hostObject

Can be added by CloudFront function Also, POST requests have an origin header. IE: Updating a record with CRUD.



133
134
135
136
# File 'lib/jets/shim/adapter/web.rb', line 133

def shim_host
  return unless headers["jets-shim-host"]
  URI.parse(headers["jets-shim-host"]).host
end

#special_headersObject



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/jets/shim/adapter/web.rb', line 52

def special_headers
  # Note: apigw does not have content-length in headers.
  # See: https://stackoverflow.com/questions/56693981/how-do-i-get-http-header-content-length-in-api-gateway-lambda-proxy-integratio
  #
  # Instead content-length must be calculated from body. Done in base_env.
  # Adding content-length here for other adapters.
  # Headers have highest precedence since they get merged last.
  {
    "CONTENT_TYPE" => "CONTENT_TYPE",
    "CONTENT_LENGTH" => "CONTENT_LENGTH"
  }
end

#to_rack_envObject



14
15
16
17
18
# File 'lib/jets/shim/adapter/web.rb', line 14

def to_rack_env
  rack_env = base_env.merge(env).merge(headers_env)
  rack_env.delete_if { |k, v| v.nil? }
  rack_env
end

#translate_response(triplet) ⇒ Object

Translate rack triplet to compatible response for the service



21
22
23
24
25
26
# File 'lib/jets/shim/adapter/web.rb', line 21

def translate_response(triplet)
  adapter_name = self.class.name.split("::").last
  response_class = Jets::Shim::Response.const_get(adapter_name)
  response = response_class.new(triplet)
  response.translate
end