/
rack.rb
118 lines (105 loc) · 3.83 KB
/
rack.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
require 'rack'
require 'webmachine/version'
require 'webmachine/headers'
require 'webmachine/request'
require 'webmachine/response'
require 'webmachine/dispatcher'
require 'webmachine/chunked_body'
module Webmachine
module Adapters
# A minimal "shim" adapter to allow Webmachine to interface with Rack. The
# intention here is to allow Webmachine to run under Rack-compatible
# web-servers, like unicorn and pow, and is not intended to allow Webmachine
# to be "plugged in" to an existing Rack app as middleware.
#
# To use this adapter, create a config.ru file and populate it like so:
#
# require 'webmachine/adapters/rack'
#
# # put your own Webmachine resources in another file:
# require 'my/resources'
#
# run MyApplication.adapter
#
# Servers like pow and unicorn will read config.ru by default and it should
# all "just work".
#
# And for development or testing your application can be run with Rack's
# builtin Server identically to the Mongrel and WEBrick adapters with:
#
# MyApplication.run
#
class Rack < Adapter
# Start the Rack adapter
def run
options = {
:app => self,
:Port => configuration.port,
:Host => configuration.ip
}.merge(configuration.adapter_options)
::Rack::Server.start(options)
end
# Handles a Rack-based request.
# @param [Hash] env the Rack environment
def call(env)
headers = Webmachine::Headers.from_cgi(env)
rack_req = ::Rack::Request.new env
request = Webmachine::Request.new(rack_req.request_method,
URI.parse(rack_req.url),
headers,
RequestBody.new(rack_req))
response = Webmachine::Response.new
@dispatcher.dispatch(request, response)
response.headers['Server'] = [Webmachine::SERVER_STRING, "Rack/#{::Rack.version}"].join(" ")
rack_status = response.code
rack_headers = response.headers.flattened("\n")
rack_body = case response.body
when String # Strings are enumerable in ruby 1.8
[response.body]
else
if response.body.respond_to?(:call)
Webmachine::ChunkedBody.new(Array(response.body.call))
elsif response.body.respond_to?(:each)
Webmachine::ChunkedBody.new(response.body)
else
[response.body.to_s]
end
end
[rack_status, rack_headers, rack_body]
end
# Wraps the Rack input so it can be treated like a String or
# Enumerable.
# @api private
class RequestBody
# @param [Rack::Request] request the Rack request
def initialize(request)
@request = request
end
# Converts the body to a String so you can work with the entire
# thing.
# @return [String] the request body as a string
def to_s
if @value
@value.join
else
@request.body.rewind
@request.body.read
end
end
# Iterates over the body in chunks. If the body has previously
# been read, this method can be called again and get the same
# sequence of chunks.
# @yield [chunk]
# @yieldparam [String] chunk a chunk of the request body
def each
if @value
@value.each {|chunk| yield chunk }
else
@value = []
@request.body.each {|chunk| @value << chunk; yield chunk }
end
end
end # class RequestBody
end # class Rack
end # module Adapters
end # module Webmachine