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
@@ -19,7 +19,7 @@ class Jets::Controller
|
|
19
19
|
|
20
20
|
redirect_url = ensure_protocol(redirect_url)
|
21
21
|
|
22
|
-
aws_proxy = Renderers::
|
22
|
+
aws_proxy = Renderers::RackRenderer.new(self,
|
23
23
|
status: options[:status] || 302,
|
24
24
|
headers: { "Location" => redirect_url },
|
25
25
|
body: "",
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Jets::Controller::Renderers
|
2
|
-
autoload :AwsProxyRenderer, "jets/controller/renderers/aws_proxy_renderer"
|
3
2
|
autoload :BaseRenderer, "jets/controller/renderers/base_renderer"
|
3
|
+
autoload :RackRenderer, "jets/controller/renderers/rack_renderer"
|
4
4
|
autoload :TemplateRenderer, "jets/controller/renderers/template_renderer"
|
5
5
|
end
|
@@ -2,17 +2,10 @@ require "rack/utils"
|
|
2
2
|
|
3
3
|
# Special renderer. All the other renderers lead here
|
4
4
|
module Jets::Controller::Renderers
|
5
|
-
class
|
6
|
-
# Transform the structure to AWS_PROXY compatiable structure
|
7
|
-
# http://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
|
5
|
+
class RackRenderer < BaseRenderer
|
8
6
|
# Example response:
|
9
7
|
#
|
10
|
-
# {
|
11
|
-
# "statusCode" => status,
|
12
|
-
# "headers" => headers,
|
13
|
-
# "body" => body,
|
14
|
-
# "isBase64Encoded" => base64,
|
15
|
-
# }
|
8
|
+
# [200, {"my-header" = > "value" }, "my body" ]
|
16
9
|
def render
|
17
10
|
# we do some normalization here
|
18
11
|
status = map_status_code(@options[:status]) || 200
|
@@ -22,16 +15,11 @@ module Jets::Controller::Renderers
|
|
22
15
|
|
23
16
|
headers = @options[:headers] || {}
|
24
17
|
headers = cors_headers.merge(headers)
|
25
|
-
headers["Content-Type"] ||= @options[:content_type] ||
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
"statusCode" => status,
|
31
|
-
"headers" => headers,
|
32
|
-
"body" => body,
|
33
|
-
"isBase64Encoded" => base64,
|
34
|
-
}
|
18
|
+
headers["Content-Type"] ||= @options[:content_type] || Jets::Controller::DEFAULT_CONTENT_TYPE
|
19
|
+
# x-jets-base64 to convert this Rack triplet to a API Gateway hash structure later
|
20
|
+
headers["x-jets-base64"] = base64 ? "true" : "false"
|
21
|
+
body = StringIO.new(body)
|
22
|
+
[status, headers, body] # triplet
|
35
23
|
end
|
36
24
|
|
37
25
|
# maps:
|
@@ -16,7 +16,7 @@ module Jets::Controller::Renderers
|
|
16
16
|
body = renderer.render(render_options)
|
17
17
|
@options[:body] = body # important to set as it was originally nil
|
18
18
|
|
19
|
-
|
19
|
+
RackRenderer.new(@controller, @options).render
|
20
20
|
end
|
21
21
|
|
22
22
|
# Example: posts/index
|
@@ -1,42 +1,21 @@
|
|
1
|
-
|
1
|
+
require 'rack/request'
|
2
|
+
|
2
3
|
class Jets::Controller
|
3
|
-
class Request
|
4
|
-
def initialize(event)
|
5
|
-
@event = event
|
4
|
+
class Request < ::Rack::Request
|
5
|
+
def initialize(event, context)
|
6
|
+
@event, @context = event, context
|
7
|
+
super(env)
|
6
8
|
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
Accept-Encoding
|
12
|
-
Accept-Language
|
13
|
-
cache-control
|
14
|
-
CloudFront-Forwarded-Proto
|
15
|
-
CloudFront-Is-Desktop-Viewer
|
16
|
-
CloudFront-Is-Mobile-Viewer
|
17
|
-
CloudFront-Is-SmartTV-Viewer
|
18
|
-
CloudFront-Is-Tablet-Viewer
|
19
|
-
CloudFront-Viewer-Country
|
20
|
-
content-type
|
21
|
-
Host
|
22
|
-
origin
|
23
|
-
Referer
|
24
|
-
upgrade-insecure-requests
|
25
|
-
User-Agent
|
26
|
-
Via
|
27
|
-
X-Amz-Cf-Id
|
28
|
-
X-Amzn-Trace-Id
|
29
|
-
X-Forwarded-For
|
30
|
-
X-Forwarded-Port
|
31
|
-
X-Forwarded-Proto
|
32
|
-
].freeze
|
10
|
+
def env
|
11
|
+
@env ||= Jets::Controller::Rack::Env.new(@event, @context).convert # convert to Rack env
|
12
|
+
end
|
33
13
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
METHOD
|
14
|
+
# When request hits the middleware Controller::Rack::Middleware::Main endpoint
|
15
|
+
# We set the it with the updated env since it could had been mutated down the
|
16
|
+
# middleware stack.
|
17
|
+
def set_env!(env)
|
18
|
+
@env = env
|
40
19
|
end
|
41
20
|
|
42
21
|
# API Gateway is inconsistent about how it cases it keys.
|
@@ -46,14 +25,5 @@ class Jets::Controller
|
|
46
25
|
headers = @event["headers"] || {}
|
47
26
|
headers.transform_keys { |key| key.downcase }
|
48
27
|
end
|
49
|
-
|
50
|
-
def xhr?
|
51
|
-
headers["x-requested-with"] == "XMLHttpRequest"
|
52
|
-
end
|
53
|
-
|
54
|
-
def path
|
55
|
-
@event["path"]
|
56
|
-
end
|
57
|
-
|
58
28
|
end
|
59
29
|
end
|
@@ -1,13 +1,61 @@
|
|
1
|
+
require 'rack/response'
|
2
|
+
|
1
3
|
class Jets::Controller
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
# The response object. See Rack::Response and Rack::Response::Helpers for
|
5
|
+
# more info:
|
6
|
+
# http://rubydoc.info/github/rack/rack/master/Rack/Response
|
7
|
+
# http://rubydoc.info/github/rack/rack/master/Rack/Response/Helpers
|
8
|
+
class Response < ::Rack::Response
|
9
|
+
DROP_BODY_RESPONSES = [204, 304]
|
10
|
+
def initialize(*)
|
11
|
+
super
|
12
|
+
# headers['Content-Type'] ||= 'text/html'
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: unsure if we should even have these methods. We dont really use them.
|
16
|
+
def body=(value)
|
17
|
+
value = value.body while Rack::Response === value
|
18
|
+
@body = String === value ? [value.to_str] : value
|
19
|
+
end
|
20
|
+
|
21
|
+
def each
|
22
|
+
block_given? ? super : enum_for(:each)
|
23
|
+
end
|
24
|
+
|
25
|
+
def finish
|
26
|
+
result = body
|
27
|
+
|
28
|
+
if drop_content_info?
|
29
|
+
headers.delete "Content-Length"
|
30
|
+
headers.delete "Content-Type"
|
31
|
+
end
|
32
|
+
|
33
|
+
if drop_body?
|
34
|
+
close
|
35
|
+
result = []
|
36
|
+
end
|
37
|
+
|
38
|
+
if calculate_content_length?
|
39
|
+
# if some other code has already set Content-Length, don't muck with it
|
40
|
+
# currently, this would be the static file-handler
|
41
|
+
headers["Content-Length"] = body.inject(0) { |l, p| l + p.bytesize }.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
[status.to_i, headers, result]
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def calculate_content_length?
|
50
|
+
headers["Content-Type"] and not headers["Content-Length"] and Array === body
|
51
|
+
end
|
52
|
+
|
53
|
+
def drop_content_info?
|
54
|
+
status.to_i / 100 == 1 or drop_body?
|
7
55
|
end
|
8
56
|
|
9
|
-
def
|
10
|
-
|
57
|
+
def drop_body?
|
58
|
+
DROP_BODY_RESPONSES.include?(status.to_i)
|
11
59
|
end
|
12
60
|
end
|
13
61
|
end
|
@@ -4,12 +4,22 @@ class Jets::RackController < Jets::Controller::Base
|
|
4
4
|
|
5
5
|
# Megamode
|
6
6
|
def process
|
7
|
-
resp =
|
7
|
+
resp = mega_request
|
8
8
|
render(resp)
|
9
9
|
end
|
10
10
|
|
11
11
|
private
|
12
|
-
|
13
|
-
|
12
|
+
# Override process! so it doesnt go through middleware adapter and hits
|
13
|
+
# process logic directly. This handles the case for AWS Lambda.
|
14
|
+
# For local server, we adjust the Middleware::Local logic.
|
15
|
+
def process!
|
16
|
+
status, headers, body = dispatch!
|
17
|
+
# Use the adapter only to convert the Rack triplet to a API Gateway hash structure
|
18
|
+
adapter = Jets::Controller::Rack::Adapter.new(event, context, meth)
|
19
|
+
adapter.convert_to_api_gateway(status, headers, body)
|
20
|
+
end
|
21
|
+
|
22
|
+
def mega_request
|
23
|
+
Jets::Mega::Request.new(event, self).proxy
|
14
24
|
end
|
15
25
|
end
|
data/lib/jets/mega.rb
ADDED
@@ -1,18 +1,21 @@
|
|
1
1
|
require 'net/http'
|
2
|
+
require 'rack'
|
2
3
|
|
3
|
-
module Jets::
|
4
|
+
module Jets::Mega
|
4
5
|
class Request
|
5
6
|
def initialize(event, controller)
|
6
7
|
@event = event
|
7
8
|
@controller = controller # Jets::Controller instance
|
8
9
|
end
|
9
10
|
|
10
|
-
def
|
11
|
+
def proxy
|
11
12
|
http_method = @event['httpMethod'] # GET, POST, PUT, DELETE, etc
|
12
13
|
params = @controller.params(raw: true, path_parameters: false)
|
13
14
|
|
14
15
|
uri = URI("http://localhost:9292#{@controller.request.path}") # local rack server
|
15
16
|
http = Net::HTTP.new(uri.host, uri.port)
|
17
|
+
http.open_timeout = 60
|
18
|
+
http.read_timeout = 60
|
16
19
|
|
17
20
|
# Rails sets _method=patch or _method=put as workaround
|
18
21
|
# Falls back to GET when testing in lambda console
|
@@ -20,7 +23,7 @@ module Jets::Rack
|
|
20
23
|
http_class.capitalize!
|
21
24
|
|
22
25
|
request_class = "Net::HTTP::#{http_class}".constantize # IE: Net::HTTP::Get
|
23
|
-
request = request_class.new(
|
26
|
+
request = request_class.new(uri.path)
|
24
27
|
if %w[Post Patch Put].include?(http_class)
|
25
28
|
params = HashConverter.encode(params)
|
26
29
|
request.set_form_data(params)
|
@@ -28,8 +31,18 @@ module Jets::Rack
|
|
28
31
|
|
29
32
|
request = set_headers!(request)
|
30
33
|
|
31
|
-
#
|
34
|
+
# Setup body
|
35
|
+
env = Jets::Controller::Rack::Env.new(@event, {}).convert # convert to Rack env
|
36
|
+
source_request = Rack::Request.new(env)
|
37
|
+
if source_request.body.respond_to?(:read)
|
38
|
+
request.body = source_request.body.read
|
39
|
+
request.content_length = source_request.content_length.to_i
|
40
|
+
source_request.body.rewind
|
41
|
+
end
|
42
|
+
|
32
43
|
response = http.request(request)
|
44
|
+
|
45
|
+
# TODO: handle binary
|
33
46
|
{
|
34
47
|
status: response.code.to_i,
|
35
48
|
headers: response.each_header.to_h,
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Jets
|
2
|
+
module Middleware
|
3
|
+
extend Memoist
|
4
|
+
|
5
|
+
autoload :Configurator, 'jets/middleware/configurator'
|
6
|
+
autoload :DefaultStack, 'jets/middleware/default_stack'
|
7
|
+
autoload :Layer, 'jets/middleware/layer'
|
8
|
+
autoload :Stack, 'jets/middleware/stack'
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
stack = middlewares.build(endpoint)
|
12
|
+
stack.call(env)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Final middleware in the stack
|
16
|
+
def endpoint
|
17
|
+
Jets::Controller::Middleware::Main
|
18
|
+
end
|
19
|
+
|
20
|
+
# Called in Jets::Booter to build middleware stack only once during bootup
|
21
|
+
def build_stack
|
22
|
+
middlewares
|
23
|
+
end
|
24
|
+
|
25
|
+
def middlewares
|
26
|
+
config_middleware.merge_into(default_stack) # returns Jets::Middleware::Stack
|
27
|
+
end
|
28
|
+
memoize :middlewares
|
29
|
+
|
30
|
+
def default_stack
|
31
|
+
Jets::Middleware::DefaultStack.new(Jets.config, Jets.application).build_stack # returns Jets::Middleware::Stack
|
32
|
+
end
|
33
|
+
|
34
|
+
def config_middleware
|
35
|
+
Jets.config.middleware # returns Jets::Middleware::Configurator
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# Based on Rails MiddlewareStackProxy
|
2
|
+
#
|
3
|
+
# Configurator is a proxy for the Jets middleware stack that allows
|
4
|
+
# you to configure middlewares in your application. It works basically as a
|
5
|
+
# command recorder, saving each command to be applied after initialization
|
6
|
+
# over the default middleware stack, so you can add, swap, or remove any
|
7
|
+
# middleware in Jets.
|
8
|
+
#
|
9
|
+
# You can add your own middlewares by using the +config.middleware.use+ method:
|
10
|
+
#
|
11
|
+
# config.middleware.use Magical::Unicorns
|
12
|
+
#
|
13
|
+
# This will put the <tt>Magical::Unicorns</tt> middleware on the end of the stack.
|
14
|
+
# You can use +insert_before+ if you wish to add a middleware before another:
|
15
|
+
#
|
16
|
+
# config.middleware.insert_before Rack::Head, Magical::Unicorns
|
17
|
+
#
|
18
|
+
# There's also +insert_after+ which will insert a middleware after another:
|
19
|
+
#
|
20
|
+
# config.middleware.insert_after Rack::Head, Magical::Unicorns
|
21
|
+
#
|
22
|
+
# Middlewares can also be completely swapped out and replaced with others:
|
23
|
+
#
|
24
|
+
# config.middleware.swap ActionDispatch::Flash, Magical::Unicorns
|
25
|
+
#
|
26
|
+
# And finally they can also be removed from the stack completely:
|
27
|
+
#
|
28
|
+
# config.middleware.delete ActionDispatch::Flash
|
29
|
+
#
|
30
|
+
module Jets::Middleware
|
31
|
+
class Configurator
|
32
|
+
def initialize(operations = [], delete_operations = [])
|
33
|
+
@operations = operations
|
34
|
+
@delete_operations = delete_operations
|
35
|
+
end
|
36
|
+
|
37
|
+
def insert_before(*args, &block)
|
38
|
+
@operations << [__method__, args, block]
|
39
|
+
end
|
40
|
+
|
41
|
+
alias :insert :insert_before
|
42
|
+
|
43
|
+
def insert_after(*args, &block)
|
44
|
+
@operations << [__method__, args, block]
|
45
|
+
end
|
46
|
+
|
47
|
+
def swap(*args, &block)
|
48
|
+
@operations << [__method__, args, block]
|
49
|
+
end
|
50
|
+
|
51
|
+
def use(*args, &block)
|
52
|
+
@operations << [__method__, args, block]
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete(*args, &block)
|
56
|
+
@delete_operations << [__method__, args, block]
|
57
|
+
end
|
58
|
+
|
59
|
+
def unshift(*args, &block)
|
60
|
+
@operations << [__method__, args, block]
|
61
|
+
end
|
62
|
+
|
63
|
+
def merge_into(other) #:nodoc:
|
64
|
+
(@operations + @delete_operations).each do |operation, args, block|
|
65
|
+
other.send(operation, *args, &block)
|
66
|
+
end
|
67
|
+
|
68
|
+
other
|
69
|
+
end
|
70
|
+
|
71
|
+
def +(other) # :nodoc:
|
72
|
+
Configurator.new(@operations + other.operations, @delete_operations + other.delete_operations)
|
73
|
+
end
|
74
|
+
|
75
|
+
protected
|
76
|
+
def operations
|
77
|
+
@operations
|
78
|
+
end
|
79
|
+
|
80
|
+
def delete_operations
|
81
|
+
@delete_operations
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Jets::Middleware
|
2
|
+
class DefaultStack
|
3
|
+
attr_reader :config, :app
|
4
|
+
def initialize(app, config)
|
5
|
+
@app = app
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_stack
|
10
|
+
Stack.new do |middleware|
|
11
|
+
middleware.use Jets::Controller::Middleware::Local # mimics AWS Lambda for local server only
|
12
|
+
middleware.use Rack::Runtime
|
13
|
+
middleware.use Rack::MethodOverride
|
14
|
+
middleware.use session_store, session_options # use session_store, session_options
|
15
|
+
middleware.use Rack::Head
|
16
|
+
middleware.use Rack::ConditionalGet
|
17
|
+
middleware.use Rack::ETag
|
18
|
+
use_webpacker(middleware)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
# Written as method to easily not include webpacker for case when either
|
24
|
+
# webpacker not installed at all or disabled upon `jets deploy`.
|
25
|
+
def use_webpacker(middleware)
|
26
|
+
return unless Jets.webpacker? # checks for local development if webpacker installed
|
27
|
+
# Different check for middleware because we need webpacker helpers for url helpers.
|
28
|
+
# But we dont want to actually serve via webpacker middleware when running on AWS.
|
29
|
+
# By this time the url helpers are serving assets out of s3.
|
30
|
+
return if File.exist?("#{Jets.root}config/disable-webpacker-middleware.txt") # created as part of `jets deploy`
|
31
|
+
require "jets/controller/middleware/webpacker_setup"
|
32
|
+
middleware.use Webpacker::DevServerProxy
|
33
|
+
end
|
34
|
+
|
35
|
+
def session_store
|
36
|
+
Jets.config.session[:store] # do not use dot notation. session.store is a method on ActiveSupport::OrderedOptions.new
|
37
|
+
end
|
38
|
+
|
39
|
+
def session_options
|
40
|
+
defaults = { secret: ENV['SECRET_KEY_BASE'] }
|
41
|
+
defaults.merge(Jets.config.session.options)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|