webmachine 1.2.2 → 1.6.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 +7 -0
- data/.gitignore +3 -0
- data/CHANGELOG.md +57 -0
- data/Gemfile +20 -15
- data/README.md +89 -91
- data/RELEASING.md +21 -0
- data/Rakefile +5 -21
- data/documentation/adapters.md +41 -0
- data/documentation/authentication-and-authorization.md +37 -0
- data/documentation/configurator.md +19 -0
- data/documentation/error-handling.md +86 -0
- data/documentation/examples.md +224 -0
- data/documentation/how-it-works.md +76 -0
- data/documentation/routes.md +112 -0
- data/documentation/validation.md +159 -0
- data/documentation/versioning-apis.md +74 -0
- data/documentation/visual-debugger.md +38 -0
- data/examples/application.rb +2 -2
- data/examples/debugger.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/lib/webmachine/adapter.rb +7 -13
- data/lib/webmachine/adapters.rb +1 -2
- data/lib/webmachine/adapters/httpkit.rb +74 -0
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -2
- data/lib/webmachine/adapters/rack.rb +70 -25
- data/lib/webmachine/adapters/rack_mapped.rb +42 -0
- data/lib/webmachine/adapters/reel.rb +22 -23
- data/lib/webmachine/adapters/webrick.rb +16 -16
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +3 -4
- data/lib/webmachine/configuration.rb +1 -1
- data/lib/webmachine/constants.rb +75 -0
- data/lib/webmachine/decision/conneg.rb +12 -10
- data/lib/webmachine/decision/flow.rb +42 -32
- data/lib/webmachine/decision/fsm.rb +14 -21
- data/lib/webmachine/decision/helpers.rb +10 -38
- data/lib/webmachine/dispatcher.rb +13 -10
- data/lib/webmachine/dispatcher/route.rb +45 -9
- data/lib/webmachine/errors.rb +9 -3
- data/lib/webmachine/events.rb +2 -2
- data/lib/webmachine/header_negotiation.rb +25 -0
- data/lib/webmachine/headers.rb +8 -3
- data/lib/webmachine/locale/en.yml +7 -5
- data/lib/webmachine/media_type.rb +10 -8
- data/lib/webmachine/request.rb +67 -26
- data/lib/webmachine/rescueable_exception.rb +62 -0
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/resource/callbacks.rb +11 -9
- data/lib/webmachine/response.rb +3 -5
- data/lib/webmachine/spec/IO_response.body +1 -0
- data/lib/webmachine/spec/adapter_lint.rb +83 -37
- data/lib/webmachine/spec/test_resource.rb +15 -4
- data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
- data/lib/webmachine/streaming/io_encoder.rb +7 -1
- data/lib/webmachine/trace.rb +1 -0
- data/lib/webmachine/trace/fsm.rb +20 -10
- data/lib/webmachine/trace/resource_proxy.rb +2 -0
- data/lib/webmachine/translation.rb +2 -1
- data/lib/webmachine/version.rb +3 -3
- data/memory_test.rb +37 -0
- data/spec/spec_helper.rb +17 -9
- data/spec/webmachine/adapter_spec.rb +14 -15
- data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
- data/spec/webmachine/adapters/rack_mapped_spec.rb +71 -0
- data/spec/webmachine/adapters/rack_spec.rb +32 -6
- data/spec/webmachine/adapters/reel_spec.rb +16 -12
- data/spec/webmachine/adapters/webrick_spec.rb +2 -2
- data/spec/webmachine/application_spec.rb +18 -17
- data/spec/webmachine/chunked_body_spec.rb +3 -3
- data/spec/webmachine/configuration_spec.rb +5 -5
- data/spec/webmachine/cookie_spec.rb +13 -13
- data/spec/webmachine/decision/conneg_spec.rb +49 -43
- data/spec/webmachine/decision/falsey_spec.rb +4 -4
- data/spec/webmachine/decision/flow_spec.rb +195 -145
- data/spec/webmachine/decision/fsm_spec.rb +81 -19
- data/spec/webmachine/decision/helpers_spec.rb +20 -20
- data/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb +22 -0
- data/spec/webmachine/dispatcher/route_spec.rb +114 -32
- data/spec/webmachine/dispatcher_spec.rb +49 -24
- data/spec/webmachine/errors_spec.rb +1 -1
- data/spec/webmachine/etags_spec.rb +19 -19
- data/spec/webmachine/events_spec.rb +6 -6
- data/spec/webmachine/headers_spec.rb +14 -14
- data/spec/webmachine/media_type_spec.rb +36 -36
- data/spec/webmachine/request_spec.rb +70 -39
- data/spec/webmachine/rescueable_exception_spec.rb +15 -0
- data/spec/webmachine/resource/authentication_spec.rb +6 -6
- data/spec/webmachine/response_spec.rb +18 -12
- data/spec/webmachine/trace/fsm_spec.rb +8 -8
- data/spec/webmachine/trace/resource_proxy_spec.rb +9 -9
- data/spec/webmachine/trace/trace_store_spec.rb +5 -5
- data/spec/webmachine/trace_spec.rb +3 -3
- data/webmachine.gemspec +2 -6
- metadata +78 -228
- data/lib/webmachine/adapters/hatetepe.rb +0 -108
- data/lib/webmachine/adapters/mongrel.rb +0 -127
- data/lib/webmachine/dispatcher/not_found_resource.rb +0 -5
- data/lib/webmachine/fiber18.rb +0 -88
- data/spec/webmachine/adapters/hatetepe_spec.rb +0 -60
- data/spec/webmachine/adapters/mongrel_spec.rb +0 -16
data/lib/webmachine/adapters.rb
CHANGED
|
@@ -5,8 +5,7 @@ module Webmachine
|
|
|
5
5
|
# Contains classes and modules that connect Webmachine to Ruby
|
|
6
6
|
# application servers.
|
|
7
7
|
module Adapters
|
|
8
|
-
autoload :Mongrel, 'webmachine/adapters/mongrel'
|
|
9
8
|
autoload :Reel, 'webmachine/adapters/reel'
|
|
10
|
-
autoload :
|
|
9
|
+
autoload :HTTPkit, 'webmachine/adapters/httpkit'
|
|
11
10
|
end
|
|
12
11
|
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'webmachine/adapter'
|
|
2
|
+
require 'webmachine/constants'
|
|
3
|
+
require 'webmachine/version'
|
|
4
|
+
require 'httpkit'
|
|
5
|
+
require 'webmachine/version'
|
|
6
|
+
require 'webmachine/response'
|
|
7
|
+
require 'webmachine/request'
|
|
8
|
+
require 'webmachine/headers'
|
|
9
|
+
|
|
10
|
+
module Webmachine
|
|
11
|
+
module Adapters
|
|
12
|
+
class HTTPkit < Adapter
|
|
13
|
+
VERSION_STRING = "#{Webmachine::SERVER_STRING} HTTPkit/#{::HTTPkit::VERSION}".freeze
|
|
14
|
+
|
|
15
|
+
def options
|
|
16
|
+
@options ||= {
|
|
17
|
+
:address => application.configuration.ip,
|
|
18
|
+
:port => application.configuration.port,
|
|
19
|
+
:handlers => [
|
|
20
|
+
::HTTPkit::Server::TimeoutsHandler.new,
|
|
21
|
+
::HTTPkit::Server::KeepAliveHandler.new,
|
|
22
|
+
self
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def run
|
|
28
|
+
::HTTPkit.start do
|
|
29
|
+
::HTTPkit::Server.start(options)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Called by HTTPkit::Server for every request
|
|
34
|
+
def serve(request, served)
|
|
35
|
+
response = Webmachine::Response.new
|
|
36
|
+
application.dispatcher.dispatch(convert_request(request), response)
|
|
37
|
+
|
|
38
|
+
served.fulfill(convert_response(response))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# Converts HTTPkit::Request to Webmachine::Request
|
|
44
|
+
def convert_request(request)
|
|
45
|
+
Webmachine::Request.new(
|
|
46
|
+
request.http_method.to_s.upcase,
|
|
47
|
+
request.uri,
|
|
48
|
+
Webmachine::Headers[request.headers.dup],
|
|
49
|
+
request.body)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Converts Webmachine::Response to HTTPkit::Response
|
|
53
|
+
def convert_response(response)
|
|
54
|
+
response.headers[SERVER] = VERSION_STRING
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
::HTTPkit::Response.new(
|
|
58
|
+
response.code.to_i,
|
|
59
|
+
response.headers,
|
|
60
|
+
convert_body(response.body))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# HTTPkit::Body accepts strings and enumerables, i.e. Webmachine's
|
|
64
|
+
# Callable, Enumerable, IO, and Fiber encoders are supported.
|
|
65
|
+
def convert_body(body)
|
|
66
|
+
if body.respond_to?(:call)
|
|
67
|
+
[body.call]
|
|
68
|
+
else
|
|
69
|
+
body || ''
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
+
require 'webmachine/adapter'
|
|
1
2
|
require 'rack'
|
|
2
|
-
require 'webmachine/
|
|
3
|
+
require 'webmachine/constants'
|
|
3
4
|
require 'webmachine/headers'
|
|
4
5
|
require 'webmachine/request'
|
|
5
6
|
require 'webmachine/response'
|
|
6
|
-
require 'webmachine/
|
|
7
|
+
require 'webmachine/version'
|
|
7
8
|
require 'webmachine/chunked_body'
|
|
8
9
|
|
|
9
10
|
module Webmachine
|
|
10
11
|
module Adapters
|
|
11
12
|
# A minimal "shim" adapter to allow Webmachine to interface with Rack. The
|
|
12
13
|
# intention here is to allow Webmachine to run under Rack-compatible
|
|
13
|
-
# web-servers, like unicorn and pow
|
|
14
|
-
#
|
|
14
|
+
# web-servers, like unicorn and pow.
|
|
15
|
+
#
|
|
16
|
+
# The adapter expects your Webmachine application to be mounted at the root path -
|
|
17
|
+
# it will NOT allow you to nest your Webmachine application at an arbitrary path
|
|
18
|
+
# eg. map "/api" { run MyWebmachineAPI }
|
|
19
|
+
# To use map your Webmachine application at an arbitrary path, use the
|
|
20
|
+
# `Webmachine::Adapters::RackMapped` subclass instead.
|
|
15
21
|
#
|
|
16
22
|
# To use this adapter, create a config.ru file and populate it like so:
|
|
17
23
|
#
|
|
@@ -26,7 +32,7 @@ module Webmachine
|
|
|
26
32
|
# all "just work".
|
|
27
33
|
#
|
|
28
34
|
# And for development or testing your application can be run with Rack's
|
|
29
|
-
# builtin Server identically to the
|
|
35
|
+
# builtin Server identically to the WEBrick adapter with:
|
|
30
36
|
#
|
|
31
37
|
# MyApplication.run
|
|
32
38
|
#
|
|
@@ -34,49 +40,48 @@ module Webmachine
|
|
|
34
40
|
# Used to override default Rack server options (useful in testing)
|
|
35
41
|
DEFAULT_OPTIONS = {}
|
|
36
42
|
|
|
43
|
+
REQUEST_URI = 'REQUEST_URI'.freeze
|
|
44
|
+
VERSION_STRING = "#{Webmachine::SERVER_STRING} Rack/#{::Rack.version}".freeze
|
|
45
|
+
NEWLINE = "\n".freeze
|
|
46
|
+
|
|
37
47
|
# Start the Rack adapter
|
|
38
48
|
def run
|
|
39
49
|
options = DEFAULT_OPTIONS.merge({
|
|
40
50
|
:app => self,
|
|
41
|
-
:Port => configuration.port,
|
|
42
|
-
:Host => configuration.ip
|
|
43
|
-
}).merge(configuration.adapter_options)
|
|
51
|
+
:Port => application.configuration.port,
|
|
52
|
+
:Host => application.configuration.ip
|
|
53
|
+
}).merge(application.configuration.adapter_options)
|
|
44
54
|
|
|
45
55
|
@server = ::Rack::Server.new(options)
|
|
46
56
|
@server.start
|
|
47
57
|
end
|
|
48
58
|
|
|
49
|
-
def shutdown
|
|
50
|
-
@server.server.shutdown if @server
|
|
51
|
-
end
|
|
52
|
-
|
|
53
59
|
# Handles a Rack-based request.
|
|
54
60
|
# @param [Hash] env the Rack environment
|
|
55
61
|
def call(env)
|
|
56
62
|
headers = Webmachine::Headers.from_cgi(env)
|
|
57
63
|
|
|
58
64
|
rack_req = ::Rack::Request.new env
|
|
59
|
-
request =
|
|
60
|
-
URI.parse(rack_req.url),
|
|
61
|
-
headers,
|
|
62
|
-
RequestBody.new(rack_req))
|
|
65
|
+
request = build_webmachine_request(rack_req, headers)
|
|
63
66
|
|
|
64
67
|
response = Webmachine::Response.new
|
|
65
|
-
|
|
68
|
+
application.dispatcher.dispatch(request, response)
|
|
66
69
|
|
|
67
|
-
response.headers[
|
|
70
|
+
response.headers[SERVER] = VERSION_STRING
|
|
68
71
|
|
|
69
72
|
rack_status = response.code
|
|
70
|
-
rack_headers = response.headers.flattened(
|
|
73
|
+
rack_headers = response.headers.flattened(NEWLINE)
|
|
71
74
|
rack_body = case response.body
|
|
72
75
|
when String # Strings are enumerable in ruby 1.8
|
|
73
76
|
[response.body]
|
|
74
77
|
else
|
|
75
|
-
if response.body
|
|
78
|
+
if (io_body = IO.try_convert(response.body))
|
|
79
|
+
io_body
|
|
80
|
+
elsif response.body.respond_to?(:call)
|
|
76
81
|
Webmachine::ChunkedBody.new(Array(response.body.call))
|
|
77
82
|
elsif response.body.respond_to?(:each)
|
|
78
83
|
# This might be an IOEncoder with a Content-Length, which shouldn't be chunked.
|
|
79
|
-
if response.headers[
|
|
84
|
+
if response.headers[TRANSFER_ENCODING] == "chunked"
|
|
80
85
|
Webmachine::ChunkedBody.new(response.body)
|
|
81
86
|
else
|
|
82
87
|
response.body
|
|
@@ -90,7 +95,39 @@ module Webmachine
|
|
|
90
95
|
rack_res.finish
|
|
91
96
|
end
|
|
92
97
|
|
|
98
|
+
protected
|
|
99
|
+
def routing_tokens(rack_req)
|
|
100
|
+
nil # no-op for default, un-mapped rack adapter
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def base_uri(rack_req)
|
|
104
|
+
nil # no-op for default, un-mapped rack adapter
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
def build_webmachine_request(rack_req, headers)
|
|
109
|
+
RackRequest.new(rack_req.request_method,
|
|
110
|
+
rack_req.url,
|
|
111
|
+
headers,
|
|
112
|
+
RequestBody.new(rack_req),
|
|
113
|
+
routing_tokens(rack_req),
|
|
114
|
+
base_uri(rack_req),
|
|
115
|
+
rack_req.env
|
|
116
|
+
)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
class RackRequest < Webmachine::Request
|
|
120
|
+
attr_reader :env
|
|
121
|
+
|
|
122
|
+
def initialize(method, uri, headers, body, routing_tokens, base_uri, env)
|
|
123
|
+
super(method, uri, headers, body, routing_tokens, base_uri)
|
|
124
|
+
@env = env
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
93
128
|
class RackResponse
|
|
129
|
+
ONE_FIVE = '1.5'.freeze
|
|
130
|
+
|
|
94
131
|
def initialize(body, status, headers)
|
|
95
132
|
@body = body
|
|
96
133
|
@status = status
|
|
@@ -98,8 +135,8 @@ module Webmachine
|
|
|
98
135
|
end
|
|
99
136
|
|
|
100
137
|
def finish
|
|
101
|
-
@headers[
|
|
102
|
-
@headers.delete(
|
|
138
|
+
@headers[CONTENT_TYPE] ||= TEXT_HTML if rack_release_enforcing_content_type
|
|
139
|
+
@headers.delete(CONTENT_TYPE) if response_without_body
|
|
103
140
|
[@status, @headers, @body]
|
|
104
141
|
end
|
|
105
142
|
|
|
@@ -110,7 +147,7 @@ module Webmachine
|
|
|
110
147
|
end
|
|
111
148
|
|
|
112
149
|
def rack_release_enforcing_content_type
|
|
113
|
-
::Rack.release <
|
|
150
|
+
::Rack.release < ONE_FIVE
|
|
114
151
|
end
|
|
115
152
|
end
|
|
116
153
|
|
|
@@ -123,6 +160,15 @@ module Webmachine
|
|
|
123
160
|
@request = request
|
|
124
161
|
end
|
|
125
162
|
|
|
163
|
+
# Rack Servers differ in the way you can access their request bodys.
|
|
164
|
+
# While some allow you to directly get a Ruby IO object others don't.
|
|
165
|
+
# You have to check the methods they expose, like #gets, #read, #each, #rewind and maybe others.
|
|
166
|
+
# See: https://github.com/rack/rack/blob/rack-1.5/lib/rack/lint.rb#L296
|
|
167
|
+
# @return [IO] the request body
|
|
168
|
+
def to_io
|
|
169
|
+
@request.body
|
|
170
|
+
end
|
|
171
|
+
|
|
126
172
|
# Converts the body to a String so you can work with the entire
|
|
127
173
|
# thing.
|
|
128
174
|
# @return [String] the request body as a string
|
|
@@ -150,6 +196,5 @@ module Webmachine
|
|
|
150
196
|
end
|
|
151
197
|
end # class RequestBody
|
|
152
198
|
end # class Rack
|
|
153
|
-
|
|
154
199
|
end # module Adapters
|
|
155
200
|
end # module Webmachine
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'webmachine/adapters/rack'
|
|
2
|
+
|
|
3
|
+
module Webmachine
|
|
4
|
+
module Adapters
|
|
5
|
+
# Provides the same functionality as the parent Webmachine::Adapters::Rack
|
|
6
|
+
# adapter, but allows the Webmachine application to be hosted at an
|
|
7
|
+
# arbitrary path in a parent Rack application (as in Rack `map` or Rails
|
|
8
|
+
# routing `mount`)
|
|
9
|
+
#
|
|
10
|
+
# This functionality is separated out from the parent class to preserve
|
|
11
|
+
# backward compatibility in the behaviour of the parent Rack adpater.
|
|
12
|
+
#
|
|
13
|
+
# To use the adapter in a parent Rack application, map the Webmachine
|
|
14
|
+
# application as follows in a rackup file or Rack::Builder:
|
|
15
|
+
#
|
|
16
|
+
# map '/foo' do
|
|
17
|
+
# run SomeotherRackApp
|
|
18
|
+
#
|
|
19
|
+
# map '/bar' do
|
|
20
|
+
# run MyWebmachineApp.adapter
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
class RackMapped < Rack
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
|
|
27
|
+
def routing_tokens(rack_req)
|
|
28
|
+
routing_match = rack_req.path_info.match(Webmachine::Request::ROUTING_PATH_MATCH)
|
|
29
|
+
routing_path = routing_match ? routing_match[1] : ""
|
|
30
|
+
routing_path.split(SLASH)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def base_uri(rack_req)
|
|
34
|
+
# rack SCRIPT_NAME env var doesn't end with "/". This causes weird
|
|
35
|
+
# behavour when URI.join concatenates URI components in
|
|
36
|
+
# Webmachine::Decision::Flow#n11
|
|
37
|
+
script_name = rack_req.script_name + SLASH
|
|
38
|
+
URI.join(rack_req.base_url, script_name)
|
|
39
|
+
end
|
|
40
|
+
end # class RackMapped
|
|
41
|
+
end # module Adapters
|
|
42
|
+
end # module Webmachine
|
|
@@ -1,40 +1,42 @@
|
|
|
1
|
+
require 'webmachine/adapter'
|
|
2
|
+
require 'webmachine/constants'
|
|
3
|
+
require 'set'
|
|
4
|
+
require 'celluloid/current'
|
|
1
5
|
require 'reel'
|
|
2
|
-
require 'webmachine/version'
|
|
3
6
|
require 'webmachine/headers'
|
|
4
7
|
require 'webmachine/request'
|
|
5
8
|
require 'webmachine/response'
|
|
6
|
-
require 'webmachine/dispatcher'
|
|
7
|
-
require 'set'
|
|
8
9
|
|
|
9
10
|
module Webmachine
|
|
10
11
|
module Adapters
|
|
11
12
|
class Reel < Adapter
|
|
12
13
|
# Used to override default Reel server options (useful in testing)
|
|
13
14
|
DEFAULT_OPTIONS = {}
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
def run
|
|
16
17
|
@options = DEFAULT_OPTIONS.merge({
|
|
17
|
-
:port => configuration.port,
|
|
18
|
-
:host => configuration.ip
|
|
19
|
-
}).merge(configuration.adapter_options)
|
|
18
|
+
:port => application.configuration.port,
|
|
19
|
+
:host => application.configuration.ip
|
|
20
|
+
}).merge(application.configuration.adapter_options)
|
|
20
21
|
|
|
21
|
-
if extra_verbs = configuration.adapter_options[:extra_verbs]
|
|
22
|
+
if extra_verbs = application.configuration.adapter_options[:extra_verbs]
|
|
22
23
|
@extra_verbs = Set.new(extra_verbs.map(&:to_s).map(&:upcase))
|
|
23
24
|
else
|
|
24
25
|
@extra_verbs = Set.new
|
|
25
26
|
end
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
if @options[:ssl]
|
|
29
|
+
unless @options[:ssl][:cert] && @options[:ssl][:key]
|
|
30
|
+
raise ArgumentError, 'Certificate or Private key missing for HTTPS Server'
|
|
31
|
+
end
|
|
32
|
+
@server = ::Reel::Server::HTTPS.supervise(@options[:host], @options[:port], @options[:ssl], &method(:process))
|
|
33
|
+
else
|
|
34
|
+
@server = ::Reel::Server::HTTP.supervise(@options[:host], @options[:port], &method(:process))
|
|
35
|
+
end
|
|
28
36
|
|
|
29
|
-
# FIXME: this will no longer work on Ruby 2.0. We need Celluloid.trap
|
|
30
|
-
trap("INT") { @server.terminate; exit 0 }
|
|
31
37
|
Celluloid::Actor.join(@server)
|
|
32
38
|
end
|
|
33
39
|
|
|
34
|
-
def shutdown
|
|
35
|
-
@server.terminate! if @server
|
|
36
|
-
end
|
|
37
|
-
|
|
38
40
|
def process(connection)
|
|
39
41
|
connection.each_request do |request|
|
|
40
42
|
# Users of the adapter can configure a custom WebSocket handler
|
|
@@ -54,7 +56,7 @@ module Webmachine
|
|
|
54
56
|
# state machine. Do the "Railsy" thing and handle them like POSTs
|
|
55
57
|
# with a magical parameter
|
|
56
58
|
if @extra_verbs.include?(request.method)
|
|
57
|
-
method =
|
|
59
|
+
method = POST_METHOD
|
|
58
60
|
param = "_method=#{request.method}"
|
|
59
61
|
uri = request_uri(request.url, request.headers, param)
|
|
60
62
|
else
|
|
@@ -64,8 +66,9 @@ module Webmachine
|
|
|
64
66
|
|
|
65
67
|
wm_headers = Webmachine::Headers[request.headers.dup]
|
|
66
68
|
wm_request = Webmachine::Request.new(method, uri, wm_headers, request.body)
|
|
69
|
+
|
|
67
70
|
wm_response = Webmachine::Response.new
|
|
68
|
-
|
|
71
|
+
application.dispatcher.dispatch(wm_request, wm_response)
|
|
69
72
|
|
|
70
73
|
fixup_headers(wm_response)
|
|
71
74
|
fixup_callable_encoder(wm_response)
|
|
@@ -77,13 +80,9 @@ module Webmachine
|
|
|
77
80
|
end
|
|
78
81
|
|
|
79
82
|
def request_uri(path, headers, extra_query_params = nil)
|
|
80
|
-
host_parts = headers.fetch('Host').split(':')
|
|
81
83
|
path_parts = path.split('?')
|
|
82
|
-
|
|
83
|
-
uri_hash =
|
|
84
|
-
|
|
85
|
-
uri_hash[:port] = host_parts.last.to_i if host_parts.length == 2
|
|
86
|
-
uri_hash[:query] = path_parts.last if path_parts.length == 2
|
|
84
|
+
uri_hash = {path: path_parts.first}
|
|
85
|
+
uri_hash[:query] = path_parts.last if path_parts.length == 2
|
|
87
86
|
|
|
88
87
|
if extra_query_params
|
|
89
88
|
if uri_hash[:query]
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
require 'webmachine/adapter'
|
|
1
2
|
require 'webrick'
|
|
2
|
-
require 'webmachine/
|
|
3
|
+
require 'webmachine/constants'
|
|
3
4
|
require 'webmachine/headers'
|
|
5
|
+
require 'webmachine/adapters/lazy_request_body'
|
|
4
6
|
require 'webmachine/request'
|
|
5
7
|
require 'webmachine/response'
|
|
6
|
-
require 'webmachine/
|
|
8
|
+
require 'webmachine/version'
|
|
7
9
|
|
|
8
10
|
module Webmachine
|
|
9
11
|
module Adapters
|
|
@@ -15,22 +17,19 @@ module Webmachine
|
|
|
15
17
|
# Starts the WEBrick adapter
|
|
16
18
|
def run
|
|
17
19
|
options = DEFAULT_OPTIONS.merge({
|
|
18
|
-
:Port => configuration.port,
|
|
19
|
-
:BindAddress => configuration.ip
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
:Port => application.configuration.port,
|
|
21
|
+
:BindAddress => application.configuration.ip,
|
|
22
|
+
:application => application
|
|
23
|
+
}).merge(application.configuration.adapter_options)
|
|
24
|
+
@server = Server.new(options)
|
|
23
25
|
@server.start
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
def shutdown
|
|
27
|
-
@server.shutdown if @server
|
|
28
|
-
end
|
|
29
|
-
|
|
30
28
|
# WEBRick::HTTPServer that is run by the WEBrick adapter.
|
|
31
29
|
class Server < ::WEBrick::HTTPServer
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
|
|
31
|
+
def initialize(options)
|
|
32
|
+
@application = options[:application]
|
|
34
33
|
super(options)
|
|
35
34
|
end
|
|
36
35
|
|
|
@@ -42,8 +41,9 @@ module Webmachine
|
|
|
42
41
|
wreq.request_uri,
|
|
43
42
|
header,
|
|
44
43
|
LazyRequestBody.new(wreq))
|
|
44
|
+
|
|
45
45
|
response = Webmachine::Response.new
|
|
46
|
-
@dispatcher.dispatch(request, response)
|
|
46
|
+
@application.dispatcher.dispatch(request, response)
|
|
47
47
|
wres.status = response.code.to_i
|
|
48
48
|
|
|
49
49
|
headers = response.headers.flattened.reject { |k,v| k == 'Set-Cookie' }
|
|
@@ -52,12 +52,12 @@ module Webmachine
|
|
|
52
52
|
cookies = [response.headers['Set-Cookie'] || []].flatten
|
|
53
53
|
cookies.each { |c| wres.cookies << c }
|
|
54
54
|
|
|
55
|
-
wres[
|
|
55
|
+
wres[SERVER] = [Webmachine::SERVER_STRING, wres.config[:ServerSoftware]].join(" ")
|
|
56
56
|
case response.body
|
|
57
57
|
when String
|
|
58
58
|
wres.body << response.body
|
|
59
59
|
when Enumerable
|
|
60
|
-
wres.chunked = response.headers[
|
|
60
|
+
wres.chunked = response.headers[TRANSFER_ENCODING] == 'chunked'
|
|
61
61
|
response.body.each {|part| wres.body << part }
|
|
62
62
|
else
|
|
63
63
|
if response.body.respond_to?(:call)
|