padrino-core 0.11.4 → 0.12.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/padrino-core/application/authenticity_token.rb +25 -0
  3. data/lib/padrino-core/application/rendering/extensions/erubis.rb +11 -7
  4. data/lib/padrino-core/application/rendering/extensions/haml.rb +3 -2
  5. data/lib/padrino-core/application/rendering/extensions/slim.rb +10 -3
  6. data/lib/padrino-core/application/rendering.rb +13 -5
  7. data/lib/padrino-core/application/routing.rb +62 -19
  8. data/lib/padrino-core/application.rb +136 -50
  9. data/lib/padrino-core/cli/base.rb +32 -1
  10. data/lib/padrino-core/loader.rb +68 -68
  11. data/lib/padrino-core/logger.rb +6 -6
  12. data/lib/padrino-core/mounter.rb +9 -4
  13. data/lib/padrino-core/reloader/rack.rb +26 -0
  14. data/lib/padrino-core/reloader/storage.rb +55 -0
  15. data/lib/padrino-core/reloader.rb +192 -287
  16. data/lib/padrino-core/router.rb +11 -12
  17. data/lib/padrino-core/server.rb +5 -0
  18. data/lib/padrino-core/support_lite.rb +31 -32
  19. data/lib/padrino-core/version.rb +1 -1
  20. data/lib/padrino-core.rb +22 -30
  21. data/padrino-core.gemspec +2 -1
  22. data/test/fixtures/apps/helpers/system_helpers.rb +8 -0
  23. data/test/fixtures/apps/kiq.rb +3 -0
  24. data/test/fixtures/apps/lib/myklass/mysubklass.rb +4 -0
  25. data/test/fixtures/apps/lib/myklass.rb +2 -0
  26. data/test/fixtures/apps/models/child.rb +2 -0
  27. data/test/fixtures/apps/models/parent.rb +5 -0
  28. data/test/fixtures/apps/render.rb +13 -0
  29. data/test/fixtures/apps/system.rb +13 -0
  30. data/test/fixtures/apps/views/blog/post.erb +1 -0
  31. data/test/helper.rb +1 -1
  32. data/test/mini_shoulda.rb +4 -4
  33. data/test/test_application.rb +5 -13
  34. data/test/test_core.rb +2 -6
  35. data/test/test_csrf_protection.rb +67 -1
  36. data/test/test_dependencies.rb +14 -1
  37. data/test/test_mounter.rb +50 -6
  38. data/test/test_reloader_complex.rb +2 -2
  39. data/test/test_reloader_simple.rb +1 -1
  40. data/test/test_reloader_system.rb +52 -0
  41. data/test/test_rendering.rb +54 -0
  42. data/test/test_router.rb +121 -2
  43. data/test/test_routing.rb +84 -15
  44. metadata +29 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4eaaf6b58a471d045e8141109e191b8932937605
4
- data.tar.gz: f84f79482e130307c53a7fd152b8db5b2e6aec2d
3
+ metadata.gz: 07676eda48ccc772dcca11b4d6ebe2267cb86fe9
4
+ data.tar.gz: 669c9795dd7cd5eab46986a28fed64ea87400311
5
5
  SHA512:
