webmachine 1.2.2 → 1.3.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 +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -11
- data/README.md +85 -89
- data/Rakefile +0 -1
- data/documentation/adapters.md +39 -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 +215 -0
- data/documentation/how-it-works.md +76 -0
- data/documentation/routes.md +97 -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 +37 -21
- data/lib/webmachine/adapters/reel.rb +21 -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/constants.rb +75 -0
- data/lib/webmachine/decision/conneg.rb +12 -10
- data/lib/webmachine/decision/flow.rb +31 -21
- data/lib/webmachine/decision/fsm.rb +10 -18
- data/lib/webmachine/decision/helpers.rb +9 -37
- data/lib/webmachine/dispatcher.rb +13 -10
- data/lib/webmachine/dispatcher/route.rb +18 -8
- data/lib/webmachine/errors.rb +7 -1
- data/lib/webmachine/header_negotiation.rb +25 -0
- data/lib/webmachine/headers.rb +7 -2
- data/lib/webmachine/locale/en.yml +7 -5
- data/lib/webmachine/media_type.rb +10 -8
- data/lib/webmachine/request.rb +44 -15
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/resource/callbacks.rb +6 -4
- data/lib/webmachine/spec/IO_response.body +1 -0
- data/lib/webmachine/spec/adapter_lint.rb +70 -36
- data/lib/webmachine/spec/test_resource.rb +10 -4
- data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
- data/lib/webmachine/streaming/io_encoder.rb +6 -0
- 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 +9 -9
- data/spec/webmachine/adapter_spec.rb +14 -15
- data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
- data/spec/webmachine/adapters/rack_spec.rb +6 -6
- data/spec/webmachine/adapters/reel_spec.rb +15 -11
- 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 +48 -42
- data/spec/webmachine/decision/falsey_spec.rb +4 -4
- data/spec/webmachine/decision/flow_spec.rb +194 -144
- data/spec/webmachine/decision/fsm_spec.rb +17 -17
- data/spec/webmachine/decision/helpers_spec.rb +20 -20
- data/spec/webmachine/dispatcher/route_spec.rb +73 -27
- data/spec/webmachine/dispatcher_spec.rb +34 -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 +33 -33
- data/spec/webmachine/resource/authentication_spec.rb +6 -6
- data/spec/webmachine/response_spec.rb +12 -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 +48 -206
- 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
@@ -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)
|
@@ -8,7 +8,7 @@ module Webmachine
|
|
8
8
|
#
|
9
9
|
# MyApp = Webmachine::Application.new do |app|
|
10
10
|
# app.routes do
|
11
|
-
# add [
|
11
|
+
# add [:*], AssetResource
|
12
12
|
# end
|
13
13
|
#
|
14
14
|
# app.configure do |config|
|
@@ -56,7 +56,7 @@ module Webmachine
|
|
56
56
|
# @return an instance of the configured web-server adapter
|
57
57
|
# @see Adapters
|
58
58
|
def adapter
|
59
|
-
@adapter ||= adapter_class.new(
|
59
|
+
@adapter ||= adapter_class.new(self)
|
60
60
|
end
|
61
61
|
|
62
62
|
# @return an instance of the configured web-server adapter
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'webmachine/constants'
|
2
|
+
|
1
3
|
module Webmachine
|
2
4
|
# {ChunkedBody} is used to wrap an {Enumerable} object (like an enumerable
|
3
5
|
# {Response#body}) so it yields proper chunks for chunked transfer encoding.
|
@@ -13,11 +15,8 @@ module Webmachine
|
|
13
15
|
#
|
14
16
|
# This is needed for Ruby webservers which don't do the chunking themselves.
|
15
17
|
class ChunkedBody
|
16
|
-
# Delimiter for chunked encoding
|
17
|
-
CRLF = "\r\n"
|
18
|
-
|
19
18
|
# Final chunk in any chunked-encoding response
|
20
|
-
FINAL_CHUNK = "0#{CRLF}#{CRLF}"
|
19
|
+
FINAL_CHUNK = "0#{CRLF}#{CRLF}".freeze
|
21
20
|
|
22
21
|
# Creates a new {ChunkedBody} from the given {Enumerable}.
|
23
22
|
# @param [Enumerable] body the enumerable response body
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Webmachine
|
2
|
+
# Universal HTTP delimiter
|
3
|
+
CRLF = "\r\n".freeze
|
4
|
+
|
5
|
+
# HTTP Content-Type
|
6
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
7
|
+
|
8
|
+
# Default Content-Type
|
9
|
+
TEXT_HTML = 'text/html'.freeze
|
10
|
+
|
11
|
+
# HTTP Date
|
12
|
+
DATE = 'Date'.freeze
|
13
|
+
|
14
|
+
# HTTP Transfer-Encoding
|
15
|
+
TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
|
16
|
+
|
17
|
+
# HTTP Content-Length
|
18
|
+
CONTENT_LENGTH = 'Content-Length'.freeze
|
19
|
+
|
20
|
+
# A underscore
|
21
|
+
UNDERSCORE = '_'.freeze
|
22
|
+
|
23
|
+
# A dash
|
24
|
+
DASH = '-'.freeze
|
25
|
+
|
26
|
+
# A Slash
|
27
|
+
SLASH = '/'.freeze
|
28
|
+
|
29
|
+
MATCHES_ALL = '*/*'.freeze
|
30
|
+
|
31
|
+
GET_METHOD = "GET"
|
32
|
+
HEAD_METHOD = "HEAD"
|
33
|
+
POST_METHOD = "POST"
|
34
|
+
PUT_METHOD = "PUT"
|
35
|
+
DELETE_METHOD = "DELETE"
|
36
|
+
OPTIONS_METHOD = "OPTIONS"
|
37
|
+
TRACE_METHOD = "TRACE"
|
38
|
+
CONNECT_METHOD = "CONNECT"
|
39
|
+
|
40
|
+
STANDARD_HTTP_METHODS = [
|
41
|
+
GET_METHOD, HEAD_METHOD, POST_METHOD,
|
42
|
+
PUT_METHOD, DELETE_METHOD, TRACE_METHOD,
|
43
|
+
CONNECT_METHOD, OPTIONS_METHOD
|
44
|
+
].map!(&:freeze)
|
45
|
+
STANDARD_HTTP_METHODS.freeze
|
46
|
+
|
47
|
+
# A colon
|
48
|
+
COLON = ':'.freeze
|
49
|
+
|
50
|
+
# http string
|
51
|
+
HTTP = 'http'.freeze
|
52
|
+
|
53
|
+
# Host string
|
54
|
+
HOST = 'Host'.freeze
|
55
|
+
|
56
|
+
# HTTP Content-Encoding
|
57
|
+
CONTENT_ENCODING = 'Content-Encoding'.freeze
|
58
|
+
|
59
|
+
# Charset string
|
60
|
+
CHARSET = 'Charset'.freeze
|
61
|
+
|
62
|
+
# Semicolon split match
|
63
|
+
SPLIT_SEMI = /\s*,\s*/.freeze
|
64
|
+
|
65
|
+
# Star Character
|
66
|
+
STAR = '*'.freeze
|
67
|
+
|
68
|
+
# HTTP Location
|
69
|
+
LOCATION = 'Location'.freeze
|
70
|
+
|
71
|
+
# identity Encoding
|
72
|
+
IDENTITY = 'identity'.freeze
|
73
|
+
|
74
|
+
SERVER = 'Server'.freeze
|
75
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'webmachine/constants'
|
1
2
|
require 'webmachine/translation'
|
2
3
|
require 'webmachine/media_type'
|
3
4
|
|
@@ -13,7 +14,8 @@ module Webmachine
|
|
13
14
|
# appropriate media type.
|
14
15
|
# @api private
|
15
16
|
def choose_media_type(provided, header)
|
16
|
-
|
17
|
+
types = Array(header).map{|h| h.split(SPLIT_SEMI) }.flatten
|
18
|
+
requested = MediaTypeList.build(types)
|
17
19
|
provided = provided.map do |p| # normalize_provided
|
18
20
|
MediaType.parse(p)
|
19
21
|
end
|
@@ -30,9 +32,9 @@ module Webmachine
|
|
30
32
|
# @api private
|
31
33
|
def choose_encoding(provided, header)
|
32
34
|
encodings = provided.keys
|
33
|
-
if encoding = do_choose(encodings, header,
|
34
|
-
response.headers[
|
35
|
-
metadata[
|
35
|
+
if encoding = do_choose(encodings, header, IDENTITY)
|
36
|
+
response.headers[CONTENT_ENCODING] = encoding unless encoding == IDENTITY
|
37
|
+
metadata[CONTENT_ENCODING] = encoding
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -43,7 +45,7 @@ module Webmachine
|
|
43
45
|
if provided && !provided.empty?
|
44
46
|
charsets = provided.map {|c| c.first }
|
45
47
|
if charset = do_choose(charsets, header, HAS_ENCODING ? Encoding.default_external.name : kcode_charset)
|
46
|
-
metadata[
|
48
|
+
metadata[CHARSET] = charset
|
47
49
|
end
|
48
50
|
else
|
49
51
|
true
|
@@ -55,8 +57,8 @@ module Webmachine
|
|
55
57
|
# @api private
|
56
58
|
def choose_language(provided, header)
|
57
59
|
if provided && !provided.empty?
|
58
|
-
requested = PriorityList.build(header.split(
|
59
|
-
star_priority = requested.priority_of(
|
60
|
+
requested = PriorityList.build(header.split(SPLIT_SEMI))
|
61
|
+
star_priority = requested.priority_of(STAR)
|
60
62
|
any_ok = star_priority && star_priority > 0.0
|
61
63
|
accepted = requested.find do |priority, range|
|
62
64
|
if priority == 0.0
|
@@ -97,9 +99,9 @@ module Webmachine
|
|
97
99
|
# @api private
|
98
100
|
def do_choose(choices, header, default)
|
99
101
|
choices = choices.dup.map {|s| s.downcase }
|
100
|
-
accepted = PriorityList.build(header.split(
|
102
|
+
accepted = PriorityList.build(header.split(SPLIT_SEMI))
|
101
103
|
default_priority = accepted.priority_of(default)
|
102
|
-
star_priority = accepted.priority_of(
|
104
|
+
star_priority = accepted.priority_of(STAR)
|
103
105
|
default_ok = (default_priority.nil? && star_priority != 0.0) || default_priority
|
104
106
|
any_ok = star_priority && star_priority > 0.0
|
105
107
|
chosen = accepted.find do |priority, acceptable|
|
@@ -117,7 +119,7 @@ module Webmachine
|
|
117
119
|
|
118
120
|
private
|
119
121
|
# Matches acceptable items that include 'q' values
|
120
|
-
CONNEG_REGEX = /^\s*(\S+);\s*q=(\S*)\s
|
122
|
+
CONNEG_REGEX = /^\s*(\S+);\s*q=(\S*)\s*$/.freeze
|
121
123
|
|
122
124
|
# Matches the requested media type (with potential modifiers)
|
123
125
|
# against the provided types (with potential modifiers).
|
@@ -1,5 +1,7 @@
|
|
1
|
-
require 'time'
|
1
|
+
require 'time'
|
2
2
|
require 'digest/md5'
|
3
|
+
require 'base64'
|
4
|
+
require 'webmachine/constants'
|
3
5
|
require 'webmachine/decision/conneg'
|
4
6
|
require 'webmachine/decision/falsey'
|
5
7
|
require 'webmachine/translation'
|
@@ -16,6 +18,8 @@ module Webmachine
|
|
16
18
|
# of the chart.
|
17
19
|
# @see https://raw.github.com/wiki/basho/webmachine/images/http-headers-status-v3.png
|
18
20
|
module Flow
|
21
|
+
include Base64
|
22
|
+
|
19
23
|
# Version of the flow diagram
|
20
24
|
VERSION = 3
|
21
25
|
|
@@ -81,7 +85,7 @@ module Webmachine
|
|
81
85
|
response.body = "Content-MD5 header does not match request body."
|
82
86
|
400
|
83
87
|
else # not_validated
|
84
|
-
if request.content_md5 == Digest::MD5.hexdigest(request.body)
|
88
|
+
if decode64(request.content_md5) == Digest::MD5.hexdigest(request.body)
|
85
89
|
:b9b
|
86
90
|
else
|
87
91
|
response.body = "Content-MD5 header does not match request body."
|
@@ -116,9 +120,10 @@ module Webmachine
|
|
116
120
|
decision_test(resource.forbidden?, 403, :b6)
|
117
121
|
end
|
118
122
|
|
123
|
+
CONTENT = /content-/.freeze
|
119
124
|
# Okay Content-* Headers?
|
120
125
|
def b6
|
121
|
-
decision_test(resource.valid_content_headers?(request.headers.grep(
|
126
|
+
decision_test(resource.valid_content_headers?(request.headers.grep(CONTENT)), :b5, 501)
|
122
127
|
end
|
123
128
|
|
124
129
|
# Known Content-Type?
|
@@ -144,7 +149,7 @@ module Webmachine
|
|
144
149
|
# Accept exists?
|
145
150
|
def c3
|
146
151
|
if !request.accept
|
147
|
-
metadata[
|
152
|
+
metadata[CONTENT_TYPE] = MediaType.parse(resource.content_types_provided.first.first)
|
148
153
|
:d4
|
149
154
|
else
|
150
155
|
:c4
|
@@ -158,7 +163,7 @@ module Webmachine
|
|
158
163
|
if !chosen_type
|
159
164
|
406
|
160
165
|
else
|
161
|
-
metadata[
|
166
|
+
metadata[CONTENT_TYPE] = chosen_type
|
162
167
|
:d4
|
163
168
|
end
|
164
169
|
end
|
@@ -166,7 +171,7 @@ module Webmachine
|
|
166
171
|
# Accept-Language exists?
|
167
172
|
def d4
|
168
173
|
if !request.accept_language
|
169
|
-
if language = choose_language(resource.languages_provided,
|
174
|
+
if language = choose_language(resource.languages_provided, STAR)
|
170
175
|
resource.language_chosen(language)
|
171
176
|
:e5
|
172
177
|
else
|
@@ -190,7 +195,7 @@ module Webmachine
|
|
190
195
|
# Accept-Charset exists?
|
191
196
|
def e5
|
192
197
|
if !request.accept_charset
|
193
|
-
choose_charset(resource.charsets_provided,
|
198
|
+
choose_charset(resource.charsets_provided, STAR) ? :f6 : 406
|
194
199
|
else
|
195
200
|
:e6
|
196
201
|
end
|
@@ -204,11 +209,11 @@ module Webmachine
|
|
204
209
|
# Accept-Encoding exists?
|
205
210
|
# (also, set content-type header here, now that charset is chosen)
|
206
211
|
def f6
|
207
|
-
chosen_type = metadata[
|
208
|
-
if chosen_charset = metadata[
|
212
|
+
chosen_type = metadata[CONTENT_TYPE]
|
213
|
+
if chosen_charset = metadata[CHARSET]
|
209
214
|
chosen_type.params['charset'] = chosen_charset
|
210
215
|
end
|
211
|
-
response.headers[
|
216
|
+
response.headers[CONTENT_TYPE] = chosen_type.to_s
|
212
217
|
if !request.accept_encoding
|
213
218
|
choose_encoding(resource.encodings_provided, "identity;q=1.0,*;q=0.5") ? :g7 : 406
|
214
219
|
else
|
@@ -240,13 +245,13 @@ module Webmachine
|
|
240
245
|
|
241
246
|
# ETag in If-Match
|
242
247
|
def g11
|
243
|
-
request_etags = request.if_match.split(
|
248
|
+
request_etags = request.if_match.split(SPLIT_SEMI).map {|etag| ETag.new(etag) }
|
244
249
|
request_etags.include?(ETag.new(resource.generate_etag)) ? :h10 : 412
|
245
250
|
end
|
246
251
|
|
247
252
|
# If-Match exists?
|
248
253
|
def h7
|
249
|
-
(request.if_match && unquote(request.if_match) ==
|
254
|
+
(request.if_match && unquote(request.if_match) == STAR) ? 412 : :i7
|
250
255
|
end
|
251
256
|
|
252
257
|
# If-Unmodified-Since exists?
|
@@ -273,7 +278,7 @@ module Webmachine
|
|
273
278
|
def i4
|
274
279
|
case uri = resource.moved_permanently?
|
275
280
|
when String, URI
|
276
|
-
response.headers[
|
281
|
+
response.headers[LOCATION] = uri.to_s
|
277
282
|
301
|
278
283
|
when Fixnum
|
279
284
|
uri
|
@@ -306,7 +311,7 @@ module Webmachine
|
|
306
311
|
def k5
|
307
312
|
case uri = resource.moved_permanently?
|
308
313
|
when String, URI
|
309
|
-
response.headers[
|
314
|
+
response.headers[LOCATION] = uri.to_s
|
310
315
|
301
|
311
316
|
when Fixnum
|
312
317
|
uri
|
@@ -322,15 +327,20 @@ module Webmachine
|
|
322
327
|
|
323
328
|
# Etag in if-none-match?
|
324
329
|
def k13
|
325
|
-
request_etags = request.if_none_match.split(
|
326
|
-
|
330
|
+
request_etags = request.if_none_match.split(SPLIT_SEMI).map {|etag| ETag.new(etag) }
|
331
|
+
resource_etag = resource.generate_etag
|
332
|
+
if resource_etag && request_etags.include?(ETag.new(resource_etag))
|
333
|
+
:j18
|
334
|
+
else
|
335
|
+
:l13
|
336
|
+
end
|
327
337
|
end
|
328
338
|
|
329
339
|
# Moved temporarily?
|
330
340
|
def l5
|
331
341
|
case uri = resource.moved_temporarily?
|
332
342
|
when String, URI
|
333
|
-
response.headers[
|
343
|
+
response.headers[LOCATION] = uri.to_s
|
334
344
|
307
|
335
345
|
when Fixnum
|
336
346
|
uri
|
@@ -410,7 +420,7 @@ module Webmachine
|
|
410
420
|
base_uri = resource.base_uri || request.base_uri
|
411
421
|
new_uri = URI.join(base_uri.to_s, uri)
|
412
422
|
request.disp_path = new_uri.path
|
413
|
-
response.headers[
|
423
|
+
response.headers[LOCATION] = new_uri.to_s
|
414
424
|
result = accept_helper
|
415
425
|
return result if Fixnum === result
|
416
426
|
end
|
@@ -425,7 +435,7 @@ module Webmachine
|
|
425
435
|
end
|
426
436
|
end
|
427
437
|
if response.is_redirect?
|
428
|
-
if response.headers[
|
438
|
+
if response.headers[LOCATION]
|
429
439
|
303
|
430
440
|
else
|
431
441
|
raise InvalidResource, t('do_redirect')
|
@@ -460,7 +470,7 @@ module Webmachine
|
|
460
470
|
def o18
|
461
471
|
if request.get? || request.head?
|
462
472
|
add_caching_headers
|
463
|
-
content_type = metadata[
|
473
|
+
content_type = metadata[CONTENT_TYPE]
|
464
474
|
handler = resource.content_types_provided.find {|ct, _| content_type.type_matches?(MediaType.parse(ct)) }.last
|
465
475
|
result = resource.send(handler)
|
466
476
|
if Fixnum === result
|
@@ -497,7 +507,7 @@ module Webmachine
|
|
497
507
|
|
498
508
|
# New resource?
|
499
509
|
def p11
|
500
|
-
!response.headers[
|
510
|
+
!response.headers[LOCATION] ? :o20 : 201
|
501
511
|
end
|
502
512
|
|
503
513
|
end # module Flow
|
@@ -1,5 +1,7 @@
|
|
1
|
-
require 'webmachine/decision/helpers'
|
1
|
+
require 'webmachine/decision/helpers'
|
2
|
+
require 'webmachine/trace'
|
2
3
|
require 'webmachine/translation'
|
4
|
+
require 'webmachine/constants'
|
3
5
|
|
4
6
|
module Webmachine
|
5
7
|
module Decision
|
@@ -8,6 +10,7 @@ module Webmachine
|
|
8
10
|
class FSM
|
9
11
|
include Flow
|
10
12
|
include Helpers
|
13
|
+
include Trace::FSM
|
11
14
|
include Translation
|
12
15
|
|
13
16
|
attr_reader :resource, :request, :response, :metadata
|
@@ -15,7 +18,7 @@ module Webmachine
|
|
15
18
|
def initialize(resource, request, response)
|
16
19
|
@resource, @request, @response = resource, request, response
|
17
20
|
@metadata = {}
|
18
|
-
|
21
|
+
super
|
19
22
|
end
|
20
23
|
|
21
24
|
# Processes the request, iteratively invoking the decision methods in {Flow}.
|
@@ -35,7 +38,7 @@ module Webmachine
|
|
35
38
|
raise InvalidResource, t('fsm_broke', :state => state, :result => result.inspect)
|
36
39
|
end
|
37
40
|
end
|
38
|
-
rescue
|
41
|
+
rescue => e
|
39
42
|
Webmachine.render_error(500, request, response, :message => e.message)
|
40
43
|
ensure
|
41
44
|
trace_response(response)
|
@@ -48,7 +51,7 @@ module Webmachine
|
|
48
51
|
rescue MalformedRequest => e
|
49
52
|
Webmachine.render_error(400, request, response, :message => e.message)
|
50
53
|
400
|
51
|
-
rescue
|
54
|
+
rescue => e
|
52
55
|
resource.handle_exception(e)
|
53
56
|
500
|
54
57
|
end
|
@@ -60,7 +63,7 @@ module Webmachine
|
|
60
63
|
when 404
|
61
64
|
Webmachine.render_error(code, request, response)
|
62
65
|
when 304
|
63
|
-
response.headers.delete(
|
66
|
+
response.headers.delete(CONTENT_TYPE)
|
64
67
|
add_caching_headers
|
65
68
|
end
|
66
69
|
|
@@ -69,19 +72,8 @@ module Webmachine
|
|
69
72
|
response.code
|
70
73
|
end
|
71
74
|
|
72
|
-
ensure_content_length
|
73
|
-
ensure_date_header
|
74
|
-
end
|
75
|
-
|
76
|
-
# When tracing is disabled, this does nothing.
|
77
|
-
def trace_decision(state); end
|
78
|
-
# When tracing is disabled, this does nothing.
|
79
|
-
def trace_request(request); end
|
80
|
-
# When tracing is disabled, this does nothing.
|
81
|
-
def trace_response(response); end
|
82
|
-
|
83
|
-
def initialize_tracing
|
84
|
-
extend Trace::FSM if Trace.trace?(resource)
|
75
|
+
ensure_content_length(response)
|
76
|
+
ensure_date_header(response)
|
85
77
|
end
|
86
78
|
end # class FSM
|
87
79
|
end # module Decision
|