jets 1.0.18 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +10 -10
- data/README/testing.md +5 -2
- data/lib/jets.rb +2 -2
- data/lib/jets/application.rb +69 -40
- data/lib/jets/booter.rb +17 -20
- data/lib/jets/builders/code_builder.rb +7 -8
- data/lib/jets/cfn/ship.rb +0 -6
- data/lib/jets/commands/build.rb +0 -5
- data/lib/jets/commands/deploy.rb +0 -4
- data/lib/jets/commands/main.rb +31 -4
- data/lib/jets/commands/templates/skeleton/{.env → .env.tt} +1 -0
- data/lib/jets/commands/templates/skeleton/config.ru +1 -0
- data/lib/jets/commands/upgrade/v1.rb +12 -0
- data/lib/jets/controller.rb +5 -0
- data/lib/jets/controller/base.rb +43 -21
- data/lib/jets/controller/cookies.rb +40 -0
- data/lib/jets/controller/cookies/jar.rb +269 -0
- data/lib/jets/controller/middleware.rb +4 -0
- data/lib/jets/controller/middleware/local.rb +119 -0
- data/lib/jets/{server/lambda_aws_proxy.rb → controller/middleware/local/api_gateway.rb} +11 -49
- data/lib/jets/controller/middleware/local/mimic_aws_call.rb +38 -0
- data/lib/jets/{server → controller/middleware/local}/route_matcher.rb +4 -4
- data/lib/jets/controller/middleware/main.rb +46 -0
- data/lib/jets/{server → controller/middleware}/webpacker_setup.rb +0 -1
- data/lib/jets/controller/params.rb +2 -1
- data/lib/jets/controller/rack.rb +5 -0
- data/lib/jets/controller/rack/adapter.rb +60 -0
- data/lib/jets/controller/rack/env.rb +96 -0
- data/lib/jets/controller/redirection.rb +1 -1
- data/lib/jets/controller/renderers.rb +1 -1
- data/lib/jets/controller/renderers/base_renderer.rb +0 -4
- data/lib/jets/controller/renderers/{aws_proxy_renderer.rb → rack_renderer.rb} +7 -19
- data/lib/jets/controller/renderers/template_renderer.rb +1 -1
- data/lib/jets/controller/request.rb +14 -44
- data/lib/jets/controller/response.rb +55 -7
- data/lib/jets/internal/app/controllers/jets/rack_controller.rb +13 -3
- data/lib/jets/mega.rb +7 -0
- data/lib/jets/{rack → mega}/hash_converter.rb +1 -1
- data/lib/jets/{rack → mega}/request.rb +17 -4
- data/lib/jets/middleware.rb +38 -0
- data/lib/jets/middleware/configurator.rb +84 -0
- data/lib/jets/middleware/default_stack.rb +44 -0
- data/lib/jets/middleware/layer.rb +34 -0
- data/lib/jets/middleware/stack.rb +77 -0
- data/lib/jets/resource/function.rb +1 -1
- data/lib/jets/ruby_server.rb +1 -1
- data/lib/jets/server.rb +48 -13
- data/lib/jets/version.rb +1 -1
- metadata +24 -17
- data/lib/jets/application/middleware.rb +0 -23
- data/lib/jets/default/application.rb +0 -23
- data/lib/jets/rack.rb +0 -7
- data/lib/jets/rack/server.rb +0 -47
- data/lib/jets/server/api_gateway.rb +0 -39
- data/lib/jets/server/timing_middleware.rb +0 -33
- data/lib/jets/timing.rb +0 -65
- data/lib/jets/timing/report.rb +0 -82
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
|
3
|
+
# Handles mimicking of API Gateway to Lambda function call locally
|
4
|
+
module Jets::Controller::Middleware
|
5
|
+
class Local
|
6
|
+
extend Memoist
|
7
|
+
|
8
|
+
autoload :ApiGateway, 'jets/controller/middleware/local/api_gateway'
|
9
|
+
autoload :MimicAwsCall, 'jets/controller/middleware/local/mimic_aws_call'
|
10
|
+
autoload :RouteMatcher, 'jets/controller/middleware/local/route_matcher'
|
11
|
+
|
12
|
+
def initialize(app)
|
13
|
+
@app = app
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(env)
|
17
|
+
route = RouteMatcher.new(env).find_route
|
18
|
+
unless route
|
19
|
+
return [404, {'Content-Type' => 'text/html'}, not_found(env)]
|
20
|
+
end
|
21
|
+
|
22
|
+
mimic = MimicAwsCall.new(route, env)
|
23
|
+
# Make @controller and @meth instance available so we dont not have to pass it around.
|
24
|
+
@controller, @meth, @event = mimic.controller, mimic.meth, mimic.event
|
25
|
+
|
26
|
+
if route.to == 'jets/rack#process' # megamode
|
27
|
+
# Bypass the Jets middlewares since it could interfere with the Rack
|
28
|
+
# application's middleware stack.
|
29
|
+
#
|
30
|
+
# Rails sends back a transfer-encoding=chunked. Curling Rails directly works,
|
31
|
+
# but passing the Rails response back through this middleware results in errors.
|
32
|
+
# Disable chunking responses by deleting the transfer-encoding response header.
|
33
|
+
# Would like to understand why this happens this better, if someone can explain please let me know.
|
34
|
+
status, headers, body = @controller.dispatch! # jets/rack_controller
|
35
|
+
headers.delete "transfer-encoding"
|
36
|
+
[status, headers, body]
|
37
|
+
elsif polymorphic_function?
|
38
|
+
# Will never hit when calling polymorphic function on AWS Lambda.
|
39
|
+
# This can only really get called with the local server.
|
40
|
+
run_polymophic_function
|
41
|
+
else # Normal Jets request
|
42
|
+
mimick_aws_lambda!(env, mimic.vars) unless on_aws?(env)
|
43
|
+
@app.call(env)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def polymorphic_function?
|
48
|
+
polymorphic_function.task.lang != :ruby
|
49
|
+
end
|
50
|
+
|
51
|
+
def polymorphic_function
|
52
|
+
# Abusing PolyFun to run polymorphic code, should call LambdaExecutor directly
|
53
|
+
# after reworking LambdaExecutor so it has a better interface.
|
54
|
+
Jets::PolyFun.new(@controller.class, @meth)
|
55
|
+
end
|
56
|
+
memoize :polymorphic_function
|
57
|
+
|
58
|
+
def run_polymophic_function
|
59
|
+
resp = polymorphic_function.run(@event, @meth) # polymorphic code
|
60
|
+
status = resp['statusCode']
|
61
|
+
headers = resp['headers']
|
62
|
+
body = StringIO.new(resp['body'])
|
63
|
+
[status, headers, body] # triplet
|
64
|
+
end
|
65
|
+
|
66
|
+
# Modifies env the in the same way real call from AWS lambda would modify env
|
67
|
+
def mimick_aws_lambda!(env, vars)
|
68
|
+
env.merge!(vars)
|
69
|
+
env
|
70
|
+
end
|
71
|
+
|
72
|
+
def on_aws?(env)
|
73
|
+
return false if ENV['TEST'] # usually with test we're passing in full API Gateway fixtures with the HTTP_X_AMZN_TRACE_ID
|
74
|
+
!!env['HTTP_X_AMZN_TRACE_ID']
|
75
|
+
end
|
76
|
+
|
77
|
+
def routes_error_message(env)
|
78
|
+
message = "<h2>404 Error: Route #{env['PATH_INFO'].sub('/','')} not found</h2>"
|
79
|
+
if Jets.env != "production"
|
80
|
+
message << "<p>Here are the routes defined in your application:</p>"
|
81
|
+
message << "#{routes_table}"
|
82
|
+
end
|
83
|
+
message
|
84
|
+
end
|
85
|
+
|
86
|
+
def not_found(env)
|
87
|
+
message = routes_error_message(env)
|
88
|
+
body = <<~HTML
|
89
|
+
<!DOCTYPE html>
|
90
|
+
<html>
|
91
|
+
<head>
|
92
|
+
<meta charset="utf-8">
|
93
|
+
<title>Route not found</title>
|
94
|
+
</head>
|
95
|
+
<body>
|
96
|
+
#{message}
|
97
|
+
</body>
|
98
|
+
</html>
|
99
|
+
HTML
|
100
|
+
StringIO.new(body)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Show pretty route table for user to help with debugging in non-production mode
|
104
|
+
def routes_table
|
105
|
+
routes = Jets::Router.routes
|
106
|
+
|
107
|
+
return "Your routes table is empty." if routes.empty?
|
108
|
+
|
109
|
+
text = "Verb | Path | Controller#action\n"
|
110
|
+
text << "--- | --- | ---\n"
|
111
|
+
routes.each do |route|
|
112
|
+
text << "#{route.method} | #{route.path} | #{route.to}\n"
|
113
|
+
end
|
114
|
+
html = Kramdown::Document.new(text).to_html
|
115
|
+
puts html
|
116
|
+
html
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -1,38 +1,13 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Takes a Rack env and converts to ApiGateway event
|
2
|
+
class Jets::Controller::Middleware::Local
|
3
|
+
class ApiGateway
|
4
|
+
extend Memoist
|
3
5
|
|
4
|
-
class Jets::Server
|
5
|
-
# This doesnt really need to be middleware
|
6
|
-
class LambdaAwsProxy
|
7
6
|
def initialize(route, env)
|
8
|
-
@route = route
|
9
|
-
@env = env
|
10
|
-
# puts "Rack env:".colorize(:yellow)
|
11
|
-
# @env.each do |k,v|
|
12
|
-
# puts "#{k}: #{v}"
|
13
|
-
# end
|
7
|
+
@route, @env = route, env
|
14
8
|
end
|
15
9
|
|
16
|
-
def
|
17
|
-
event = build_event
|
18
|
-
context = {}
|
19
|
-
|
20
|
-
controller_class = find_controller_class
|
21
|
-
controller_action = find_controller_action
|
22
|
-
|
23
|
-
fun = Jets::PolyFun.new(controller_class, controller_action)
|
24
|
-
resp = fun.run(event, context) # check the logs for polymorphic function errors
|
25
|
-
|
26
|
-
# Map lambda proxy response format to rack format
|
27
|
-
status = resp["statusCode"]
|
28
|
-
headers = resp["headers"] || {}
|
29
|
-
headers = {'Content-Type' => 'text/html'}.merge(headers)
|
30
|
-
body = resp["body"]
|
31
|
-
|
32
|
-
[status, headers, [body]]
|
33
|
-
end
|
34
|
-
|
35
|
-
def build_event
|
10
|
+
def event
|
36
11
|
resource = @route.path(:api_gateway) # posts/{id}/edit
|
37
12
|
path = @env['PATH_INFO'].sub('/','') # remove beginning slash
|
38
13
|
{
|
@@ -48,6 +23,7 @@ class Jets::Server
|
|
48
23
|
"isBase64Encoded" => false,
|
49
24
|
}
|
50
25
|
end
|
26
|
+
memoize :event
|
51
27
|
|
52
28
|
# Annoying. The headers part of the AWS Lambda proxy structure
|
53
29
|
# does not consisently use the same casing scheme for the header keys.
|
@@ -97,12 +73,6 @@ class Jets::Server
|
|
97
73
|
end
|
98
74
|
end
|
99
75
|
|
100
|
-
# Way to fake X-Amzn-Trace-Id which on_aws? helper checks.
|
101
|
-
# This is how we distinguish a request from API gateway vs local.
|
102
|
-
if ENV['JETS_ON_AWS']
|
103
|
-
headers["X-Amzn-Trace-Id"] = "Root=fake-trace-id"
|
104
|
-
end
|
105
|
-
|
106
76
|
headers
|
107
77
|
end
|
108
78
|
|
@@ -114,21 +84,13 @@ class Jets::Server
|
|
114
84
|
# rack.input: #<StringIO:0x007f8ccf8db9a0>
|
115
85
|
def get_body
|
116
86
|
# @env["rack.input"] is always provided by rack and we should make
|
117
|
-
# the test data always have rack.input to mimic rack
|
118
|
-
#
|
87
|
+
# the test data always have rack.input to mimic rack defaulting to
|
88
|
+
# StringIO.new to help make testing easier
|
119
89
|
input = @env["rack.input"] || StringIO.new
|
120
90
|
body = input.read
|
121
|
-
#
|
91
|
+
input.rewind # IMPORTANT or else it screws up other middlewares that use the body
|
92
|
+
# return nil for blank string, because Lambda AWS_PROXY does this
|
122
93
|
body unless body.empty?
|
123
94
|
end
|
124
|
-
|
125
|
-
def find_controller_class
|
126
|
-
# posts#edit => PostsController
|
127
|
-
@route.controller_name.constantize
|
128
|
-
end
|
129
|
-
|
130
|
-
def find_controller_action
|
131
|
-
@route.action_name
|
132
|
-
end
|
133
95
|
end
|
134
96
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Jets::Controller::Middleware::Local
|
2
|
+
class MimicAwsCall
|
3
|
+
extend Memoist
|
4
|
+
|
5
|
+
def initialize(route, env)
|
6
|
+
@route, @env = route, env
|
7
|
+
end
|
8
|
+
|
9
|
+
def vars
|
10
|
+
{
|
11
|
+
'jets.controller' => controller,
|
12
|
+
'lambda.context' => context,
|
13
|
+
'lambda.event' => event,
|
14
|
+
'lambda.meth' => meth,
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Actual controller instance
|
19
|
+
def controller
|
20
|
+
controller_class = @route.controller_name.constantize
|
21
|
+
meth = @route.action_name
|
22
|
+
controller_class.new(event, context, meth)
|
23
|
+
end
|
24
|
+
|
25
|
+
def meth
|
26
|
+
@route.action_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def event
|
30
|
+
ApiGateway.new(@route, @env).event
|
31
|
+
end
|
32
|
+
memoize :event
|
33
|
+
|
34
|
+
def context
|
35
|
+
{}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Jets::
|
1
|
+
class Jets::Controller::Middleware::Local
|
2
2
|
class RouteMatcher
|
3
3
|
def initialize(env)
|
4
4
|
@env = env
|
@@ -12,14 +12,14 @@ class Jets::Server
|
|
12
12
|
# Within these 2 groups we consider the routes with the longest path first
|
13
13
|
# since posts/:id and posts/:id/edit can both match.
|
14
14
|
routes = router.ordered_routes
|
15
|
-
route = routes.find do |
|
16
|
-
route_found?(
|
15
|
+
route = routes.find do |r|
|
16
|
+
route_found?(r)
|
17
17
|
end
|
18
18
|
route
|
19
19
|
end
|
20
20
|
|
21
21
|
def route_found?(route)
|
22
|
-
request_method = @env["REQUEST_METHOD"]
|
22
|
+
request_method = @env["REQUEST_METHOD"] || "GET"
|
23
23
|
actual_path = @env["PATH_INFO"].sub(/^\//,'') # remove beginning slash
|
24
24
|
|
25
25
|
# Immediately stop checking when the request method: GET, POST, ANY, etc
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# All roads lead here
|
2
|
+
#
|
3
|
+
# 1. AWS Lambda: PostsController - Rack::Adapter - Jets.application.call
|
4
|
+
# 2. Local server: config.ru - run Jet.application - Jets.application.call
|
5
|
+
#
|
6
|
+
# Then eventually:
|
7
|
+
#
|
8
|
+
# Jets.application.call - Middleware stack - Jets::Controller::Middleware::Main
|
9
|
+
#
|
10
|
+
module Jets::Controller::Middleware
|
11
|
+
class Main
|
12
|
+
def initialize(env)
|
13
|
+
@env = env
|
14
|
+
@controller = env['jets.controller']
|
15
|
+
@event = env['lambda.event']
|
16
|
+
@context = env['lambda.context']
|
17
|
+
@meth = env['lambda.meth']
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
dup.call!
|
22
|
+
end
|
23
|
+
|
24
|
+
def call!
|
25
|
+
setup
|
26
|
+
@controller.dispatch! # Returns triplet
|
27
|
+
end
|
28
|
+
|
29
|
+
# Common setup logical at this point of middleware processing right before
|
30
|
+
# calling any controller actions.
|
31
|
+
def setup
|
32
|
+
# We already recreated a mimicke rack env earlier as part of the very first
|
33
|
+
# middleware layer. However, by the time the rack env reaches the main middleware
|
34
|
+
# it could had been updated by other middlewares. We update the env here again.
|
35
|
+
@controller.request.set_env!(@env)
|
36
|
+
# This allows sesison helpers to work. Sessions are managed by
|
37
|
+
# the Rack::Session::Cookie middleware by default.
|
38
|
+
@controller.session = @env['rack.session'] || {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.call(env)
|
42
|
+
instance = new(env)
|
43
|
+
instance.call
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "action_controller/metal/strong_parameters"
|
2
|
+
require "rack"
|
2
3
|
|
3
4
|
class Jets::Controller
|
4
5
|
module Params
|
@@ -39,7 +40,7 @@ class Jets::Controller
|
|
39
40
|
# API Gateway seems to use either: content-type or Content-Type
|
40
41
|
content_type = headers["content-type"]
|
41
42
|
if content_type.to_s.include?("application/x-www-form-urlencoded")
|
42
|
-
return Rack::Utils.parse_nested_query(body)
|
43
|
+
return ::Rack::Utils.parse_nested_query(body)
|
43
44
|
end
|
44
45
|
|
45
46
|
{} # fallback to empty Hash
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Jets::Controller::Rack
|
2
|
+
class Adapter
|
3
|
+
extend Memoist
|
4
|
+
|
5
|
+
# Returns back API Gateway response hash structure
|
6
|
+
def self.process(event, context, meth)
|
7
|
+
adapter = new(event, context, meth)
|
8
|
+
adapter.process
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(event, context, meth)
|
12
|
+
@event, @context, @meth = event, context, meth
|
13
|
+
end
|
14
|
+
|
15
|
+
# 1. Convert API Gateway event event to Rack env
|
16
|
+
# 2. Process using full Rack middleware stack
|
17
|
+
# 3. Convert back to API gateway response structure payload
|
18
|
+
def process
|
19
|
+
status, headers, body = Jets.application.call(env)
|
20
|
+
convert_to_api_gateway(status, headers, body)
|
21
|
+
end
|
22
|
+
|
23
|
+
def env
|
24
|
+
Env.new(@event, @context).convert # convert to Rack env
|
25
|
+
end
|
26
|
+
memoize :env
|
27
|
+
|
28
|
+
# Transform the structure to AWS_PROXY compatiable structure
|
29
|
+
# http://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
|
30
|
+
def convert_to_api_gateway(status, headers, body)
|
31
|
+
base64 = headers["x-jets-base64"] == 'true'
|
32
|
+
body = body.respond_to?(:read) ? body.read : body
|
33
|
+
{
|
34
|
+
"statusCode" => status,
|
35
|
+
"headers" => headers,
|
36
|
+
"body" => body,
|
37
|
+
"isBase64Encoded" => base64,
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
# Called from Jets::Controller::Base.process. Example:
|
42
|
+
#
|
43
|
+
# adapter.rack_vars(
|
44
|
+
# 'jets.controller' => self,
|
45
|
+
# 'lambda.context' => context,
|
46
|
+
# 'lambda.event' => event,
|
47
|
+
# 'lambda.meth' => meth,
|
48
|
+
# )
|
49
|
+
#
|
50
|
+
# Passes a these special variables so we have access to them in the middleware.
|
51
|
+
# The controller instance is called in the Main middleware.
|
52
|
+
# The lambda.* info is used by the Rack::Local middleware to create a mimicked
|
53
|
+
# controller for the local server.
|
54
|
+
#
|
55
|
+
def rack_vars(vars)
|
56
|
+
env.merge!(vars)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
# Takes an ApiGateway event and converts it to an Rack env that can be used for
|
4
|
+
# rack.call(env).
|
5
|
+
module Jets::Controller::Rack
|
6
|
+
class Env
|
7
|
+
def initialize(event, context)
|
8
|
+
@event, @context = event, context
|
9
|
+
end
|
10
|
+
|
11
|
+
def convert
|
12
|
+
options = {}
|
13
|
+
options = add_top_level(options)
|
14
|
+
options = add_http_headers(options)
|
15
|
+
path = @event['path'] || '/' # always set by API Gateway but might not be when testing shim, so setting it to make testing easier
|
16
|
+
Rack::MockRequest.env_for(path, options)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def add_top_level(options)
|
21
|
+
map = {
|
22
|
+
'CONTENT_TYPE' => content_type,
|
23
|
+
'QUERY_STRING' => query_string,
|
24
|
+
'REMOTE_ADDR' => headers['X-Forwarded-For'],
|
25
|
+
'REMOTE_HOST' => headers['Host'],
|
26
|
+
'REQUEST_METHOD' => @event['httpMethod'],
|
27
|
+
'REQUEST_PATH' => @event['path'],
|
28
|
+
'REQUEST_URI' => request_uri,
|
29
|
+
'SCRIPT_NAME' => "",
|
30
|
+
'SERVER_NAME' => headers['Host'],
|
31
|
+
'SERVER_PORT' => headers['X-Forwarded-Port'],
|
32
|
+
'SERVER_PROTOCOL' => "HTTP/1.1", # unsure if this should be set
|
33
|
+
'SERVER_SOFTWARE' => "WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)",
|
34
|
+
}
|
35
|
+
|
36
|
+
map['CONTENT_LENGTH'] = content_length if content_length
|
37
|
+
# Even if not set, Rack always assigns an StringIO to "rack.input"
|
38
|
+
map[:input] = StringIO.new(body) if body
|
39
|
+
|
40
|
+
# TODO: handle decoding base64 encoded body from API Gateaway
|
41
|
+
# Will need to make sure that pass the base64 info via a request header
|
42
|
+
|
43
|
+
options.merge(map)
|
44
|
+
end
|
45
|
+
|
46
|
+
def content_type
|
47
|
+
headers['Content-Type'] || Jets::Controller::DEFAULT_CONTENT_TYPE
|
48
|
+
end
|
49
|
+
|
50
|
+
def content_length
|
51
|
+
bytesize = body.bytesize.to_s if body
|
52
|
+
headers['Content-Length'] || bytesize
|
53
|
+
end
|
54
|
+
|
55
|
+
def body
|
56
|
+
@event['body']
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_http_headers(options)
|
60
|
+
headers.each do |k,v|
|
61
|
+
# content-type => HTTP_CONTENT_TYPE
|
62
|
+
key = k.gsub('-','_').upcase
|
63
|
+
key = "HTTP_#{key}"
|
64
|
+
options[key] = v
|
65
|
+
end
|
66
|
+
options
|
67
|
+
end
|
68
|
+
|
69
|
+
def request_uri
|
70
|
+
# IE: "http://localhost:8888/posts/tung/edit?foo=bar"
|
71
|
+
proto = headers['X-Forwarded-Proto']
|
72
|
+
host = headers['Host']
|
73
|
+
port = headers['X-Forwarded-Port']
|
74
|
+
|
75
|
+
# Add port if needed
|
76
|
+
if proto == 'https' && port != '443' or
|
77
|
+
proto == 'http' && port != '80'
|
78
|
+
host = "#{host}:#{port}"
|
79
|
+
end
|
80
|
+
|
81
|
+
path = @event['path']
|
82
|
+
qs = "?#{query_string}" unless query_string.empty?
|
83
|
+
"#{proto}://#{host}#{path}#{qs}"
|
84
|
+
end
|
85
|
+
|
86
|
+
def query_string
|
87
|
+
qs_params = @event["queryStringParameters"] || {} # always set with API Gateway but when testing node shim might not be
|
88
|
+
hash = Jets::Mega::HashConverter.encode(qs_params)
|
89
|
+
hash.to_query
|
90
|
+
end
|
91
|
+
|
92
|
+
def headers
|
93
|
+
@event['headers'] || {}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|