falcon 0.36.4 → 0.36.5
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/lib/falcon/adapters/early_hints.rb +8 -0
- data/lib/falcon/adapters/input.rb +32 -11
- data/lib/falcon/adapters/output.rb +20 -1
- data/lib/falcon/adapters/rack.rb +59 -32
- data/lib/falcon/adapters/response.rb +23 -1
- data/lib/falcon/adapters/rewindable.rb +10 -3
- data/lib/falcon/command.rb +2 -0
- data/lib/falcon/command/host.rb +13 -2
- data/lib/falcon/command/paths.rb +4 -0
- data/lib/falcon/command/proxy.rb +14 -0
- data/lib/falcon/command/redirect.rb +12 -0
- data/lib/falcon/command/serve.rb +22 -15
- data/lib/falcon/command/supervisor.rb +15 -1
- data/lib/falcon/command/top.rb +16 -0
- data/lib/falcon/command/virtual.rb +15 -0
- data/lib/falcon/configuration.rb +69 -7
- data/lib/falcon/controller/host.rb +12 -0
- data/lib/falcon/controller/proxy.rb +13 -0
- data/lib/falcon/controller/redirect.rb +7 -0
- data/lib/falcon/controller/serve.rb +14 -1
- data/lib/falcon/controller/virtual.rb +17 -0
- data/lib/falcon/endpoint.rb +8 -0
- data/lib/falcon/{configuration/proxy.rb → environments.rb} +9 -5
- data/lib/falcon/environments/application.rb +68 -0
- data/lib/falcon/{configuration/application.rb → environments/lets_encrypt_tls.rb} +21 -20
- data/lib/falcon/{configuration/lets_encrypt_tls.rb → environments/proxy.rb} +13 -6
- data/lib/falcon/{configuration → environments}/rack.rb +14 -2
- data/lib/falcon/{configuration → environments}/self_signed_tls.rb +9 -1
- data/lib/falcon/{configuration → environments}/supervisor.rb +19 -5
- data/lib/falcon/{configuration → environments}/tls.rb +39 -5
- data/lib/falcon/extensions/openssl.rb +1 -0
- data/lib/falcon/middleware/proxy.rb +26 -5
- data/lib/falcon/middleware/redirect.rb +11 -0
- data/lib/falcon/{verbose.rb → middleware/verbose.rb} +34 -26
- data/lib/falcon/proxy_endpoint.rb +21 -0
- data/lib/falcon/server.rb +8 -2
- data/lib/falcon/service/application.rb +9 -0
- data/lib/falcon/service/generic.rb +18 -0
- data/lib/falcon/service/proxy.rb +6 -0
- data/lib/falcon/service/supervisor.rb +13 -1
- data/lib/falcon/services.rb +21 -0
- data/lib/falcon/tls.rb +4 -2
- data/lib/falcon/version.rb +1 -1
- data/lib/rack/handler/falcon.rb +7 -1
- metadata +16 -72
- data/.editorconfig +0 -5
- data/.github/FUNDING.yml +0 -3
- data/.github/workflows/development.yml +0 -60
- data/.gitignore +0 -14
- data/.rspec +0 -3
- data/Gemfile +0 -17
- data/README.md +0 -316
- data/examples/beer/config.ru +0 -57
- data/examples/beer/falcon.rb +0 -8
- data/examples/benchmark/config.ru +0 -39
- data/examples/benchmark/falcon.rb +0 -6
- data/examples/csv/config.ru +0 -31
- data/examples/google/falcon.rb +0 -14
- data/examples/hello/config.ru +0 -22
- data/examples/hello/falcon.rb +0 -24
- data/examples/hello/preload.rb +0 -7
- data/examples/internet/config.ru +0 -54
- data/examples/memory/allocations.rb +0 -39
- data/examples/memory/config.ru +0 -14
- data/examples/push/client.rb +0 -29
- data/examples/push/config.ru +0 -28
- data/examples/push/index.html +0 -14
- data/examples/push/script.js +0 -2
- data/examples/push/style.css +0 -4
- data/examples/redis/Gemfile +0 -9
- data/examples/redis/config.ru +0 -28
- data/examples/sequel/Gemfile +0 -4
- data/examples/sequel/config.ru +0 -8
- data/examples/sequel/data.sqlite3 +0 -0
- data/examples/server/standalone.rb +0 -27
- data/examples/sinatra/Gemfile +0 -7
- data/examples/sinatra/Gemfile.lock +0 -53
- data/examples/sinatra/config.ru +0 -16
- data/examples/trailers/config.ru +0 -34
- data/examples/trailers/falcon.rb +0 -8
- data/falcon.gemspec +0 -45
- data/gems/rack1.gemfile +0 -4
- data/gems/rack3.gemfile +0 -4
- data/logo-square.afdesign +0 -0
- data/logo.afdesign +0 -0
- data/logo.svg +0 -107
- data/server.rb +0 -21
- data/tasks/benchmark.rake +0 -103
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5f107eaf9cd170b5a399f5ad13222504f99e061292be94aab8720b7efa70c8b
|
4
|
+
data.tar.gz: 9787ecd87ba56f416b24abb02f55f16f7c3de3f3c89090c7724c63030995d8f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '034873da8c3ca3e809bc3144879ab46521b63d279fc3622501b0ab6348d24a36428fa5d6285455091d8eb542ad5ae39b4b42a594efb6052b5b4632aed75d103b'
|
7
|
+
data.tar.gz: b7e68e1c275ee07ee752228ad04a90ea0da0a658f467030a4e849fc3c0661f78f706ea4243460da12cfe2e7610233d59c5ff0d91f0b5092e767d3f452f372567
|
@@ -24,17 +24,25 @@ require 'protocol/http/middleware'
|
|
24
24
|
|
25
25
|
module Falcon
|
26
26
|
module Adapters
|
27
|
+
# Provide an interface for advising the client to preload related resources.
|
27
28
|
class EarlyHints
|
28
29
|
PRELOAD = /<(?<path>.*?)>;.*?rel=preload/
|
29
30
|
|
31
|
+
# Initialize the early hints interface.
|
32
|
+
#
|
33
|
+
# @parameter request [Protocol::HTTP::Request]
|
30
34
|
def initialize(request)
|
31
35
|
@request = request
|
32
36
|
end
|
33
37
|
|
38
|
+
# Advise the request that the specified path should be preloaded.
|
39
|
+
# @parameter path [String]
|
40
|
+
# @parameter preload [Boolean] whether the client should preload the resource.
|
34
41
|
def push(path, preload: true, **options)
|
35
42
|
@request.push(path)
|
36
43
|
end
|
37
44
|
|
45
|
+
# Extract link headers and invoke {push}.
|
38
46
|
def call(headers)
|
39
47
|
headers.each do |key, value|
|
40
48
|
if key.casecmp("link").zero? and match = PRELOAD.match(value)
|
@@ -25,8 +25,14 @@ require 'protocol/http/body/rewindable'
|
|
25
25
|
|
26
26
|
module Falcon
|
27
27
|
module Adapters
|
28
|
-
#
|
28
|
+
# Wraps a streaming input body into the interface required by `rack.input`.
|
29
|
+
#
|
30
|
+
# The input stream is an `IO`-like object which contains the raw HTTP POST data. When applicable, its external encoding must be `ASCII-8BIT` and it must be opened in binary mode, for Ruby 1.9 compatibility. The input stream must respond to `gets`, `each`, `read` and `rewind`.
|
31
|
+
#
|
32
|
+
# This implementation is not always rewindable, to avoid buffering the input when handling large uploads. See {Rewindable} for more details.
|
29
33
|
class Input
|
34
|
+
# Initialize the input wrapper.
|
35
|
+
# @parameter body [Protocol::HTTP::Body::Readable]
|
30
36
|
def initialize(body)
|
31
37
|
@body = body
|
32
38
|
|
@@ -35,9 +41,13 @@ module Falcon
|
|
35
41
|
@finished = @body.nil?
|
36
42
|
end
|
37
43
|
|
44
|
+
# The input body.
|
45
|
+
# @attribute [Protocol::HTTP::Body::Readable]
|
38
46
|
attr :body
|
39
47
|
|
40
|
-
#
|
48
|
+
# Enumerate chunks of the request body.
|
49
|
+
# @yields {|chunk| ...}
|
50
|
+
# @parameter chunk [String]
|
41
51
|
def each(&block)
|
42
52
|
return to_enum unless block_given?
|
43
53
|
|
@@ -46,8 +56,11 @@ module Falcon
|
|
46
56
|
end
|
47
57
|
end
|
48
58
|
|
49
|
-
#
|
50
|
-
#
|
59
|
+
# Rewind the input stream back to the start.
|
60
|
+
#
|
61
|
+
# `rewind` must be called without arguments. It rewinds the input stream back to the beginning. It must not raise Errno::ESPIPE: that is, it may not be a pipe or a socket. Therefore, handler developers must buffer the input data into some rewindable object if the underlying input stream is not rewindable.
|
62
|
+
#
|
63
|
+
# @returns [Boolean] Whether the body could be rewound.
|
51
64
|
def rewind
|
52
65
|
if @body and @body.respond_to? :rewind
|
53
66
|
# If the body is not rewindable, this will fail.
|
@@ -61,10 +74,13 @@ module Falcon
|
|
61
74
|
return false
|
62
75
|
end
|
63
76
|
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
77
|
+
# Read data from the input stream.
|
78
|
+
#
|
79
|
+
# `read` behaves like `IO#read`. Its signature is `read(length = nil, buffer = nil)`. If given, length must be a non-negative `Integer` (>= 0) or `nil`, and buffer must be a `String` and may not be nil. If `length` is given and not `nil`, then this method reads at most `length` bytes from the input stream. If `length` is not given or `nil`, then this method reads all data. When the end is reached, this method returns `nil` if `length` is given and not `nil`, or an empty `String` if `length` is not given or is `nil`. If `buffer` is given, then the read data will be placed into the `buffer` instead of a newly created `String` object.
|
80
|
+
#
|
81
|
+
# @parameter length [Integer] the amount of data to read
|
82
|
+
# @parameter buffer [String] the buffer which will receive the data
|
83
|
+
# @returns a buffer containing the data
|
68
84
|
def read(length = nil, buffer = nil)
|
69
85
|
buffer ||= Async::IO::Buffer.new
|
70
86
|
buffer.clear
|
@@ -93,12 +109,17 @@ module Falcon
|
|
93
109
|
return buffer
|
94
110
|
end
|
95
111
|
|
112
|
+
# Has the input stream been read completely?
|
113
|
+
# @returns [Boolean]
|
96
114
|
def eof?
|
97
115
|
@finished and @buffer.nil?
|
98
116
|
end
|
99
117
|
|
100
|
-
#
|
101
|
-
#
|
118
|
+
# Read the next chunk of data from the input stream.
|
119
|
+
#
|
120
|
+
# `gets` must be called without arguments and return a `String`, or `nil` when the input stream has no more data.
|
121
|
+
#
|
122
|
+
# @returns [String | Nil] The next chunk from the body.
|
102
123
|
def gets
|
103
124
|
if @buffer.nil?
|
104
125
|
return read_next
|
@@ -109,7 +130,7 @@ module Falcon
|
|
109
130
|
end
|
110
131
|
end
|
111
132
|
|
112
|
-
#
|
133
|
+
# Close and discard the remainder of the input stream.
|
113
134
|
def close
|
114
135
|
@body&.close
|
115
136
|
end
|
@@ -26,11 +26,15 @@ require 'protocol/http/body/file'
|
|
26
26
|
module Falcon
|
27
27
|
module Adapters
|
28
28
|
# Wraps the rack response body.
|
29
|
-
#
|
29
|
+
#
|
30
|
+
# The `rack` body must respond to `each` and must only yield `String` values. If the body responds to `close`, it will be called after iteration. If the body is replaced by a middleware after action, the original body must be closed first, if it responds to `close`. If the body responds to `to_path`, it must return a String identifying the location of a file whose contents are identical to that produced by calling `each`; this may be used by the server as an alternative, possibly more efficient way to transport the response. The body commonly is an `Array` of strings, the application instance itself, or a `File`-like object.
|
30
31
|
class Output < ::Protocol::HTTP::Body::Readable
|
31
32
|
CONTENT_LENGTH = 'content-length'.freeze
|
32
33
|
|
33
34
|
# Wraps an array into a buffered body.
|
35
|
+
# @parameter status [Integer] The response status.
|
36
|
+
# @parameter headers [Protocol::HTTP::Headers] The response headers.
|
37
|
+
# @parameter body [Object] The `rack` response body.
|
34
38
|
def self.wrap(status, headers, body)
|
35
39
|
# In no circumstance do we want this header propagating out:
|
36
40
|
if length = headers.delete(CONTENT_LENGTH)
|
@@ -51,6 +55,9 @@ module Falcon
|
|
51
55
|
end
|
52
56
|
end
|
53
57
|
|
58
|
+
# Initialize the output wrapper.
|
59
|
+
# @parameter body [Object] The rack response body.
|
60
|
+
# @parameter length [Integer] The rack response length.
|
54
61
|
def initialize(body, length)
|
55
62
|
@length = length
|
56
63
|
@body = body
|
@@ -64,10 +71,17 @@ module Falcon
|
|
64
71
|
# The content length of the rack response body.
|
65
72
|
attr :length
|
66
73
|
|
74
|
+
# Whether the body is empty.
|
67
75
|
def empty?
|
68
76
|
@length == 0 or (@body.respond_to?(:empty?) and @body.empty?)
|
69
77
|
end
|
70
78
|
|
79
|
+
# Whether the body can be read immediately.
|
80
|
+
def ready?
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
# Close the response body.
|
71
85
|
def close(error = nil)
|
72
86
|
if @body and @body.respond_to?(:close)
|
73
87
|
@body.close
|
@@ -79,12 +93,17 @@ module Falcon
|
|
79
93
|
super
|
80
94
|
end
|
81
95
|
|
96
|
+
# Enumerate the response body.
|
97
|
+
# @yields {|chunk| ...}
|
98
|
+
# @parameter chunk [String]
|
82
99
|
def each(&block)
|
83
100
|
@body.each(&block)
|
84
101
|
ensure
|
85
102
|
self.close($!)
|
86
103
|
end
|
87
104
|
|
105
|
+
# Read the next chunk from the response body.
|
106
|
+
# @returns [String | Nil]
|
88
107
|
def read
|
89
108
|
@chunks ||= @body.to_enum(:each)
|
90
109
|
|
data/lib/falcon/adapters/rack.rb
CHANGED
@@ -31,40 +31,48 @@ require 'async/logger'
|
|
31
31
|
module Falcon
|
32
32
|
module Adapters
|
33
33
|
class Rack
|
34
|
-
# CGI keys
|
35
|
-
HTTP_HOST = 'HTTP_HOST'.freeze
|
36
|
-
PATH_INFO = 'PATH_INFO'.freeze
|
37
|
-
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
38
|
-
REQUEST_PATH = 'REQUEST_PATH'.freeze
|
39
|
-
REQUEST_URI = 'REQUEST_URI'.freeze
|
40
|
-
SCRIPT_NAME = 'SCRIPT_NAME'.freeze
|
41
|
-
QUERY_STRING = 'QUERY_STRING'.freeze
|
42
|
-
SERVER_PROTOCOL = 'SERVER_PROTOCOL'.freeze
|
43
|
-
SERVER_NAME = 'SERVER_NAME'.freeze
|
44
|
-
SERVER_PORT = 'SERVER_PORT'.freeze
|
45
|
-
REMOTE_ADDR = 'REMOTE_ADDR'.freeze
|
46
|
-
CONTENT_TYPE = 'CONTENT_TYPE'.freeze
|
47
|
-
CONTENT_LENGTH = 'CONTENT_LENGTH'.freeze
|
34
|
+
# CGI keys <https://tools.ietf.org/html/rfc3875#section-4.1>:
|
48
35
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
36
|
+
HTTP_HOST = 'HTTP_HOST'
|
37
|
+
PATH_INFO = 'PATH_INFO'
|
38
|
+
REQUEST_METHOD = 'REQUEST_METHOD'
|
39
|
+
REQUEST_PATH = 'REQUEST_PATH'
|
40
|
+
REQUEST_URI = 'REQUEST_URI'
|
41
|
+
SCRIPT_NAME = 'SCRIPT_NAME'
|
42
|
+
QUERY_STRING = 'QUERY_STRING'
|
43
|
+
SERVER_PROTOCOL = 'SERVER_PROTOCOL'
|
44
|
+
SERVER_NAME = 'SERVER_NAME'
|
45
|
+
SERVER_PORT = 'SERVER_PORT'
|
46
|
+
REMOTE_ADDR = 'REMOTE_ADDR'
|
47
|
+
CONTENT_TYPE = 'CONTENT_TYPE'
|
48
|
+
CONTENT_LENGTH = 'CONTENT_LENGTH'
|
62
49
|
|
63
|
-
|
50
|
+
# Rack environment variables:
|
64
51
|
|
65
|
-
|
66
|
-
|
52
|
+
RACK_VERSION = 'rack.version'
|
53
|
+
RACK_ERRORS = 'rack.errors'
|
54
|
+
RACK_LOGGER = 'rack.logger'
|
55
|
+
RACK_INPUT = 'rack.input'
|
56
|
+
RACK_MULTITHREAD = 'rack.multithread'
|
57
|
+
RACK_MULTIPROCESS = 'rack.multiprocess'
|
58
|
+
RACK_RUNONCE = 'rack.run_once'
|
59
|
+
RACK_URL_SCHEME = 'rack.url_scheme'
|
60
|
+
RACK_HIJACK = 'rack.hijack'
|
61
|
+
RACK_IS_HIJACK = 'rack.hijack?'
|
62
|
+
RACK_HIJACK_IO = 'rack.hijack_io'
|
63
|
+
RACK_EARLY_HINTS = "rack.early_hints"
|
67
64
|
|
65
|
+
# Async::HTTP specific metadata:
|
66
|
+
|
67
|
+
ASYNC_HTTP_REQUEST = "async.http.request"
|
68
|
+
|
69
|
+
# Header constants:
|
70
|
+
|
71
|
+
HTTP_X_FORWARDED_PROTO = 'HTTP_X_FORWARDED_PROTO'
|
72
|
+
|
73
|
+
# Initialize the rack adaptor middleware.
|
74
|
+
# @parameter app [Object] The rack middleware.
|
75
|
+
# @parameter logger [Console::Logger] The logger to use.
|
68
76
|
def initialize(app, logger = Async.logger)
|
69
77
|
@app = app
|
70
78
|
|
@@ -73,7 +81,12 @@ module Falcon
|
|
73
81
|
@logger = logger
|
74
82
|
end
|
75
83
|
|
76
|
-
#
|
84
|
+
# Unwrap raw HTTP headers into the CGI-style expected by Rack middleware.
|
85
|
+
#
|
86
|
+
# Rack separates multiple headers with the same key, into a single field with multiple lines.
|
87
|
+
#
|
88
|
+
# @parameter headers [Protocol::HTTP::Headers] The raw HTTP request headers.
|
89
|
+
# @parameter env [Hash] The rack request `env`.
|
77
90
|
def unwrap_headers(headers, env)
|
78
91
|
headers.each do |key, value|
|
79
92
|
http_key = "HTTP_#{key.upcase.tr('-', '_')}"
|
@@ -86,7 +99,15 @@ module Falcon
|
|
86
99
|
end
|
87
100
|
end
|
88
101
|
|
89
|
-
# Process the incoming request into a valid rack env
|
102
|
+
# Process the incoming request into a valid rack `env`.
|
103
|
+
#
|
104
|
+
# - Set the `env['CONTENT_TYPE']` and `env['CONTENT_LENGTH']` based on the incoming request body.
|
105
|
+
# - Set the `env['HTTP_HOST']` header to the request authority.
|
106
|
+
# - Set the `env['HTTP_X_FORWARDED_PROTO']` header to the request scheme.
|
107
|
+
# - Set `env['REMOTE_ADDR']` to the request remote adress.
|
108
|
+
#
|
109
|
+
# @parameter request [Protocol::HTTP::Request] The incoming request.
|
110
|
+
# @parameter env [Hash] The rack `env`.
|
90
111
|
def unwrap_request(request, env)
|
91
112
|
if content_type = request.headers.delete('content-type')
|
92
113
|
env[CONTENT_TYPE] = content_type
|
@@ -113,6 +134,9 @@ module Falcon
|
|
113
134
|
end
|
114
135
|
end
|
115
136
|
|
137
|
+
# Build a rack `env` from the incoming request and apply it to the rack middleware.
|
138
|
+
#
|
139
|
+
# @parameter request [Protocol::HTTP::Request] The incoming request.
|
116
140
|
def call(request)
|
117
141
|
request_path, query_string = request.path.split('?', 2)
|
118
142
|
server_name, server_port = (request.authority || '').split(':', 2)
|
@@ -194,6 +218,9 @@ module Falcon
|
|
194
218
|
return failure_response(exception)
|
195
219
|
end
|
196
220
|
|
221
|
+
# Generate a suitable response for the given exception.
|
222
|
+
# @parameter exception [Exception]
|
223
|
+
# @returns [Protocol::HTTP::Response]
|
197
224
|
def failure_response(exception)
|
198
225
|
Protocol::HTTP::Response.for_exception(exception)
|
199
226
|
end
|
@@ -29,10 +29,22 @@ require 'time'
|
|
29
29
|
|
30
30
|
module Falcon
|
31
31
|
module Adapters
|
32
|
+
# A wrapper for a `Rack` response.
|
33
|
+
#
|
34
|
+
# A Rack response consisting of `[status, headers, body]` includes various rack-specific elements, including:
|
35
|
+
#
|
36
|
+
# - A `headers['rack.hijack']` callback which bypasses normal response handling.
|
37
|
+
# - Potentially invalid content length.
|
38
|
+
# - Potentially invalid body when processing a `HEAD` request.
|
39
|
+
# - Newline-separated header values.
|
40
|
+
# - Other `rack.` specific header key/value pairs.
|
41
|
+
#
|
42
|
+
# This wrapper takes those issues into account and adapts the rack response tuple into a {Protocol::HTTP::Response}.
|
32
43
|
class Response < ::Protocol::HTTP::Response
|
33
44
|
IGNORE_HEADERS = Middleware::Proxy::HOP_HEADERS
|
34
45
|
|
35
|
-
#
|
46
|
+
# Process the rack response headers into into a {Protocol::HTTP::Headers} instance, along with any extra `rack.` metadata.
|
47
|
+
# @returns [Tuple(Protocol::HTTP::Headers, Hash)]
|
36
48
|
def self.wrap_headers(fields)
|
37
49
|
headers = ::Protocol::HTTP::Headers.new
|
38
50
|
meta = {}
|
@@ -52,6 +64,11 @@ module Falcon
|
|
52
64
|
return headers, meta
|
53
65
|
end
|
54
66
|
|
67
|
+
# Wrap a rack response.
|
68
|
+
# @parameter status [Integer] The rack response status.
|
69
|
+
# @parameter headers [Duck(:each)] The rack response headers.
|
70
|
+
# @parameter body [Duck(:each, :close) | Nil] The rack response body.
|
71
|
+
# @parameter request [Protocol::HTTP::Request] The original request.
|
55
72
|
def self.wrap(status, headers, body, request = nil)
|
56
73
|
headers, meta = wrap_headers(headers)
|
57
74
|
|
@@ -83,6 +100,11 @@ module Falcon
|
|
83
100
|
return self.new(status, headers, body, protocol)
|
84
101
|
end
|
85
102
|
|
103
|
+
# Initialize the response wrapper.
|
104
|
+
# @parameter status [Integer] The response status.
|
105
|
+
# @parameter headers [Protocol::HTTP::Headers] The response headers.
|
106
|
+
# @parameter body [Protocol::HTTP::Body] The response body.
|
107
|
+
# @parameter protocol [String] The response protocol for upgraded requests.
|
86
108
|
def initialize(status, headers, body, protocol = nil)
|
87
109
|
super(nil, status, headers, body, protocol)
|
88
110
|
end
|
@@ -24,8 +24,9 @@ require 'protocol/http/body/rewindable'
|
|
24
24
|
|
25
25
|
module Falcon
|
26
26
|
module Adapters
|
27
|
-
# Content
|
27
|
+
# Content-type driven input buffering, specific to the needs of `rack`.
|
28
28
|
class Rewindable < ::Protocol::HTTP::Middleware
|
29
|
+
# Media types that require buffering.
|
29
30
|
BUFFERED_MEDIA_TYPES = %r{
|
30
31
|
application/x-www-form-urlencoded|
|
31
32
|
multipart/form-data|
|
@@ -35,10 +36,15 @@ module Falcon
|
|
35
36
|
|
36
37
|
POST = 'POST'.freeze
|
37
38
|
|
39
|
+
# Initialize the rewindable middleware.
|
40
|
+
# @parameter app [Protocol::HTTP::Middleware] The middleware to wrap.
|
38
41
|
def initialize(app)
|
39
42
|
super(app)
|
40
43
|
end
|
41
44
|
|
45
|
+
# Determine whether the request needs a rewindable body.
|
46
|
+
# @parameter request [Protocol::HTTP::Request]
|
47
|
+
# @returns [Boolean]
|
42
48
|
def needs_rewind?(request)
|
43
49
|
content_type = request.headers['content-type']
|
44
50
|
|
@@ -53,8 +59,9 @@ module Falcon
|
|
53
59
|
return false
|
54
60
|
end
|
55
61
|
|
56
|
-
# Wrap the request body in a rewindable buffer.
|
57
|
-
# @
|
62
|
+
# Wrap the request body in a rewindable buffer if required.
|
63
|
+
# @parameter request [Protocol::HTTP::Request]
|
64
|
+
# @returns [Protocol::HTTP::Response] the response.
|
58
65
|
def call(request)
|
59
66
|
if body = request.body and needs_rewind?(request)
|
60
67
|
request.body = Async::HTTP::Body::Rewindable.new(body)
|
data/lib/falcon/command.rb
CHANGED
data/lib/falcon/command/host.rb
CHANGED
@@ -25,20 +25,29 @@ require_relative '../configuration'
|
|
25
25
|
require_relative '../version'
|
26
26
|
|
27
27
|
require 'samovar'
|
28
|
+
require 'bundler'
|
28
29
|
|
29
30
|
module Falcon
|
30
31
|
module Command
|
32
|
+
# Implements the `falcon host` command. Designed for *deployment*.
|
33
|
+
#
|
34
|
+
# Manages a {Controller::Host} instance which is responsible for running applications in a production environment.
|
31
35
|
class Host < Samovar::Command
|
32
36
|
self.description = "Host the specified applications."
|
33
37
|
|
38
|
+
# One or more paths to the configuration files.
|
39
|
+
# @name paths
|
40
|
+
# @attribute [Array(String)]
|
34
41
|
many :paths, "Service configuration paths.", default: ["falcon.rb"]
|
35
42
|
|
43
|
+
# The container class to use.
|
36
44
|
def container_class
|
37
45
|
Async::Container.best_container_class
|
38
46
|
end
|
39
47
|
|
40
|
-
|
41
|
-
|
48
|
+
# Generate a configuration based on the specified {paths}.
|
49
|
+
def configuration
|
50
|
+
configuration = Configuration.new
|
42
51
|
|
43
52
|
@paths.each do |path|
|
44
53
|
path = File.expand_path(path)
|
@@ -48,10 +57,12 @@ module Falcon
|
|
48
57
|
return configuration
|
49
58
|
end
|
50
59
|
|
60
|
+
# Prepare a new controller for the command.
|
51
61
|
def controller
|
52
62
|
Controller::Host.new(self)
|
53
63
|
end
|
54
64
|
|
65
|
+
# Prepare the environment and run the controller.
|
55
66
|
def call
|
56
67
|
Async.logger.info(self) do |buffer|
|
57
68
|
buffer.puts "Falcon Host v#{VERSION} taking flight!"
|