6
- metadata.gz: d19c9ccab9b572cb7d624e884f1e3948b8c1d4b7cd6e22cba8a8a4c16d0cc139b97365f8fdcf5e9fca288aef8b5d12d0308a193fd685d505c51c7378986cb644
7
- data.tar.gz: f8c01eaba904cc2ba5dbab8ddb28d323721ed00b9ff56ac95619dc999cbd711172751fed794d249febfd33b932bc44a22c430c24f47182a101f7af622d956eab
6
+ metadata.gz: a4b95dfbdd3ea29423c1f09424ac28a4fce32e08732830b739b08ec159d6205f84f423a04224c9b17ed889c5b4d6850678e94943f8960c6ee94ad2fe8cf69709
7
+ data.tar.gz: 3c5da6330346fe9950be1bb42dc706c4bca7e682e452d42c7d1c9e6fc18f82b71c482c7eceaaac2838285db1629bf8ecab76d04061201e00afa4b7edc070237f
@@ -0,0 +1,25 @@
1
+ module Padrino
2
+ class AuthenticityToken < Rack::Protection::AuthenticityToken
3
+ def initialize(app, options = {})
4
+ @app = app
5
+ @except = options[:except]
6
+ @except = Array(@except) unless @except.is_a?(Proc)
7
+ super
8
+ end
9
+
10
+ def call(env)
11
+ if except?(env)
12
+ @app.call(env)
13
+ else
14
+ super(env)
15
+ end
16
+ end
17
+
18
+ def except?(env)
19
+ return false unless @except
20
+ path_info = env['PATH_INFO']
21
+ @except.is_a?(Proc) ? @except.call(env) : @except.any?{|path|
22
+ path.is_a?(Regexp) ? path.match(path_info) : path == path_info }
23
+ end
24
+ end
25
+ end
@@ -40,15 +40,18 @@ begin
40
40
  def render(*args)
41
41
  app = args.first
42
42
  app_class = app.class
43
- @padrino_app = app.kind_of?(Padrino::Application) ||
44
- (app_class.respond_to?(:erb) && app_class.erb[:engine_class] == Padrino::Erubis::SafeBufferTemplate)
43
+ @is_padrino_app = app.kind_of?(Padrino::Application) ||
44
+ (app_class.respond_to?(:erb) && app_class.erb[:engine_class] == Padrino::Erubis::SafeBufferTemplate)
45
45
  super
46
46
  end
47
47
 
48
+ ##
49
+ # In preamble we need a flag `__in_erb_template` and SafeBuffer for padrino apps.
50
+ #
48
51
  def precompiled_preamble(locals)
49
- buf = @padrino_app ? "ActiveSupport::SafeBuffer.new" : "''"
50
- old_postamble = super.split("\n")[0..-2]
51
- [old_postamble, "#{@outvar} = _buf = (#{@outvar} || #{buf})"].join("\n")
52
+ original = super
53
+ return original unless @is_padrino_app
54
+ "__in_erb_template = true\n" << original.rpartition("\n").first << "#{@outvar} = _buf = ActiveSupport::SafeBuffer.new\n"
52
55
  end
53
56
  end
54
57
  end
@@ -57,8 +60,9 @@ begin
57
60
  Tilt.prefer(Padrino::Erubis::Template, :erb)
58
61
 
59
62
  if defined? Padrino::Rendering
60
- Padrino::Rendering.engine_configurations[:erb] =
61
- {:engine_class => Padrino::Erubis::SafeBufferTemplate}
63
+ Padrino::Rendering.engine_configurations[:erb] = {
64
+ :engine_class => Padrino::Erubis::SafeBufferTemplate,
65
+ }
62
66
  end
63
67
  rescue LoadError
64
68
  end
@@ -17,8 +17,9 @@ begin
17
17
  end
18
18
 
19
19
  if defined? Padrino::Rendering
20
- Padrino::Rendering.engine_configurations[:haml] =
21
- {:escape_html => true}
20
+ Padrino::Rendering.engine_configurations[:haml] = {
21
+ :escape_html => true,
22
+ }
22
23
 
23
24
  class Tilt::HamlTemplate
24
25
  include Padrino::Rendering::SafeTemplate
@@ -2,12 +2,19 @@ begin
2
2
  require 'slim'
3
3
 
4
4
  if defined? Padrino::Rendering
5
- Padrino::Rendering.engine_configurations[:slim] =
6
- {:generator => Temple::Generators::RailsOutputBuffer,
7
- :buffer => "@_out_buf", :use_html_safe => true}
5
+ Padrino::Rendering.engine_configurations[:slim] = {
6
+ :generator => Temple::Generators::RailsOutputBuffer,
7
+ :buffer => "@_out_buf",
8
+ :use_html_safe => true,
9
+ :disable_capture => true,
10
+ }
8
11
 
9
12
  class Slim::Template
10
13
  include Padrino::Rendering::SafeTemplate
14
+
15
+ def precompiled_preamble(locals)
16
+ "__in_slim_template = true\n" << super
17
+ end
11
18
  end
