merb-core 1.1.0.rc1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/merb-core/bootloader.rb +4 -5
- data/lib/merb-core/config.rb +3 -0
- data/lib/merb-core/controller/mixins/conditional_get.rb +64 -49
- data/lib/merb-core/controller/mixins/controller.rb +9 -1
- data/lib/merb-core/controller/template.rb +4 -0
- data/lib/merb-core/dispatch/dispatcher.rb +0 -2
- data/lib/merb-core/dispatch/request_parsers.rb +6 -1
- data/lib/merb-core/dispatch/session/store_container.rb +14 -1
- data/lib/merb-core/rack/handler/mongrel.rb +6 -2
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +0 -1
- data/lib/merb-core/version.rb +1 -1
- data/spec/public/controller/conditional_get_spec.rb +76 -11
- data/spec/public/controller/controllers/conditional_get.rb +4 -0
- data/spec/public/controller/controllers/redirect.rb +13 -1
- data/spec/public/controller/redirect_spec.rb +12 -0
- data/spec/public/core/config_spec.rb +18 -0
- data/spec/public/request/multipart_spec.rb +37 -18
- data/spec/public/session/memory_session_spec.rb +31 -1
- metadata +7 -9
data/lib/merb-core/bootloader.rb
CHANGED
@@ -372,15 +372,12 @@ class Merb::BootLoader::Dependencies < Merb::BootLoader
|
|
372
372
|
# :api: plugin
|
373
373
|
def self.run
|
374
374
|
set_encoding
|
375
|
-
|
376
|
-
# then environment init file, then start enabling specific
|
377
|
-
# components, load dependencies and update logger.
|
375
|
+
load_dependencies
|
378
376
|
unless Merb::disabled?(:initfile)
|
379
377
|
load_initfile
|
380
378
|
load_env_config
|
381
379
|
end
|
382
380
|
expand_ruby_path
|
383
|
-
load_dependencies
|
384
381
|
update_logger
|
385
382
|
nil
|
386
383
|
end
|
@@ -1036,7 +1033,6 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
1036
1033
|
error_map = {}
|
1037
1034
|
|
1038
1035
|
klasses.each do |klass|
|
1039
|
-
klasses.delete(klass)
|
1040
1036
|
begin
|
1041
1037
|
load_file klass
|
1042
1038
|
rescue NameError => ne
|
@@ -1044,6 +1040,7 @@ class Merb::BootLoader::LoadClasses < Merb::BootLoader
|
|
1044
1040
|
failed_classes.push(klass)
|
1045
1041
|
end
|
1046
1042
|
end
|
1043
|
+
klasses.clear
|
1047
1044
|
|
1048
1045
|
# Keep list of classes unique
|
1049
1046
|
failed_classes.each { |k| klasses.push(k) unless klasses.include?(k) }
|
@@ -1317,6 +1314,8 @@ class Merb::BootLoader::RackUpApplication < Merb::BootLoader
|
|
1317
1314
|
Merb::Config[:app] = eval("::Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, Merb::Config[:rackup])
|
1318
1315
|
else
|
1319
1316
|
Merb::Config[:app] = ::Rack::Builder.new {
|
1317
|
+
use Rack::Head # handle head requests
|
1318
|
+
use Merb::Rack::ContentLength # report content length
|
1320
1319
|
if prefix = ::Merb::Config[:path_prefix]
|
1321
1320
|
use Merb::Rack::PathPrefix, prefix
|
1322
1321
|
end
|
data/lib/merb-core/config.rb
CHANGED
@@ -7,94 +7,109 @@
|
|
7
7
|
# +request_fresh?+ that is used after setting of
|
8
8
|
# last modification time or ETag:
|
9
9
|
#
|
10
|
-
#
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# def show
|
13
|
+
# self.etag = Digest::SHA1.hexdigest(calculate_cache_key(params))
|
11
14
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# @product = Product.get(params[:id])
|
20
|
-
# display @product
|
15
|
+
# if request_fresh?
|
16
|
+
# self.status = 304
|
17
|
+
# return ''
|
18
|
+
# else
|
19
|
+
# @product = Product.get(params[:id])
|
20
|
+
# display @product
|
21
|
+
# end
|
21
22
|
# end
|
22
|
-
# end
|
23
23
|
module Merb::ConditionalGetMixin
|
24
24
|
|
25
|
-
# Sets ETag response header by calling
|
26
|
-
#
|
25
|
+
# Sets ETag response header by calling #to_s on the argument
|
26
|
+
#
|
27
|
+
# @param tag [#to_s] value of ETag header
|
27
28
|
#
|
28
|
-
#
|
29
|
-
# tag<~to_s>::
|
30
|
-
# value of ETag header enclosed in double quotes
|
31
|
-
# as required by the RFC
|
29
|
+
# @return [String] value of ETag header enclosed in double quotes as required by the RFC
|
32
30
|
#
|
33
|
-
#
|
31
|
+
# @api public
|
34
32
|
def etag=(tag)
|
35
33
|
headers[Merb::Const::ETAG] = %("#{tag}")
|
36
34
|
end
|
37
35
|
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
36
|
+
# Value of the ETag header
|
37
|
+
#
|
38
|
+
# @return [String] Value of ETag response header if set.
|
39
|
+
# @return [nil] If ETag header not set.
|
41
40
|
#
|
42
|
-
#
|
41
|
+
# @api public
|
43
42
|
def etag
|
44
43
|
headers[Merb::Const::ETAG]
|
45
44
|
end
|
46
45
|
|
47
|
-
#
|
48
|
-
# <Boolean>::
|
49
|
-
# true if ETag response header equals If-None-Match request header,
|
50
|
-
# false otherwise
|
46
|
+
# Test to see if the request's Etag matches the one supplied locally
|
51
47
|
#
|
52
|
-
#
|
48
|
+
# @return [true] if ETag response header equals If-None-Match request header
|
49
|
+
# @return [true] if it does not.
|
50
|
+
#
|
51
|
+
# @api public
|
53
52
|
def etag_matches?(tag = self.etag)
|
54
53
|
tag == self.request.if_none_match
|
55
54
|
end
|
56
55
|
|
57
|
-
# Sets Last-Modified response header
|
56
|
+
# Sets Last-Modified response header
|
57
|
+
#
|
58
|
+
# @param time [Time,DateTime] The last modified time of the resource
|
58
59
|
#
|
59
|
-
#
|
60
|
-
# tag<Time>::
|
61
|
-
# resource modification timestamp converted into format
|
62
|
-
# required by the RFC
|
60
|
+
# @return [String] The last modified time of the resource in the format required by the RFC
|
63
61
|
#
|
64
|
-
#
|
62
|
+
# @api public
|
65
63
|
def last_modified=(time)
|
66
64
|
time = time.to_time if time.is_a?(DateTime)
|
67
65
|
# time.utc.strftime("%a, %d %b %Y %X") if we could rely on locale being American
|
68
66
|
headers[Merb::Const::LAST_MODIFIED] = time.httpdate
|
69
67
|
end
|
70
68
|
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
69
|
+
# Value of the Last-Modified header
|
70
|
+
#
|
71
|
+
# @return [Time] Value of Last-Modified response header if set.
|
72
|
+
# @return [nil] If Last-Modified not set.
|
74
73
|
#
|
75
|
-
#
|
74
|
+
# @api public
|
76
75
|
def last_modified
|
77
76
|
last_mod = headers[Merb::Const::LAST_MODIFIED]
|
78
77
|
Time.rfc2822(last_mod) if last_mod
|
79
78
|
end
|
80
79
|
|
81
|
-
#
|
82
|
-
# <Boolean>::
|
83
|
-
# true if Last-Modified response header is < than
|
84
|
-
# If-Modified-Since request header value, false otherwise.
|
80
|
+
# Test to see if the request's If-Modified-Since is satisfied
|
85
81
|
#
|
86
|
-
#
|
82
|
+
# @param time [Time] Time to test if the If-Modified-Since header against
|
83
|
+
#
|
84
|
+
# @return [true] Last-Modified response header is < than If-Modified-Since request header
|
85
|
+
# @return [false] otherwise
|
86
|
+
#
|
87
|
+
# @api public
|
87
88
|
def not_modified?(time = self.last_modified)
|
88
|
-
request.if_modified_since
|
89
|
+
if !request.if_modified_since.nil? and !time.nil?
|
90
|
+
time <= request.if_modified_since
|
91
|
+
else
|
92
|
+
false
|
93
|
+
end
|
89
94
|
end
|
90
95
|
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
# so request is fresh; false otherwise
|
96
|
+
# Tests freshness of response using all supplied validators
|
97
|
+
#
|
98
|
+
# A response with no validators is always stale.
|
95
99
|
#
|
96
|
-
#
|
100
|
+
# @return [true] ETag matches and entity is not modified
|
101
|
+
# @return [false] One or more validators failed, or none were supplied
|
102
|
+
#
|
103
|
+
# @api public
|
97
104
|
def request_fresh?
|
98
|
-
|
105
|
+
# make sure we have something to compare too.
|
106
|
+
return false unless last_modified or etag
|
107
|
+
|
108
|
+
fresh = true
|
109
|
+
|
110
|
+
# only check if we have set the right headers
|
111
|
+
fresh &&= etag_matches?(self.etag) if etag
|
112
|
+
fresh &&= not_modified?(self.last_modified) if last_modified
|
113
|
+
fresh
|
99
114
|
end
|
100
115
|
end
|
@@ -124,6 +124,10 @@ module Merb
|
|
124
124
|
# Shorthand for common usage :message => {:error => "..."}
|
125
125
|
# :success<String>::
|
126
126
|
# Shorthand for common usage :message => {:success => "..."}
|
127
|
+
# :status<String, Symbol>::
|
128
|
+
# Status code to set for the response. Can be any valid redirect
|
129
|
+
# status. Has precedence over the :permanent parameter, which is
|
130
|
+
# retained for convenience.
|
127
131
|
#
|
128
132
|
# ==== Returns
|
129
133
|
# String:: Explanation of redirect.
|
@@ -141,7 +145,11 @@ module Merb
|
|
141
145
|
opts = default_redirect_options.merge(opts)
|
142
146
|
|
143
147
|
url = handle_redirect_messages(url,opts)
|
144
|
-
|
148
|
+
|
149
|
+
_status = opts[:status] if opts[:status]
|
150
|
+
_status ||= opts[:permanent] ? 301 : 302
|
151
|
+
self.status = _status
|
152
|
+
|
145
153
|
Merb.logger.info("Redirecting to: #{url} (#{self.status})")
|
146
154
|
headers['Location'] = url
|
147
155
|
"<html><body>You are being <a href=\"#{url}\">redirected</a>.</body></html>"
|
@@ -187,6 +187,10 @@ module Merb::Template
|
|
187
187
|
require 'erubis'
|
188
188
|
|
189
189
|
class Erubis
|
190
|
+
# Fixing bug in Erubis
|
191
|
+
# http://rubyforge.org/tracker/index.php?func=detail&aid=21825&group_id=1320&atid=5201
|
192
|
+
XmlHelper = ::Erubis::XmlHelper
|
193
|
+
|
190
194
|
# ==== Parameters
|
191
195
|
# io<#path>:: An IO containing the full path of the template.
|
192
196
|
# name<String>:: The name of the method that will be created.
|
@@ -127,12 +127,17 @@ module Merb
|
|
127
127
|
else
|
128
128
|
data = body
|
129
129
|
end
|
130
|
+
|
130
131
|
unless key_memo.include?(name) && name !~ /\[\]/
|
131
132
|
paramhsh = normalize_params(paramhsh,name,data)
|
132
133
|
end
|
133
|
-
|
134
|
+
|
135
|
+
# Prevent from double processing files but process other params
|
136
|
+
key_memo << name if filename && !filename.empty?
|
137
|
+
|
134
138
|
break if buf.empty? || content_length == -1
|
135
139
|
}
|
140
|
+
|
136
141
|
paramhsh
|
137
142
|
end
|
138
143
|
|
@@ -6,6 +6,9 @@ module Merb
|
|
6
6
|
# :api: private
|
7
7
|
attr_accessor :_fingerprint
|
8
8
|
|
9
|
+
# Determines how many times to try generating a unique session key before we give up
|
10
|
+
GENERATE_MAX_TRIES = 100
|
11
|
+
|
9
12
|
# The class attribute :store holds a reference to an object that implements
|
10
13
|
# the following interface:
|
11
14
|
#
|
@@ -54,7 +57,17 @@ module Merb
|
|
54
57
|
#
|
55
58
|
# :api: private
|
56
59
|
def generate
|
57
|
-
|
60
|
+
|
61
|
+
# make sure we generate a unique session uuid
|
62
|
+
sid = nil
|
63
|
+
GENERATE_MAX_TRIES.times do |i|
|
64
|
+
sid = Merb::SessionMixin.rand_uuid
|
65
|
+
data = store.retrieve_session(sid) rescue nil
|
66
|
+
break if data.nil?
|
67
|
+
raise "Unable to Generate Unique Session key" if i == (GENERATE_MAX_TRIES-1)
|
68
|
+
end
|
69
|
+
|
70
|
+
session = new(sid)
|
58
71
|
session.needs_new_cookie = true
|
59
72
|
session
|
60
73
|
end
|
@@ -83,16 +83,20 @@ module Merb
|
|
83
83
|
|
84
84
|
begin
|
85
85
|
response.status = status.to_i
|
86
|
+
response.send_status(body.respond_to?(:length) ? body.length : nil)
|
87
|
+
|
86
88
|
headers.each { |k, vs|
|
87
89
|
Array(vs).each { |v|
|
88
90
|
response.header[k] = v
|
89
91
|
}
|
90
92
|
}
|
93
|
+
response.send_header
|
91
94
|
|
92
95
|
body.each { |part|
|
93
|
-
response.
|
96
|
+
response.write(part)
|
97
|
+
response.socket.flush
|
94
98
|
}
|
95
|
-
response.
|
99
|
+
response.done = true
|
96
100
|
ensure
|
97
101
|
body.close if body.respond_to? :close
|
98
102
|
end
|
data/lib/merb-core/version.rb
CHANGED
@@ -3,9 +3,9 @@ require File.join(File.dirname(__FILE__), "spec_helper")
|
|
3
3
|
Controllers = Merb::Test::Fixtures::Controllers
|
4
4
|
|
5
5
|
describe Merb::Controller, "#etag=" do
|
6
|
-
|
6
|
+
|
7
7
|
before do
|
8
|
-
Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
|
8
|
+
Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
|
9
9
|
Merb::Router.prepare do
|
10
10
|
default_routes
|
11
11
|
end
|
@@ -21,7 +21,7 @@ end
|
|
21
21
|
|
22
22
|
describe Merb::Controller, "#last_modified=" do
|
23
23
|
before do
|
24
|
-
Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
|
24
|
+
Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
|
25
25
|
Merb::Router.prepare do
|
26
26
|
default_routes
|
27
27
|
end
|
@@ -53,7 +53,7 @@ describe Merb::Controller, "#modified_since?" do
|
|
53
53
|
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
54
54
|
:sets_last_modified, {}, { Merb::Const::HTTP_IF_MODIFIED_SINCE => Time.at(7000).httpdate })
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
it 'return true when response Last-Modified header value <= request If-Modified-Since header' do
|
58
58
|
@controller.not_modified?(Time.at(5000)).should be(true)
|
59
59
|
@controller.not_modified?(Time.at(6999)).should be(true)
|
@@ -67,35 +67,100 @@ end
|
|
67
67
|
|
68
68
|
|
69
69
|
describe Merb::Controller, "#request_fresh?" do
|
70
|
+
it "returns false if no headers are supplied" do
|
71
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
72
|
+
:superfresh, {}, {})
|
73
|
+
@controller.request_fresh?.should be(false)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "returns false if no validation information is supplied by the action and no headers are sent" do
|
77
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
78
|
+
:sets_nothing, {}, {})
|
79
|
+
@controller.request_fresh?.should be(false)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "returns false if no validation information is supplied by the action and an ETag header is sent" do
|
83
|
+
env = { Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
84
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
85
|
+
:sets_nothing, {}, env)
|
86
|
+
@controller.request_fresh?.should be(false)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns false if no validation information is supplied by the action and an If-Modified-Since header is sent" do
|
90
|
+
env = { Merb::Const::HTTP_IF_MODIFIED_SINCE => Time.at(7000).httpdate }
|
91
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
92
|
+
:sets_nothing, {}, env)
|
93
|
+
@controller.request_fresh?.should be(false)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "returns false if no validation information is supplied by the action and both headers are sent" do
|
97
|
+
env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
98
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
99
|
+
:sets_nothing, {}, env)
|
100
|
+
|
101
|
+
@controller.request_fresh?.should be(false)
|
102
|
+
end
|
103
|
+
|
104
|
+
|
70
105
|
it 'return true when ETag matches' do
|
71
|
-
env = {
|
106
|
+
env = { Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
72
107
|
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
73
108
|
:sets_etag, {}, env)
|
74
109
|
|
75
110
|
@controller.request_fresh?.should be(true)
|
76
111
|
end
|
77
112
|
|
113
|
+
it 'return false when no If-None-Match is sent, but an ETag is set' do
|
114
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
115
|
+
:sets_etag, {}, {})
|
116
|
+
|
117
|
+
@controller.request_fresh?.should be(false)
|
118
|
+
end
|
119
|
+
|
78
120
|
it 'return true when entity is not modified since date given in request header' do
|
79
121
|
env = { Merb::Const::HTTP_IF_MODIFIED_SINCE => Time.at(7000).httpdate }
|
80
122
|
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
81
123
|
:sets_last_modified, {}, env)
|
82
|
-
|
124
|
+
|
83
125
|
@controller.request_fresh?.should be(true)
|
84
126
|
end
|
85
127
|
|
128
|
+
it 'return false when a Last-Modified is set, but no header is sent' do
|
129
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
130
|
+
:sets_last_modified, {}, {})
|
131
|
+
|
132
|
+
@controller.request_fresh?.should be(false)
|
133
|
+
end
|
134
|
+
|
86
135
|
it 'return true when both etag and last modification date satisfy request freshness' do
|
87
|
-
env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
136
|
+
env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
88
137
|
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
89
138
|
:superfresh, {}, env)
|
90
|
-
|
139
|
+
|
91
140
|
@controller.request_fresh?.should be(true)
|
92
141
|
end
|
93
142
|
|
143
|
+
it 'return false if etag satisfies but the last modification date does not satisfy request freshness' do
|
144
|
+
env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(6999).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
145
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
146
|
+
:superfresh, {}, env)
|
147
|
+
|
148
|
+
@controller.request_fresh?.should be(false)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'return false if etag does not satisfy but the last modification date does satisfy request freshness' do
|
152
|
+
env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"wrong"' }
|
153
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
154
|
+
:superfresh, {}, env)
|
155
|
+
|
156
|
+
@controller.request_fresh?.should be(false)
|
157
|
+
end
|
158
|
+
|
94
159
|
it 'return false when neither etag nor last modification date satisfy request freshness' do
|
95
|
-
env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
160
|
+
env = { 'HTTP_IF_MODIFIED_SINCE' => Time.at(7000).httpdate, Merb::Const::HTTP_IF_NONE_MATCH => '"39791e6fb09"' }
|
96
161
|
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::ConditionalGet,
|
97
162
|
:stale, {}, env)
|
98
|
-
|
163
|
+
|
99
164
|
@controller.request_fresh?.should be(false)
|
100
|
-
end
|
165
|
+
end
|
101
166
|
end
|
@@ -21,6 +21,18 @@ module Merb::Test::Fixtures::Controllers
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
class PermanentAndStatusRedirect < Testing
|
25
|
+
def index
|
26
|
+
redirect("/", :permanent => true, :status => 302)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class WithStatusRedirect < Testing
|
31
|
+
def index
|
32
|
+
redirect("/", :status => 307)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
24
36
|
class RedirectWithMessage < Testing
|
25
37
|
def index
|
26
38
|
redirect("/", :message => { :notice => "what?" })
|
@@ -57,4 +69,4 @@ module Merb::Test::Fixtures::Controllers
|
|
57
69
|
message[:notice]
|
58
70
|
end
|
59
71
|
end
|
60
|
-
end
|
72
|
+
end
|
@@ -19,6 +19,18 @@ describe Merb::Controller, " redirects" do
|
|
19
19
|
@controller.headers["Location"].should == "/"
|
20
20
|
end
|
21
21
|
|
22
|
+
it "recirect with :permanent and :stauts use :status" do
|
23
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::PermanentAndStatusRedirect, :index)
|
24
|
+
@controller.status.should == 302
|
25
|
+
@controller.headers["Location"].should == "/"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "redirect with status" do
|
29
|
+
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::WithStatusRedirect, :index)
|
30
|
+
@controller.status.should == 307
|
31
|
+
@controller.headers["Location"].should == "/"
|
32
|
+
end
|
33
|
+
|
22
34
|
it "redirects with messages" do
|
23
35
|
@controller = dispatch_to(Merb::Test::Fixtures::Controllers::RedirectWithMessage, :index)
|
24
36
|
@controller.status.should == 302
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
|
2
|
+
|
3
|
+
describe Merb::Config do
|
4
|
+
|
5
|
+
it "should set Dispatcher.use_mutex to true by default" do
|
6
|
+
lambda {
|
7
|
+
startup_merb
|
8
|
+
Merb::Dispatcher.use_mutex.should be_true
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should set Dispatcher.use_mutex to value in config" do
|
13
|
+
lambda {
|
14
|
+
startup_merb({:use_mutex => false})
|
15
|
+
Merb::Dispatcher.use_mutex.should be_false
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
@@ -1,13 +1,23 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "spec_helper"))
|
2
2
|
startup_merb
|
3
3
|
|
4
|
+
module Merb::MultipartRequestSpecHelper
|
5
|
+
def fake_file(read = nil, filename = 'sample.txt', path = 'sample.txt')
|
6
|
+
read ||= 'This is a text file with some small content in it.'
|
7
|
+
Struct.new(:read, :filename, :path).new(read, filename, path)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
describe Merb::Request do
|
12
|
+
include Merb::MultipartRequestSpecHelper
|
13
|
+
|
5
14
|
it "should handle file upload for multipart/form-data posts" do
|
6
|
-
file =
|
7
|
-
|
8
|
-
m = Merb::Test::MultipartRequestHelper::Post.new :file => file
|
15
|
+
file = fake_file
|
16
|
+
m = Merb::Test::MultipartRequestHelper::Post.new(:file => file)
|
9
17
|
body, head = m.to_multipart
|
10
|
-
request = fake_request({:request_method => "POST",
|
18
|
+
request = fake_request({:request_method => "POST",
|
19
|
+
:content_type => head,
|
20
|
+
:content_length => body.length}, :req => body)
|
11
21
|
request.params[:file].should_not be_nil
|
12
22
|
request.params[:file][:tempfile].class.should == Tempfile
|
13
23
|
request.params[:file][:content_type].should == 'text/plain'
|
@@ -15,23 +25,22 @@ describe Merb::Request do
|
|
15
25
|
end
|
16
26
|
|
17
27
|
it "should correctly format multipart posts which contain multiple parameters" do
|
18
|
-
|
19
|
-
new("This is a text file with some small content in it.", "sample.txt", "sample.txt")
|
20
|
-
params = {:model => {:description1 => 'foo', :description2 => 'bar', :file => file}}
|
21
|
-
|
28
|
+
params = {:model => {:description1 => 'foo', :description2 => 'bar', :file => fake_file}}
|
22
29
|
m = Merb::Test::MultipartRequestHelper::Post.new params
|
23
30
|
body, head = m.to_multipart
|
24
31
|
body.split('----------0xKhTmLbOuNdArY').size.should eql(5)
|
25
32
|
end
|
26
33
|
|
27
34
|
it "should correctly format multipart posts which contain an array as parameter" do
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
+
file = fake_file
|
36
|
+
file2 = fake_file("This is another text file", "sample2.txt", "sample2.txt")
|
37
|
+
params = {:model => {:description1 => 'foo',
|
38
|
+
:description2 => 'bar',
|
39
|
+
:child_attributes => [
|
40
|
+
{ :file => file },
|
41
|
+
{ :file => file2 }
|
42
|
+
]
|
43
|
+
}}
|
35
44
|
|
36
45
|
m = Merb::Test::MultipartRequestHelper::Post.new params
|
37
46
|
body, head = m.to_multipart
|
@@ -42,8 +51,7 @@ describe Merb::Request do
|
|
42
51
|
end
|
43
52
|
|
44
53
|
it "should accept env['rack.input'] as IO object (instead of StringIO)" do
|
45
|
-
file =
|
46
|
-
new("This is a text file with some small content in it.", "sample.txt", "sample.txt")
|
54
|
+
file = fake_file
|
47
55
|
m = Merb::Test::MultipartRequestHelper::Post.new :file => file
|
48
56
|
body, head = m.to_multipart
|
49
57
|
|
@@ -66,5 +74,16 @@ describe Merb::Request do
|
|
66
74
|
request = fake_request({:request_method => "GET", :content_type => 'multipart/form-data, boundary=----------0xKhTmLbOuNdArY', :content_length => 0}, :req => '')
|
67
75
|
running {request.params}.should_not raise_error
|
68
76
|
end
|
69
|
-
|
77
|
+
|
78
|
+
it "should handle multiple occurences of one parameter" do
|
79
|
+
m = Merb::Test::MultipartRequestHelper::Post.new :file => fake_file
|
80
|
+
m.push_params({:checkbox => 0})
|
81
|
+
m.push_params({:checkbox => 1})
|
82
|
+
body, head = m.to_multipart
|
83
|
+
request = fake_request({:request_method => "POST",
|
84
|
+
:content_type => head,
|
85
|
+
:content_length => body.length}, :req => body)
|
86
|
+
request.params[:file].should_not be_nil
|
87
|
+
request.params[:checkbox].should eql '1'
|
88
|
+
end
|
70
89
|
end
|
@@ -2,6 +2,36 @@ require File.join(File.dirname(__FILE__), "spec_helper")
|
|
2
2
|
startup_merb(:session_store => "memory")
|
3
3
|
require File.join(File.dirname(__FILE__), "controllers", "sessions")
|
4
4
|
|
5
|
+
describe Merb::MemorySession, "container" do
|
6
|
+
|
7
|
+
it "should always generate unique session" do
|
8
|
+
# Fix session id generation
|
9
|
+
Merb::SessionMixin.stub!(:rand_uuid).and_return(1, 1, 2)
|
10
|
+
|
11
|
+
s1 = Merb::MemorySession.generate
|
12
|
+
s1.store.store_session(s1.session_id, {:foo => 'bar'})
|
13
|
+
s1.session_id.should eql 1
|
14
|
+
|
15
|
+
s2 = Merb::MemorySession.generate
|
16
|
+
s2.session_id.should eql 2
|
17
|
+
# Cleanup
|
18
|
+
s1.store.delete_session(1)
|
19
|
+
s2.store.delete_session(2)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should raise exception if unable to generate unique ID" do
|
23
|
+
# Fix session id generation
|
24
|
+
Merb::SessionMixin.stub!(:rand_uuid).and_return(1, 1)
|
25
|
+
|
26
|
+
s1 = Merb::MemorySession.generate
|
27
|
+
s1.store.store_session(s1.session_id, {:foo => 'bar'})
|
28
|
+
|
29
|
+
lambda { s2 = Merb::MemorySession.generate }.should raise_error
|
30
|
+
|
31
|
+
s1.store.delete_session(1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
5
35
|
describe Merb::MemorySession do
|
6
36
|
|
7
37
|
before do
|
@@ -23,4 +53,4 @@ describe Merb::MemorySession, "mixed into Merb::Controller" do
|
|
23
53
|
|
24
54
|
it_should_behave_like "All session-stores mixed into Merb::Controller"
|
25
55
|
|
26
|
-
end
|
56
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: merb-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
4
|
+
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
|
10
|
-
version: 1.1.0.rc1
|
9
|
+
version: 1.1.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Ezra Zygmuntowicz
|
@@ -15,7 +14,7 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-22 00:00:00 +00:00
|
19
18
|
default_executable: merb
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
@@ -388,6 +387,7 @@ files:
|
|
388
387
|
- spec/public/controller/spec_helper.rb
|
389
388
|
- spec/public/controller/streaming_spec.rb
|
390
389
|
- spec/public/controller/url_spec.rb
|
390
|
+
- spec/public/core/config_spec.rb
|
391
391
|
- spec/public/core/merb_core_spec.rb
|
392
392
|
- spec/public/core_ext/kernel_spec.rb
|
393
393
|
- spec/public/core_ext/spec_helper.rb
|
@@ -2400,13 +2400,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
2400
2400
|
version: "0"
|
2401
2401
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
2402
2402
|
requirements:
|
2403
|
-
- - "
|
2403
|
+
- - ">="
|
2404
2404
|
- !ruby/object:Gem::Version
|
2405
2405
|
segments:
|
2406
|
-
-
|
2407
|
-
|
2408
|
-
- 1
|
2409
|
-
version: 1.3.1
|
2406
|
+
- 0
|
2407
|
+
version: "0"
|
2410
2408
|
requirements: []
|
2411
2409
|
|
2412
2410
|
rubyforge_project:
|