webmachine 1.2.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +57 -0
  4. data/Gemfile +20 -15
  5. data/README.md +89 -91
  6. data/RELEASING.md +21 -0
  7. data/Rakefile +5 -21
  8. data/documentation/adapters.md +41 -0
  9. data/documentation/authentication-and-authorization.md +37 -0
  10. data/documentation/configurator.md +19 -0
  11. data/documentation/error-handling.md +86 -0
  12. data/documentation/examples.md +224 -0
  13. data/documentation/how-it-works.md +76 -0
  14. data/documentation/routes.md +112 -0
  15. data/documentation/validation.md +159 -0
  16. data/documentation/versioning-apis.md +74 -0
  17. data/documentation/visual-debugger.md +38 -0
  18. data/examples/application.rb +2 -2
  19. data/examples/debugger.rb +1 -1
  20. data/lib/webmachine.rb +3 -1
  21. data/lib/webmachine/adapter.rb +7 -13
  22. data/lib/webmachine/adapters.rb +1 -2
  23. data/lib/webmachine/adapters/httpkit.rb +74 -0
  24. data/lib/webmachine/adapters/lazy_request_body.rb +1 -2
  25. data/lib/webmachine/adapters/rack.rb +70 -25
  26. data/lib/webmachine/adapters/rack_mapped.rb +42 -0
  27. data/lib/webmachine/adapters/reel.rb +22 -23
  28. data/lib/webmachine/adapters/webrick.rb +16 -16
  29. data/lib/webmachine/application.rb +2 -2
  30. data/lib/webmachine/chunked_body.rb +3 -4
  31. data/lib/webmachine/configuration.rb +1 -1
  32. data/lib/webmachine/constants.rb +75 -0
  33. data/lib/webmachine/decision/conneg.rb +12 -10
  34. data/lib/webmachine/decision/flow.rb +42 -32
  35. data/lib/webmachine/decision/fsm.rb +14 -21
  36. data/lib/webmachine/decision/helpers.rb +10 -38
  37. data/lib/webmachine/dispatcher.rb +13 -10
  38. data/lib/webmachine/dispatcher/route.rb +45 -9
  39. data/lib/webmachine/errors.rb +9 -3
  40. data/lib/webmachine/events.rb +2 -2
  41. data/lib/webmachine/header_negotiation.rb +25 -0
  42. data/lib/webmachine/headers.rb +8 -3
  43. data/lib/webmachine/locale/en.yml +7 -5
  44. data/lib/webmachine/media_type.rb +10 -8
  45. data/lib/webmachine/request.rb +67 -26
  46. data/lib/webmachine/rescueable_exception.rb +62 -0
  47. data/lib/webmachine/resource.rb +1 -1
  48. data/lib/webmachine/resource/callbacks.rb +11 -9
  49. data/lib/webmachine/response.rb +3 -5
  50. data/lib/webmachine/spec/IO_response.body +1 -0
  51. data/lib/webmachine/spec/adapter_lint.rb +83 -37
  52. data/lib/webmachine/spec/test_resource.rb +15 -4
  53. data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
  54. data/lib/webmachine/streaming/io_encoder.rb +7 -1
  55. data/lib/webmachine/trace.rb +1 -0
  56. data/lib/webmachine/trace/fsm.rb +20 -10
  57. data/lib/webmachine/trace/resource_proxy.rb +2 -0
  58. data/lib/webmachine/translation.rb +2 -1
  59. data/lib/webmachine/version.rb +3 -3
  60. data/memory_test.rb +37 -0
  61. data/spec/spec_helper.rb +17 -9
  62. data/spec/webmachine/adapter_spec.rb +14 -15
  63. data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
  64. data/spec/webmachine/adapters/rack_mapped_spec.rb +71 -0
  65. data/spec/webmachine/adapters/rack_spec.rb +32 -6
  66. data/spec/webmachine/adapters/reel_spec.rb +16 -12
  67. data/spec/webmachine/adapters/webrick_spec.rb +2 -2
  68. data/spec/webmachine/application_spec.rb +18 -17
  69. data/spec/webmachine/chunked_body_spec.rb +3 -3
  70. data/spec/webmachine/configuration_spec.rb +5 -5
  71. data/spec/webmachine/cookie_spec.rb +13 -13
  72. data/spec/webmachine/decision/conneg_spec.rb +49 -43
  73. data/spec/webmachine/decision/falsey_spec.rb +4 -4
  74. data/spec/webmachine/decision/flow_spec.rb +195 -145
  75. data/spec/webmachine/decision/fsm_spec.rb +81 -19
  76. data/spec/webmachine/decision/helpers_spec.rb +20 -20
  77. data/spec/webmachine/dispatcher/rfc3986_percent_decode_spec.rb +22 -0
  78. data/spec/webmachine/dispatcher/route_spec.rb +114 -32
  79. data/spec/webmachine/dispatcher_spec.rb +49 -24
  80. data/spec/webmachine/errors_spec.rb +1 -1
  81. data/spec/webmachine/etags_spec.rb +19 -19
  82. data/spec/webmachine/events_spec.rb +6 -6
  83. data/spec/webmachine/headers_spec.rb +14 -14
  84. data/spec/webmachine/media_type_spec.rb +36 -36
  85. data/spec/webmachine/request_spec.rb +70 -39
  86. data/spec/webmachine/rescueable_exception_spec.rb +15 -0
  87. data/spec/webmachine/resource/authentication_spec.rb +6 -6
  88. data/spec/webmachine/response_spec.rb +18 -12
  89. data/spec/webmachine/trace/fsm_spec.rb +8 -8
  90. data/spec/webmachine/trace/resource_proxy_spec.rb +9 -9
  91. data/spec/webmachine/trace/trace_store_spec.rb +5 -5
  92. data/spec/webmachine/trace_spec.rb +3 -3
  93. data/webmachine.gemspec +2 -6
  94. metadata +78 -228
  95. data/lib/webmachine/adapters/hatetepe.rb +0 -108
  96. data/lib/webmachine/adapters/mongrel.rb +0 -127
  97. data/lib/webmachine/dispatcher/not_found_resource.rb +0 -5
  98. data/lib/webmachine/fiber18.rb +0 -88
  99. data/spec/webmachine/adapters/hatetepe_spec.rb +0 -60
  100. data/spec/webmachine/adapters/mongrel_spec.rb +0 -16