12
19
  end
13
20
  rescue LoadError
@@ -195,14 +195,16 @@ module Padrino
195
195
  options[:layout] = @layout if options[:layout].nil? || options[:layout] == true
196
196
  # Resolve layouts similar to in Rails
197
197
  if options[:layout].nil? && !settings.templates.has_key?(:layout)
198
- layout_path, layout_engine = *resolved_layout
198
+ layout_path = settings.fetch_layout_path(options[:layout])
199
+ is_included_extension = %w[.slim .erb .haml].include?(File.extname(layout_path.to_s))
200
+ layout_path, layout_engine = *(is_included_extension ? resolve_template(layout_path) : resolved_layout)
199
201
 
200
202
  # We need to force layout false so sinatra don't try to render it
201
203
  options[:layout] = layout_path || false
202
- options[:layout] = false unless layout_engine == engine # TODO allow different layout engine
204
+ options[:layout] = false unless is_included_extension ? layout_engine : layout_engine == engine
203
205
  options[:layout_engine] = layout_engine || engine if options[:layout]
204
206
  elsif options[:layout].present?
205
- options[:layout] = settings.fetch_layout_path(options[:layout] || @layout)
207
+ options[:layout], options[:layout_engine] = *resolve_template(settings.fetch_layout_path(options[:layout]))
206
208
  end
207
209
  # Default to original layout value if none found.
208
210
  options[:layout] ||= layout_was
@@ -276,11 +278,17 @@ module Padrino
276
278
  view_path = options.delete(:views) || settings.views || "./views"
277
279
  target_extension = File.extname(template_path)[1..-1] || "none" # explicit template extension
278
280
  template_path = template_path.chomp(".#{target_extension}")
281
+ template_glob =
282
+ if respond_to?(:request) && request.controller.present?
283
+ File.join("{,#{request.controller}}", template_path)
284
+ else
285
+ template_path
286
+ end
279
287
 
280
288
  # Generate potential template candidates
281
- templates = Dir[File.join(view_path, template_path) + ".*"].map do |file|
289
+ templates = Dir[File.join(view_path, template_glob) + ".*"].map do |file|
282
290
  template_engine = File.extname(file)[1..-1].to_sym # Retrieves engine extension
283
- template_file = file.sub(view_path, '').chomp(".#{template_engine}").to_sym # retrieves template filename
291
+ template_file = file.squeeze('/').sub(view_path, '').chomp(".#{template_engine}").to_sym # retrieves template filename
284
292
  [template_file, template_engine] unless IGNORE_FILE_PATTERN.any? { |pattern| template_engine.to_s =~ pattern }
285
293
  end
286
294
 
@@ -15,6 +15,19 @@ class Sinatra::Request
15
15
  end
16
16
  end
17
17
 
18
+ ##
19
+ # This patches Sinatra to accept UTF-8 urls on JRuby 1.7.6
20
+ #
21
+ if RUBY_ENGINE == 'jruby' && defined?(JRUBY_VERSION) && JRUBY_VERSION > '1.7.4'
22
+ class Sinatra::Base
23
+ class << self
24
+ alias_method :old_generate_method, :generate_method
25
+ def generate_method(method_name, &block)
26
+ old_generate_method(method_name.to_sym, &block)
27
+ end
28
+ end
29
+ end
30
+ end
18
31
 
19
32
  class HttpRouter
20
33
  def rewrite_partial_path_info(env, request); end
@@ -61,7 +74,7 @@ class HttpRouter
61
74
  class Route
62
75
  VALID_HTTP_VERBS.replace %w[GET POST PUT PATCH DELETE HEAD OPTIONS LINK UNLINK]
63
76
 
64
- attr_accessor :use_layout, :controller, :action, :cache, :cache_key, :cache_expires_in, :parent
77
+ attr_accessor :use_layout, :controller, :action, :cache, :cache_key, :cache_expires, :parent
65
78
 
66
79
  def before_filters(&block)
67
80
  @_before_filters ||= []
@@ -172,6 +185,7 @@ class HttpRouter
172
185
  env['router.request'] = request
