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.
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)