@@ -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 :Hatetepe, 'webmachine/adapters/hatetepe'
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,5 +1,4 @@
1
-
2
- module Webmachine
1
+ module Webmachine
3
2
  module Adapters
4
3
  # Wraps a request body so that it can be passed to
5
4
  # {Request} while still lazily evaluating the body.
@@ -1,17 +1,23 @@
1
+ require 'webmachine/adapter'
1
2
  require 'rack'
2
- require 'webmachine/version'
3
+ require 'webmachine/constants'
3
4
  require 'webmachine/headers'
4
5
  require 'webmachine/request'
5
6
  require 'webmachine/response'
6
- require 'webmachine/dispatcher'
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, and is not intended to allow Webmachine
14
- # to be "plugged in" to an existing Rack app as middleware.
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 Mongrel and WEBrick adapters with:
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 = Webmachine::Request.new(rack_req.request_method,
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
- @dispatcher.dispatch(request, response)
68
+ application.dispatcher.dispatch(request, response)
66
69
 
67
- response.headers['Server'] = [Webmachine::SERVER_STRING, "Rack/#{::Rack.version}"].join(" ")
70
+ response.headers[SERVER] = VERSION_STRING
68
71
 
69
72
  rack_status = response.code
70
- rack_headers = response.headers.flattened("\n")
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.respond_to?(:call)
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["Transfer-Encoding"] == "chunked"
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['Content-Type'] ||= 'text/html' if rack_release_enforcing_content_type
102
- @headers.delete('Content-Type') if response_without_body
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 < '1.5'
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
- @server = ::Reel::Server.supervise(@options[:host], @options[:port], &method(:process))
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 = "POST"
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
- @dispatcher.dispatch(wm_request, wm_response)
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 = {host: host_parts.first, path: path_parts.first}
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/version'
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/dispatcher'
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
- }).merge(configuration.adapter_options)
21
- @server = Server.new(dispatcher, options)
22
- trap("INT") { shutdown }
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
- def initialize(dispatcher, options)
33
- @dispatcher = dispatcher
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['Server'] = [Webmachine::SERVER_STRING, wres.config[:ServerSoftware]].join(" ")
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['Transfer-Encoding'] == 'chunked'
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)