merb-core 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +38 -8
- data/Rakefile +1 -59
- data/lib/merb-core.rb +3 -2
- data/lib/merb-core/bootloader.rb +17 -1
- data/lib/merb-core/config.rb +1 -1
- data/lib/merb-core/dispatch/dispatcher.rb +53 -64
- data/lib/merb-core/dispatch/request.rb +1 -1
- data/lib/merb-core/dispatch/session.rb +20 -10
- data/lib/merb-core/gem_ext/erubis.rb +1 -0
- data/lib/merb-core/rack.rb +1 -0
- data/lib/merb-core/rack/adapter/abstract.rb +12 -5
- data/lib/merb-core/rack/handler/mongrel.rb +2 -2
- data/lib/merb-core/rack/middleware.rb +43 -11
- data/lib/merb-core/rack/middleware/content_length.rb +8 -14
- data/lib/merb-core/rack/middleware/head.rb +14 -0
- data/lib/merb-core/test/helpers.rb +1 -0
- data/lib/merb-core/test/helpers/webrat_helper.rb +18 -0
- data/lib/merb-core/version.rb +1 -1
- data/spec/private/dispatch/bootloader_spec.rb +1 -0
- data/spec/public/controller/controllers/redirect.rb +1 -1
- data/spec/public/controller/redirect_spec.rb +6 -3
- data/spec/public/rack/rack_middleware_spec.rb +15 -0
- data/spec/public/rack/shared_example_groups.rb +3 -3
- data/spec/public/request/request_spec.rb +0 -2
- data/spec/public/webrat/test_app/config/init.rb +2 -1
- data/spec/public/webrat/test_app/config/rack.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- metadata +249 -239
data/CHANGELOG
CHANGED
@@ -1,4 +1,18 @@
|
|
1
|
-
== 1.1.0 ""
|
1
|
+
== 1.1.0 "Black Hole" 2010-03-22
|
2
|
+
|
3
|
+
* Ruby 1.9 support. The big one. Merb now runs on ruby 1.9.1. This mandated some
|
4
|
+
small changes to the internals as well as some changes to the specs. However,
|
5
|
+
it shouldn't require any changes in your app level code, or at least the merb
|
6
|
+
specific parts of your app level code.
|
7
|
+
|
8
|
+
* Unicorns! Merb is now better behaved as a rack app and works with a config.ru
|
9
|
+
file[2]. This change should make working with whatever is the latest and
|
10
|
+
greatest ruby webserver a lot easier.
|
11
|
+
|
12
|
+
* Bugfixes. So many bug fixes. As part of the release process we've done our
|
13
|
+
best to clear out many of the bugs which have been gathering dust over the
|
14
|
+
past year. Some do still remain, but those generally require a more complex
|
15
|
+
solution which needs some thought.
|
2
16
|
|
3
17
|
* !!!BC!!! Dependency handling using Bundler
|
4
18
|
In this version we dropped old way of loading dependencies using the Kernel
|
@@ -6,36 +20,52 @@
|
|
6
20
|
us to move the whole dependency handling and gem management outside the
|
7
21
|
Merb. Therefore we can simplify some internals and remove some of the Kernel
|
8
22
|
monkeypatching:
|
9
|
-
|
23
|
+
|
10
24
|
The old Kernel.dependency and Kernel.dependencies will only 'require
|
11
25
|
gem_name' or 'require require_as' when you call this methods. These methods
|
12
26
|
will also emit the DEPRECATED warnings when you will use them. If you see
|
13
27
|
the warning you should move your dependency to the Gemfile or Rakefile.
|
14
|
-
|
28
|
+
|
15
29
|
If you used dependencies to load exact version of the Gem and you have
|
16
30
|
installed multiple versions of the same gem you now get one more DEPRECATED
|
17
31
|
warning. This is because we don't use 'gem' command from RubyGems which was
|
18
32
|
used deep inside to load exact gem version. ALSO THE LATEST VERSION OF THE
|
19
33
|
GEM WILL BE LOADED BECAUSE WE DO SIMPLE 'require'.
|
20
|
-
|
34
|
+
|
21
35
|
Also methods: use_orm, use_test, use_testing_framework and use_template_engine
|
22
36
|
DON'T require any gems now, you must require it in Gemfile.
|
23
|
-
|
37
|
+
|
24
38
|
Merb generators was changed to generate you Gemfile for your application and
|
25
39
|
settings instead of the dependencies.rb.
|
26
|
-
|
40
|
+
|
27
41
|
So what still works? Almost everything except it doesn't defer to the Merb
|
28
42
|
start and doesn't load exact version of gem if more versions are installed:
|
29
|
-
|
43
|
+
|
30
44
|
dependency "json" => works
|
31
45
|
dependency "rspec", :require_as => 'spec' => works try to require 'spec'
|
32
46
|
dependency "json", '1.1.6' => works unless you have
|
33
47
|
>= 1.1.6 installed
|
34
48
|
dependency "json" { } => works but doesn't yield
|
35
|
-
|
49
|
+
|
36
50
|
For more information how to migrate to Bundler see:
|
37
51
|
http://wiki.github.com/merb/merb/howto-using-the-bundler
|
38
52
|
|
53
|
+
=== Bugs fixed
|
54
|
+
|
55
|
+
* [merb-core] #1040 Allow using <%== %> escaped version of <%= %>
|
56
|
+
* [merb-core] #1068 Correctly handle HEAD requests (This requires manual
|
57
|
+
alteration of rack.rb)
|
58
|
+
* [merb-core] #1174 Merb::Config[:use_mutex] issue
|
59
|
+
'sel' to string before comparing to string
|
60
|
+
* [merb-core] #1258 Sessions could be overwritten under certain (rare)
|
61
|
+
situations.
|
62
|
+
* [merb-core] #1288 Fix for run_later in clusters
|
63
|
+
* [merb-core] #1298 Fix potential timing attack on cookie sessions.
|
64
|
+
* [merb-core] #1304 Multipart input parsing produces wrong checkbox input
|
65
|
+
* [merb-core] #1310 Prevent mongrel bloat when streaming files
|
66
|
+
* [merb-core] #1317 Merb now returns correct cookie headers
|
67
|
+
* [merb-core] Improvements to handling of conditional validators
|
68
|
+
|
39
69
|
== 0.9.8 "Time Machine" 2008-06-10
|
40
70
|
|
41
71
|
* Pre-release contributors file update.
|
data/Rakefile
CHANGED
@@ -8,65 +8,8 @@ require "fileutils"
|
|
8
8
|
# Load code annotation support library
|
9
9
|
require File.expand_path("../tools/annotation_extract", __FILE__)
|
10
10
|
|
11
|
-
# Load this library's version information
|
12
|
-
require File.expand_path('../lib/merb-core/version', __FILE__)
|
13
|
-
|
14
11
|
include FileUtils
|
15
12
|
|
16
|
-
begin
|
17
|
-
|
18
|
-
gem 'jeweler', '~> 1.4'
|
19
|
-
require 'jeweler'
|
20
|
-
|
21
|
-
Jeweler::Tasks.new do |gemspec|
|
22
|
-
|
23
|
-
gemspec.version = Merb::VERSION.dup
|
24
|
-
|
25
|
-
gemspec.name = "merb-core"
|
26
|
-
gemspec.description = "Merb. Pocket rocket web framework."
|
27
|
-
gemspec.summary = "Merb plugin that provides caching (page, action, fragment, object)"
|
28
|
-
|
29
|
-
gemspec.authors = [ "Ezra Zygmuntowicz" ]
|
30
|
-
gemspec.email = "ez@engineyard.com"
|
31
|
-
gemspec.homepage = "http://merbivore.com/"
|
32
|
-
|
33
|
-
gemspec.extra_rdoc_files.include [ 'CHANGELOG' ]
|
34
|
-
|
35
|
-
gemspec.files = Dir["{bin,lib,spec,spec10}/**/*"] + [
|
36
|
-
'LICENSE',
|
37
|
-
'README',
|
38
|
-
'Rakefile',
|
39
|
-
'TODO',
|
40
|
-
'CHANGELOG',
|
41
|
-
'PUBLIC_CHANGELOG',
|
42
|
-
'CONTRIBUTORS'
|
43
|
-
]
|
44
|
-
|
45
|
-
# Runtime dependencies
|
46
|
-
gemspec.add_dependency 'bundler', '>= 0.9.3'
|
47
|
-
gemspec.add_dependency 'extlib', '>= 0.9.13'
|
48
|
-
gemspec.add_dependency 'erubis', '>= 2.6.2'
|
49
|
-
gemspec.add_dependency 'rake'
|
50
|
-
gemspec.add_dependency 'rspec'
|
51
|
-
gemspec.add_dependency 'rack'
|
52
|
-
gemspec.add_dependency 'mime-types', '>= 1.16' # supports ruby-1.9
|
53
|
-
|
54
|
-
# Development dependencies
|
55
|
-
gemspec.add_development_dependency 'rspec', '>= 1.2.9'
|
56
|
-
gemspec.add_development_dependency 'webrat', '>= 0.3.1'
|
57
|
-
|
58
|
-
# Executable files
|
59
|
-
gemspec.executables = 'merb'
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
Jeweler::GemcutterTasks.new
|
64
|
-
|
65
|
-
rescue LoadError
|
66
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
13
|
desc "Run the specs."
|
71
14
|
task :default => :specs
|
72
15
|
|
@@ -84,9 +27,8 @@ namespace :doc do
|
|
84
27
|
rdoc.rdoc_files.add(files)
|
85
28
|
rdoc.main = "README"
|
86
29
|
rdoc.title = "Merb Docs"
|
87
|
-
rdoc.template = File.expand_path("../tools/allison-2.0.2/lib/allison.rb", __FILE__)
|
88
30
|
rdoc.rdoc_dir = "doc/rdoc"
|
89
|
-
rdoc.options << "--line-numbers"
|
31
|
+
rdoc.options << "--line-numbers"
|
90
32
|
end
|
91
33
|
|
92
34
|
desc "run webgen"
|
data/lib/merb-core.rb
CHANGED
@@ -580,8 +580,9 @@ module Merb
|
|
580
580
|
# :log_level<Symbol>:: logger level, default is :info
|
581
581
|
#
|
582
582
|
# :disabled_components<Array[Symbol]>::
|
583
|
-
# array of disabled component names
|
584
|
-
#
|
583
|
+
# array of disabled component names,
|
584
|
+
# for instance, to disable json gem,
|
585
|
+
# specify :json. Default is empty array.
|
585
586
|
#
|
586
587
|
# :deferred_actions<Array(Symbol, String)]>::
|
587
588
|
# names of actions that should be deferred
|
data/lib/merb-core/bootloader.rb
CHANGED
@@ -378,6 +378,7 @@ class Merb::BootLoader::Dependencies < Merb::BootLoader
|
|
378
378
|
load_env_config
|
379
379
|
end
|
380
380
|
expand_ruby_path
|
381
|
+
enable_json_gem unless Merb::disabled?(:json)
|
381
382
|
update_logger
|
382
383
|
nil
|
383
384
|
end
|
@@ -404,6 +405,21 @@ class Merb::BootLoader::Dependencies < Merb::BootLoader
|
|
404
405
|
nil
|
405
406
|
end
|
406
407
|
|
408
|
+
# Requires json or json_pure.
|
409
|
+
#
|
410
|
+
# ==== Returns
|
411
|
+
# nil
|
412
|
+
#
|
413
|
+
# :api: private
|
414
|
+
def self.enable_json_gem
|
415
|
+
require "json"
|
416
|
+
rescue LoadError
|
417
|
+
Merb.logger.error! "You have enabled JSON but don't have json " \
|
418
|
+
"installed or don't have dependency in the Gemfile. " \
|
419
|
+
"Add \"gem 'json', '>= 1.1.7'\" or " \
|
420
|
+
"\"gem 'json_pure', '>= 1.1.7'\" to your Gemfile."
|
421
|
+
end
|
422
|
+
|
407
423
|
# Resets the logger and sets the log_stream to Merb::Config[:log_file]
|
408
424
|
# if one is specified, falling back to STDOUT.
|
409
425
|
#
|
@@ -1314,7 +1330,7 @@ class Merb::BootLoader::RackUpApplication < Merb::BootLoader
|
|
1314
1330
|
Merb::Config[:app] = eval("::Rack::Builder.new {( #{rackup_code}\n )}.to_app", TOPLEVEL_BINDING, Merb::Config[:rackup])
|
1315
1331
|
else
|
1316
1332
|
Merb::Config[:app] = ::Rack::Builder.new {
|
1317
|
-
use Rack::Head # handle head requests
|
1333
|
+
use Merb::Rack::Head # handle head requests
|
1318
1334
|
use Merb::Rack::ContentLength # report content length
|
1319
1335
|
if prefix = ::Merb::Config[:path_prefix]
|
1320
1336
|
use Merb::Rack::PathPrefix, prefix
|
data/lib/merb-core/config.rb
CHANGED
@@ -287,7 +287,7 @@ module Merb
|
|
287
287
|
adapters = [:mongrel, :emongrel, :thin, :ebb, :fastcgi, :webrick]
|
288
288
|
|
289
289
|
opts.on("-a", "--adapter ADAPTER",
|
290
|
-
"The rack adapter to use to run merb (default is
|
290
|
+
"The rack adapter to use to run merb (default is thin)" \
|
291
291
|
"[#{adapters.join(', ')}]") do |adapter|
|
292
292
|
options[:adapter] ||= adapter
|
293
293
|
end
|
@@ -4,119 +4,108 @@ module Merb
|
|
4
4
|
class Dispatcher
|
5
5
|
class << self
|
6
6
|
include Merb::ControllerExceptions
|
7
|
-
|
8
|
-
#
|
7
|
+
|
8
|
+
# @api private
|
9
9
|
attr_accessor :use_mutex
|
10
|
-
|
10
|
+
|
11
11
|
@@work_queue = Queue.new
|
12
|
-
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# :api: private
|
12
|
+
|
13
|
+
# @return [Queue] the current queue of dispatch jobs.
|
14
|
+
#
|
15
|
+
# @api private
|
17
16
|
def work_queue
|
18
17
|
@@work_queue
|
19
|
-
end
|
20
|
-
|
21
|
-
# Dispatch the rack environment.
|
22
|
-
# and redispatched.
|
18
|
+
end
|
19
|
+
|
20
|
+
# Dispatch the rack environment.
|
23
21
|
#
|
24
|
-
#
|
25
|
-
# rack_env<Rack::Environment>::
|
26
|
-
# The rack environment, which is used to instantiate a Merb::Request
|
22
|
+
# ControllerExceptions are rescued here and redispatched.
|
27
23
|
#
|
28
|
-
#
|
29
|
-
# Merb::Controller::
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# :api: private
|
24
|
+
# @param rack_env [Rack::Environment] The rack environment, which is used to instantiate a Merb::Request
|
25
|
+
# @return [Merb::Controller] The Merb::Controller that was dispatched to
|
26
|
+
#
|
27
|
+
# @api private
|
33
28
|
def handle(request)
|
34
29
|
request.handle
|
35
30
|
end
|
36
31
|
end
|
37
32
|
end
|
38
|
-
|
33
|
+
|
39
34
|
class Request
|
40
35
|
include Merb::ControllerExceptions
|
41
|
-
|
36
|
+
|
42
37
|
@@mutex = Mutex.new
|
43
|
-
|
38
|
+
|
44
39
|
attr_reader :start
|
45
|
-
|
46
|
-
# Handles request routing and action dispatch
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# :api: private
|
40
|
+
|
41
|
+
# Handles request routing and action dispatch
|
42
|
+
#
|
43
|
+
# @return [Array[Integer, Hash, #each]] A Rack response
|
44
|
+
#
|
45
|
+
# @api private
|
52
46
|
def handle
|
53
47
|
@start = env["merb.request_start"] = Time.now
|
54
48
|
Merb.logger.info { "Started request handling: #{start.to_s}" }
|
55
|
-
|
49
|
+
|
56
50
|
find_route!
|
57
51
|
return rack_response if handled?
|
58
|
-
|
52
|
+
|
59
53
|
klass = controller
|
60
|
-
|
61
|
-
|
54
|
+
|
62
55
|
unless klass < Controller
|
63
|
-
raise NotFound,
|
56
|
+
raise NotFound,
|
64
57
|
"Controller '#{klass}' not found.\n" \
|
65
58
|
"If Merb tries to find a controller for static files, " \
|
66
59
|
"you may need to check your Rackup file, see the Problems " \
|
67
60
|
"section at: http://wiki.merbivore.com/pages/rack-middleware"
|
68
61
|
end
|
69
|
-
|
62
|
+
|
63
|
+
Merb.logger.debug { "Routed to: #{klass::_filter_params(params).inspect}" }
|
64
|
+
|
70
65
|
if klass.abstract?
|
71
66
|
raise NotFound, "The '#{klass}' controller has no public actions"
|
72
67
|
end
|
73
|
-
|
68
|
+
|
74
69
|
dispatch_action(klass, params[:action])
|
75
70
|
rescue Object => exception
|
76
71
|
dispatch_exception(exception)
|
77
72
|
end
|
78
|
-
|
73
|
+
|
79
74
|
private
|
80
|
-
# Setup the controller and call the chosen action
|
75
|
+
# Setup the controller and call the chosen action
|
76
|
+
#
|
77
|
+
# @param klass [Merb::Controller] The controller class to dispatch to.
|
78
|
+
# @param action [Symbol] The action to dispatch.
|
79
|
+
# @param status [Integer] The status code to respond with.
|
81
80
|
#
|
82
|
-
#
|
83
|
-
# klass<Merb::Controller>:: The controller class to dispatch to.
|
84
|
-
# action<Symbol>:: The action to dispatch.
|
85
|
-
# status<Integer>:: The status code to respond with.
|
81
|
+
# @return [Array[Integer, Hash, #each]] A Rack response
|
86
82
|
#
|
87
|
-
#
|
88
|
-
# Array[Integer, Hash, #each]:: A Rack response
|
89
|
-
#
|
90
|
-
# :api: private
|
83
|
+
# @api private
|
91
84
|
def dispatch_action(klass, action_name, status=200)
|
92
85
|
@env["merb.status"] = status
|
93
86
|
@env["merb.action_name"] = action_name
|
94
|
-
|
87
|
+
|
95
88
|
if Dispatcher.use_mutex
|
96
89
|
@@mutex.synchronize { klass.call(env) }
|
97
90
|
else
|
98
91
|
klass.call(env)
|
99
92
|
end
|
100
93
|
end
|
101
|
-
|
102
|
-
# Re-route the
|
103
|
-
# available, and try to render the exception nicely.
|
94
|
+
|
95
|
+
# Re-route the request to the Exception controller if it is available
|
104
96
|
#
|
105
97
|
# You can handle exceptions by implementing actions for specific
|
106
98
|
# exceptions such as not_found or for entire classes of exceptions
|
107
|
-
# such as client_error. You can also implement handlers for
|
99
|
+
# such as client_error. You can also implement handlers for
|
108
100
|
# exceptions outside the Merb exception hierarchy (e.g.
|
109
101
|
# StandardError is caught in standard_error).
|
110
102
|
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
# The exception object that was created when trying to dispatch the
|
114
|
-
# original controller.
|
103
|
+
# @param exception [Object] The exception object that was created when
|
104
|
+
# trying to dispatch the original controller.
|
115
105
|
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
# :api: private
|
106
|
+
# @return [Array[Integer, Hash, #each]] A Rack response
|
107
|
+
#
|
108
|
+
# @api private
|
120
109
|
def dispatch_exception(exception)
|
121
110
|
if(exception.is_a?(Merb::ControllerExceptions::Base) &&
|
122
111
|
!exception.is_a?(Merb::ControllerExceptions::ServerError))
|
@@ -124,12 +113,12 @@ module Merb
|
|
124
113
|
else
|
125
114
|
Merb.logger.error(Merb.exception(exception))
|
126
115
|
end
|
127
|
-
|
116
|
+
|
128
117
|
exceptions = env["merb.exceptions"] = [exception]
|
129
|
-
|
118
|
+
|
130
119
|
begin
|
131
120
|
e = exceptions.first
|
132
|
-
|
121
|
+
|
133
122
|
if action_name = e.action_name
|
134
123
|
dispatch_action(Exceptions, action_name, e.class.status)
|
135
124
|
else
|
@@ -141,7 +130,7 @@ module Merb
|
|
141
130
|
else
|
142
131
|
Merb.logger.error("Dispatching #{e.class} raised another error.")
|
143
132
|
Merb.logger.error(Merb.exception(dispatch_issue))
|
144
|
-
|
133
|
+
|
145
134
|
exceptions.unshift dispatch_issue
|
146
135
|
retry
|
147
136
|
end
|
@@ -324,7 +324,7 @@ module Merb
|
|
324
324
|
def message
|
325
325
|
return {} unless params[:_message]
|
326
326
|
begin
|
327
|
-
Marshal.load(
|
327
|
+
Marshal.load(params[:_message].unpack("m").first)
|
328
328
|
rescue ArgumentError, TypeError
|
329
329
|
{}
|
330
330
|
end
|
@@ -1,6 +1,12 @@
|
|
1
1
|
require 'merb-core/dispatch/session/container'
|
2
2
|
require 'merb-core/dispatch/session/store_container'
|
3
3
|
|
4
|
+
# Try to require SecureRandom from the Ruby 1.9.x
|
5
|
+
begin
|
6
|
+
require 'securerandom'
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
4
10
|
module Merb
|
5
11
|
class Config
|
6
12
|
# Returns stores list constructed from
|
@@ -74,16 +80,20 @@ module Merb
|
|
74
80
|
#
|
75
81
|
# :api: private
|
76
82
|
def rand_uuid
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
if defined?(SecureRandom)
|
84
|
+
SecureRandom.hex(16)
|
85
|
+
else
|
86
|
+
values = [
|
87
|
+
rand(0x0010000),
|
88
|
+
rand(0x0010000),
|
89
|
+
rand(0x0010000),
|
90
|
+
rand(0x0010000),
|
91
|
+
rand(0x0010000),
|
92
|
+
rand(0x1000000),
|
93
|
+
rand(0x1000000),
|
94
|
+
]
|
95
|
+
"%04x%04x%04x%04x%04x%06x%06x" % values
|
96
|
+
end
|
87
97
|
end
|
88
98
|
|
89
99
|
# Marks this session as needing a new cookie.
|