173
186
  env['router.params'] ||= {}
174
187
  #{"env['router.params'].merge!(Hash[#{param_names.inspect}.zip(request.params)])" if dynamic?}
188
+ env['router.params'] = env['router.params'].with_indifferent_access
175
189
  @router.rewrite#{"_partial" if route.match_partially}_path_info(env, request)
176
190
  response = @router.process_destination_path(#{path_ivar}, env)
177
191
  return response unless router.pass_on_response(response)
@@ -193,7 +207,7 @@ module Padrino
193
207
  def apply?(request)
194
208
  detect = @args.any? do |arg|
195
209
  case arg
196
- when Symbol then request.route_obj && (request.route_obj.name == arg or request.route_obj.name == [@scoped_controller, arg].flatten.join("_").to_sym)
210
+ when Symbol then request.route_obj && (request.route_obj.name == arg or request.route_obj.name == [@scoped_controller, arg].flatten.join(" ").to_sym)
197
211
  else arg === request.path_info
198
212
  end
199
213
  end || @options.any? do |name, val|
@@ -557,7 +571,7 @@ module Padrino
557
571
  def url(*args)
558
572
  params = args.extract_options! # parameters is hash at end
559
573
  names, params_array = args.partition{|a| a.is_a?(Symbol)}
560
- name = names.join("_").to_sym # route name is concatenated with underscores
574
+ name = names[0, 2].join(" ").to_sym # route name is concatenated with underscores
561
575
  if params.is_a?(Hash)
562
576
  params[:format] = params[:format].to_s unless params[:format].nil?
563
577
  params = value_to_param(params)
@@ -568,10 +582,7 @@ module Padrino
568
582
  else
569
583
  compiled_router.path(name, *(params_array << params))
570
584
  end
571
- url[0,0] = conform_uri(uri_root) if defined?(uri_root)
572
- url[0,0] = conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
573
- url = "/" if url.blank?
574
- url
585
+ rebase_url(url)
575
586
  rescue HttpRouter::InvalidRouteException
576
587
  route_error = "route mapping for url(#{name.inspect}) could not be found!"
577
588
  raise Padrino::Routing::UnrecognizedException.new(route_error)
@@ -586,6 +597,17 @@ module Padrino
586
597
  route('HEAD', path, *args, &block)
587
598
  end
588
599
 
600
+ def rebase_url(url)
601
+ if url.start_with?('/')
602
+ new_url = ''
603
+ new_url << conform_uri(uri_root) if defined?(uri_root)
604
+ new_url << conform_uri(ENV['RACK_BASE_URI']) if ENV['RACK_BASE_URI']
605
+ new_url << url
606
+ else
607
+ url.blank? ? '/' : url
608
+ end
609
+ end
610
+
589
611
  private
590
612
  # Parse params from the url method
591
613
  def value_to_param(value)
@@ -786,7 +808,7 @@ module Padrino
786
808
  name = options.delete(:name) if name.nil? && options.key?(:name)
787
809
  if name
788
810
  controller_name = controller.join("_")
789
- name = "#{controller_name}_#{name}".to_sym unless controller_name.blank?
811
+ name = "#{controller_name} #{name}".to_sym unless controller_name.blank?
790
812
  end
791
813
 
792
814
  # Merge in option defaults.
@@ -859,6 +881,7 @@ module Padrino
859
881
  mime_types = types.map { |t| mime_type(t) }.compact
860
882
  url_format = params[:format].to_sym if params[:format]
861
883
  accepts = request.accept.map(&:to_str)
884
+ accepts = [] if accepts == ["*/*"]
862
885
 
863
886
  # Per rfc2616-sec14:
864
887
  # Assume */* if no ACCEPT header is given.
@@ -890,7 +913,12 @@ module Padrino
890
913
 
891
914
  if matched_format
892
915
  @_content_type = url_format || accept_format || :html
893
- content_type(@_content_type, :charset => 'utf-8')
916
+
917
+ if @_content_type != :json
918
+ content_type(@_content_type, :charset => 'utf-8')
919
+ else
920
+ content_type(@_content_type)
921
+ end
894
922
  end
895
923
 
896
924
  matched_format
@@ -924,17 +952,24 @@ module Padrino
924
952
  # url(:show, :id => 1)
925
953
  # url(:show, :name => :test)
926
954
  # url(:show, 1)
927
- # url("/foo")
955
+ # url("/foo", false, false)
928
956
  #
929
957
  # @see Padrino::Routing::ClassMethods#url
930
958
  #
931
959
  def url(*args)
932
- # Delegate to Sinatra 1.2 for simple url("/foo")
933
- # http://www.sinatrarb.com/intro#Generating%20URLs
934
- return super if args.first.is_a?(String) && !args[1].is_a?(Hash)
935
-
936
- # Delegate to Padrino named route URL generation.
937
- settings.url(*args)
960
+ if args.first.is_a?(String)
961
+ url_path = settings.rebase_url(args.shift)
962
+ if args.empty?
963
+ url_path
964
+ else
965
+ # Delegate sinatra-style urls to Sinatra. Ex: url("/foo", false, false)
966
+ # http://www.sinatrarb.com/intro#Generating%20URLs
967
+ super url_path, *args
968
+ end
969
+ else
970
+ # Delegate to Padrino named route URL generation.
971
+ settings.url(*args)
972
+ end
938
973
  end
939
974
  alias :url_for :url
940
975
 
@@ -944,9 +979,15 @@ module Padrino
944
979
  # @example
945
980
  # absolute_url(:show, :id => 1) # => http://example.com/show?id=1
946
981
  # absolute_url(:show, 24) # => https://example.com/admin/show/24
982
+ # absolute_url('/foo/bar') # => https://example.com/admin/foo/bar
983
+ # absolute_url('baz') # => https://example.com/admin/foo/baz
947
984
  #
948
- def absolute_url( *args )
949
- uri url(*args), true, false
985
+ def absolute_url(*args)
986
+ url_path = args.shift
987
+ if url_path.is_a?(String) && !url_path.start_with?('/')
988
+ url_path = request.env['PATH_INFO'].rpartition('/').first << '/' << url_path
989
+ end
990
+ uri url(url_path, *args), true, false
950
991
  end
951
992
 
952
993
  def recognize_path(path)
@@ -958,10 +999,12 @@ module Padrino
958
999
  #
959
1000
  def current_path(*path_params)
960
1001
  if path_params.last.is_a?(Hash)
961
- path_params[-1] = params.merge(path_params[-1])
1002
+ path_params[-1] = params.merge(path_params[-1].with_indifferent_access)
962
1003
  else
963
1004
  path_params << params
964
1005
  end
1006
+
1007
+ path_params[-1] = path_params[-1].symbolize_keys
965
1008
  @route.path(*path_params)
966
1009
  end
967
1010
 
@@ -2,11 +2,9 @@ require 'padrino-core/application/flash'
2
2
  require 'padrino-core/application/rendering'
3
3
  require 'padrino-core/application/routing'
4
4
  require 'padrino-core/application/showexceptions'
5
+ require 'padrino-core/application/authenticity_token'
5
6
 
6
7
  module Padrino
7
- class ApplicationSetupError < RuntimeError
8
- end
9
-
10
8
  ##
11
9
  # Subclasses of this become independent Padrino applications
12
10
  # (stemming from Sinatra::Application).
@@ -26,20 +24,24 @@ module Padrino
26
24
  Padrino.logger
27
25
  end
28
26
 
27
+ # TODO: Remove this hack after getting rid of thread-unsafe http_router:
28
+ alias_method :original_call, :call
29
+ def call(*args)
30
+ settings.init_mutex.synchronize do
31
+ instance_eval{ undef :call }
32
+ class_eval{ alias_method :call, :original_call }
33
+ instance_eval{ undef :original_call }
34
+ super(*args)
35
+ end
36
+ end
37
+
29
38
  class << self
30
39
  def inherited(base)
31
40
  begun_at = Time.now
32
41
  CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
33
42
  base.default_configuration!
34
- base.prerequisites.concat([
35
- File.join(base.root, '/models.rb'),
36
- File.join(base.root, '/models/**/*.rb'),
37
- File.join(base.root, '/lib.rb'),
38
- File.join(base.root, '/lib/**/*.rb')
39
- ]).uniq!
40
- Padrino.require_dependencies(base.prerequisites)
41
43
  logger.devel :setup, begun_at, base
42
- super(base) # Loading the subclass inherited method
44
+ super(base)
43
45
  end
44
46
 
45
47
  ##
@@ -54,10 +56,10 @@ module Padrino
54
56
  # MyApp.reload!
55
57
  #
56
58
  def reload!
57
- logger.devel "Reloading #{settings}"
59
+ logger.devel "Reloading application #{settings}"
58
60
  reset!
59
61
  reset_router!
60
- Padrino.require_dependencies(settings.app_file, :force => true) # Reload the app file
62
+ Padrino.require_dependencies(settings.app_file, :force => true)
61
63
  require_dependencies
62
64
  default_filters!
63
65
  default_routes!
@@ -90,6 +92,26 @@ module Padrino
90
92
  router.routes
91
93
  end
92
94
 
95
+ ##
96
+ # Returns an absolute path of view in application views folder.
97
+ #
98
+ # @example
99
+ # Admin.view_path 'users/index' #=> "/home/user/test/admin/views/users/index"
100
+ #
101
+ def view_path(view)
102
+ File.expand_path(view, views)
103
+ end
104
+
105
+ ##
106
+ # Returns an absolute path of application layout.
107
+ #
108
+ # @example
109
+ # Admin.layout_path :application #=> "/home/user/test/admin/views/layouts/application"
110
+ #
111
+ def layout_path(layout)
112
+ view_path("layouts/#{layout}")
113
+ end
114
+
93
115
  ##
94
116
  # Setup the application by registering initializers, load paths and logger.
95
117
  # Invoked automatically when an application is first instantiated.
@@ -103,11 +125,11 @@ module Padrino
103
125
  settings.default_routes!
104
126
  settings.default_errors!
105
127
  if defined?(I18n)
128
+ Reloader.special_files += settings.locale_path
106
129
  I18n.load_path << settings.locale_path
107
130
  I18n.reload!
108
131
  end
109
132
  @_configured = true
110
- @_configured
111
133
  end
112
134
 
113
135
  ##
@@ -127,7 +149,13 @@ module Padrino
127
149
  # directory that need to be added to +$LOAD_PATHS+ from this application
128
150
  #
129
151
  def load_paths
130
- @_load_paths ||= %w[models lib mailers controllers helpers].map { |path| File.join(settings.root, path) }
152
+ @_load_paths ||= [
153
+ 'models',
154
+ 'lib',
155
+ 'mailers',
156
+ 'controllers',
157
+ 'helpers',
158
+ ].map { |path| File.join(settings.root, path) }
131
159
  end
132
160
 
133
161
  ##
@@ -143,8 +171,14 @@ module Padrino
143
171
  #
144
172
  def dependencies
145
173
  [
146
- 'urls.rb', 'config/urls.rb', 'mailers/*.rb', 'mailers.rb',
147
- 'controllers/**/*.rb', 'controllers.rb', 'helpers/**/*.rb', 'helpers.rb'
174
+ 'urls.rb',
175
+ 'config/urls.rb',
176
+ 'mailers/*.rb',
177
+ 'mailers.rb',
178
+ 'controllers/**/*.rb',
179
+ 'controllers.rb',
180
+ 'helpers/**/*.rb',
181
+ 'helpers.rb',
148
182
  ].map { |file| Dir[File.join(settings.root, file)] }.flatten
149
183
  end
150
184
 
@@ -168,37 +202,62 @@ module Padrino
168
202
  end
169
203
 
170
204
  protected
205
+
171
206
  ##
172
207
  # Defines default settings for Padrino application.
173
208
  #
174
209
  def default_configuration!
175
- # Overwriting Sinatra defaults
176
- set :app_file, File.expand_path(caller_files.first || $0) # Assume app file is first caller
210
+ set :app_file, File.expand_path(caller_files.first || $0)
211
+ set :app_name, settings.to_s.underscore.to_sym
212
+
177
213
  set :environment, Padrino.env
178
214
  set :reload, Proc.new { development? }
179
215
  set :logging, Proc.new { development? }
216
+
180
217
  set :method_override, true
181
- set :sessions, false
182
- set :public_folder, Proc.new { Padrino.root('public', uri_root) }
183
- set :views, Proc.new { File.join(root, 'views') }
184
- set :images_path, Proc.new { File.join(public_folder, 'images') }
185
- set :protection, true
218
+ set :default_builder, 'StandardFormBuilder'
186
219
 
187
- set :haml, { :ugly => (Padrino.env == :production) } if defined?(Haml)
220
+ # TODO: Remove this hack after getting rid of thread-unsafe http_router:
221
+ set :init_mutex, Mutex.new
188
222
 
189
- # Padrino specific
190
- set :uri_root, '/'
191
- set :app_name, settings.to_s.underscore.to_sym
192
- set :default_builder, 'StandardFormBuilder'
193
- set :authentication, false
223
+ # TODO: Remove this line after sinatra version up.
224
+ set :add_charset, %w[javascript xml xhtml+xml].map {|t| "application/#{t}" }
225
+
226
+ default_paths!
227
+ default_security!
228
+ global_configuration!
229
+ setup_prerequisites!
230
+ end
231
+
232
+ def setup_prerequisites!
233
+ prerequisites.concat(default_prerequisites).uniq!
234
+ Padrino.require_dependencies(prerequisites)
235
+ end
194
236
 
195
- set :locale_path, Proc.new { Dir[File.join(settings.root, '/locale/**/*.{rb,yml}')] }
237
+ def default_paths!
238
+ set :locale_path, Proc.new { Dir.glob File.join(root, 'locale/**/*.{rb,yml}') }
239
+ set :views, Proc.new { File.join(root, 'views') }
196
240
 
197
- # Authenticity token
241
+ set :uri_root, '/'
242
+ set :public_folder, Proc.new { Padrino.root('public', uri_root) }
243
+ set :images_path, Proc.new { File.join(public_folder, 'images') }
244
+ end
245
+
246
+ def default_security!
247
+ set :protection, :except => :path_traversal
248
+ set :authentication, false
249
+ set :sessions, false
198
250
  set :protect_from_csrf, false
199
251
  set :allow_disabled_csrf, false
200
- # Load the Global Configurations
201
- class_eval(&Padrino.apps_configuration) if Padrino.apps_configuration
252
+ end
253
+
254
+ ##
255
+ # Applies global padrino configuration blocks to current application.
256
+ #
257
+ def global_configuration!
258
+ Padrino.global_configurations.each do |configuration|
259
+ class_eval(&configuration)
260
+ end
202
261
  end
203
262
 
204
263
  ##
@@ -220,9 +279,7 @@ module Padrino
220
279
  #
221
280
  def default_filters!
222
281
  before do
223
- unless @_content_type
224
- response['Content-Type'] = 'text/html;charset=utf-8'
225
- end
282
+ response['Content-Type'] = 'text/html;charset=utf-8' unless @_content_type
226
283
  end
227
284
  end
228
285
 
@@ -249,7 +306,20 @@ module Padrino
249
306
  Padrino.require_dependencies(dependencies, :force => true)
250
307
  end
251
308
 
309
+ ##
310
+ # Returns globs of default paths of application prerequisites.
311
+ #
312
+ def default_prerequisites
313
+ [
314
+ '/models.rb',
315
+ '/models/**/*.rb',
316
+ '/lib.rb',
317
+ '/lib/**/*.rb',
318
+ ].map{ |glob| File.join(settings.root, glob) }
319
+ end
320
+
252
321
  private
322
+
253
323
  # Overrides the default middleware for Sinatra based on Padrino conventions.
254
324
  # Also initializes the application after setting up the middleware.
255
325
  def setup_default_middleware(builder)
@@ -267,6 +337,34 @@ module Padrino
267
337
 
268
338
  # sets up csrf protection for the app:
269
339
  def setup_csrf_protection(builder)
340
+ check_csrf_protection_dependency
341
+
342
+ if protect_from_csrf?
343
+ if protect_from_csrf.is_a?(Hash) && protect_from_csrf[:except]
344
+ builder.use(AuthenticityToken,
345
+ options_for_csrf_protection_setup.merge(:except => protect_from_csrf[:except]))
346
+ else
347
+ builder.use(Rack::Protection::AuthenticityToken,
348
+ options_for_csrf_protection_setup)
349
+ end
350
+ end
351
+ end
352
+
353
+ # returns the options used in the builder for csrf protection setup
354
+ def options_for_csrf_protection_setup
355
+ options = { :logger => logger }
356
+
357
+ if allow_disabled_csrf?
358
+ options.merge!({
359
+ :reaction => :report,
360
+ :report_key => 'protection.csrf.failed'
361
+ })
362
+ end
363
+ options
364
+ end
365
+
366
+ # throw an exception if the protect_from_csrf is active but sessions not.
367
+ def check_csrf_protection_dependency
270
368
  if protect_from_csrf? && !sessions?
271
369
  raise(<<-ERROR)
272
370
  `protect_from_csrf` is activated, but `sessions` are not. To enable csrf
@@ -277,19 +375,7 @@ protection, use:
277
375
  or deactivate protect_from_csrf:
278
376
 
279
377
  disable :protect_from_csrf
280
- ERROR
281
- end
282
-
283
- if protect_from_csrf?
284
- if allow_disabled_csrf?
285
- builder.use Rack::Protection::AuthenticityToken,
286
- :reaction => :report,
287
- :report_key => 'protection.csrf.failed',
288
- :logger => logger
289
- else
290
- builder.use Rack::Protection::AuthenticityToken,
291
- :logger => logger
292
- end
378
+ ERROR
293
379
  end
294
380
  end
295
381
  end
@@ -18,11 +18,19 @@ module Padrino
18
18
  method_option :daemonize, :type => :boolean, :aliases => "-d", :desc => "Run daemonized in the background."
19
19
  method_option :pid, :type => :string, :aliases => "-i", :desc => "File to store pid."
20
20
  method_option :debug, :type => :boolean, :desc => "Set debugging flags."
21
+ method_option :options, :type => :array, :aliases => "-O", :desc => "--options NAME=VALUE NAME2=VALUE2'. pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$0} --server_options"
22
+ method_option :server_options, :type => :boolean, :desc => "Tells the current server handler's options that can be used with --options"
23
+
21
24
  def start
22
25
  prepare :start
23
26
  require File.expand_path("../adapter", __FILE__)
24
27
  require File.expand_path('config/boot.rb')
25
- Padrino::Cli::Adapter.start(options)
28
+
29
+ if options[:server_options]
30
+ puts server_options(options)
31
+ else
32
+ Padrino::Cli::Adapter.start(options)
33
+ end
26
34
  end
27
35
 
28
36
  desc "stop", "Stops the Padrino application (alternatively use 'st')."
@@ -124,6 +132,29 @@ module Padrino
124
132
  end
125
133
  end
126
134
 
135
+ # https://github.com/rack/rack/blob/master/lib/rack/server.rb\#L100
136
+ def server_options(options)
137
+ begin
138
+ info = []
139
+ server = Rack::Handler.get(options[:server]) || Rack::Handler.default(options)
140
+ if server && server.respond_to?(:valid_options)
141
+ info << ""
142
+ info << "Server-specific options for #{server.name}:"
143
+
144
+ has_options = false
145
+ server.valid_options.each do |name, description|
146
+ next if name.to_s.match(/^(Host|Port)[^a-zA-Z]/) # ignore handler's host and port options, we do our own.
147
+ info << " -O %-21s %s" % [name, description]
148
+ has_options = true
149
+ end
150
+ return "" if !has_options
151
+ end
152
+ info.join("\n")
153
+ rescue NameError
154
+ return "Warning: Could not find handler specified (#{options[:server] || 'default'}) to determine handler-specific options"
155
+ end
156
+ end
157
+
127
158
  protected
128
159
 
129
160
  def self.banner(task=nil, *args)