sinatra 2.0.5 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sinatra might be problematic. Click here for more details.

@@ -121,7 +121,7 @@ Arquivos estáticos são disponibilizados a partir do directório
121
121
  `:public_folder`
122
122
 
123
123
  ```ruby
124
- set :public_folder, File.dirname(__FILE__) + '/estatico'
124
+ set :public_folder, __dir__ + '/estatico'
125
125
  ```
126
126
 
127
127
  Note que o nome do directório público não é incluido no URL. Um arquivo
@@ -134,7 +134,7 @@ Templates presumem-se estar localizados sob o directório `./views`. Para
134
134
  utilizar um directório de views diferente:
135
135
 
136
136
  ```ruby
137
- set :views, File.dirname(__FILE__) + '/modelo'
137
+ set :views, __dir__ + '/modelo'
138
138
  ```
139
139
 
140
140
  Uma coisa importante a ser lembrada é que você sempre tem as referências
@@ -757,7 +757,7 @@ Alternativamente, pode adicionar o directório do `sinatra/lib` no
757
757
  `LOAD_PATH` do seu aplicativo:
758
758
 
759
759
  ```ruby
760
- $LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
760
+ $LOAD_PATH.unshift __dir__ + '/sinatra/lib'
761
761
  require 'rubygems'
762
762
  require 'sinatra'
763
763
 
@@ -431,7 +431,7 @@ end
431
431
  месторасположение при помощи опции `:public_folder`:
432
432
 
433
433
  ```ruby
434
- set :public_folder, File.dirname(__FILE__) + '/static'
434
+ set :public_folder, __dir__ + '/static'
435
435
  ```
436
436
 
437
437
  Учтите, что имя директории со статическими файлами не включено в URL.
@@ -2226,7 +2226,7 @@ end
2226
2226
  ### Настройка защиты от атак
2227
2227
 
2228
2228
  Sinatra использует
2229
- [Rack::Protection](https://github.com/sinatra/rack-protection#readme) для защиты
2229
+ [Rack::Protection](https://github.com/sinatra/sinatra/tree/master/rack-protection#readme) для защиты
2230
2230
  приложения от простых атак. Вы можете легко выключить эту защиту (что сделает
2231
2231
  ваше приложение чрезвычайно уязвимым к большому числу различных уязвимостей):
2232
2232
 
@@ -3089,9 +3089,9 @@ thin --threaded start
3089
3089
 
3090
3090
  Следующие версии Ruby официально поддерживаются:
3091
3091
  <dl>
3092
- <dt>Ruby 2.2</dt>
3092
+ <dt>Ruby 2.3</dt>
3093
3093
  <dd>
3094
- Версия 2.2 полностью поддерживается и рекомендуется. В настоящее время нет
3094
+ Версия 2.3 полностью поддерживается и рекомендуется. В настоящее время нет
3095
3095
  планов отказаться от официальной поддержки.
3096
3096
  </dd>
3097
3097
 
@@ -393,7 +393,7 @@ end
393
393
  静态文件从 `./public` 目录提供服务。可以通过设置`:public_folder` 选项设定一个不同的位置:
394
394
 
395
395
  ```ruby
396
- set :public_folder, File.dirname(__FILE__) + '/static'
396
+ set :public_folder, __dir__ + '/static'
397
397
  ```
398
398
 
399
399
  请注意 public 目录名并没有包含在 URL 中。文件 `./public/css/style.css` 可以通过
@@ -2027,7 +2027,7 @@ end
2027
2027
 
2028
2028
  ### 配置攻击防护
2029
2029
 
2030
- Sinatra 使用 [Rack::Protection](https://github.com/sinatra/rack-protection#readme)
2030
+ Sinatra 使用 [Rack::Protection](https://github.com/sinatra/sinatra/tree/master/rack-protection#readme)
2031
2031
  来抵御常见的攻击。你可以轻易地禁用该行为(但这会大大增加应用被攻击的概率)。
2032
2032
 
2033
2033
  ```ruby
data/Rakefile CHANGED
@@ -202,11 +202,14 @@ if defined?(Gem)
202
202
 
203
203
  desc "Commits the version to github repository"
204
204
  task :commit_version do
205
- sh <<-SH
206
- sed -i "s/.*VERSION.*/ VERSION = '#{source_version}'/" lib/sinatra/version.rb
207
- sed -i "s/.*VERSION.*/ VERSION = '#{source_version}'/" sinatra-contrib/lib/sinatra/contrib/version.rb
208
- sed -i "s/.*VERSION.*/ VERSION = '#{source_version}'/" rack-protection/lib/rack/protection/version.rb
209
- SH
205
+ %w[
206
+ lib/sinatra
207
+ sinatra-contrib/lib/sinatra/contrib
208
+ rack-protection/lib/rack/protection
209
+ ].each do |path|
210
+ path = File.join(path, 'version.rb')
211
+ File.write(path, File.read(path).sub(/VERSION = '(.+?)'/, "VERSION = '#{source_version}'"))
212
+ end
210
213
 
211
214
  sh <<-SH
212
215
  git commit --allow-empty -a -m '#{source_version} release' &&
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.5
1
+ 2.1.0
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby -I ../lib -I lib
2
2
  # coding: utf-8
3
+ require_relative 'rainbows'
3
4
  require 'sinatra'
4
- set :server, 'thin'
5
+ set :server, :rainbows
5
6
  connections = []
6
7
 
7
8
  get '/' do
@@ -0,0 +1,3 @@
1
+ Rainbows! do
2
+ use :EventMachine
3
+ end
@@ -0,0 +1,20 @@
1
+ require 'rainbows'
2
+
3
+ module Rack
4
+ module Handler
5
+ class Rainbows
6
+ def self.run(app, **options)
7
+ rainbows_options = {
8
+ listeners: ["#{options[:Host]}:#{options[:Port]}"],
9
+ worker_processes: 1,
10
+ timeout: 30,
11
+ config_file: ::File.expand_path('rainbows.conf', __dir__),
12
+ }
13
+
14
+ ::Rainbows::HttpServer.new(app, rainbows_options).start.join
15
+ end
16
+ end
17
+
18
+ register :rainbows, ::Rack::Handler::Rainbows
19
+ end
20
+ end
@@ -2,10 +2,10 @@
2
2
  #
3
3
  # run *one* of these:
4
4
  #
5
- # rackup -s mongrel stream.ru # gem install mongrel
6
- # thin -R stream.ru start # gem install thin
7
- # unicorn stream.ru # gem install unicorn
8
- # puma stream.ru # gem install puma
5
+ # rackup -s mongrel stream.ru # gem install mongrel
6
+ # unicorn stream.ru # gem install unicorn
7
+ # puma stream.ru # gem install puma
8
+ # rainbows -c rainbows.conf stream.ru # gem install rainbows eventmachine
9
9
 
10
10
  require 'sinatra/base'
11
11
 
@@ -43,12 +43,11 @@ module Sinatra
43
43
  end
44
44
 
45
45
  def preferred_type(*types)
46
- accepts = accept # just evaluate once
47
- return accepts.first if types.empty?
46
+ return accept.first if types.empty?
48
47
  types.flatten!
49
- return types.first if accepts.empty?
50
- accepts.detect do |pattern|
51
- type = types.detect { |t| File.fnmatch(pattern, t) }
48
+ return types.first if accept.empty?
49
+ accept.detect do |accept_header|
50
+ type = types.detect { |t| MimeTypeEntry.new(t).accepts?(accept_header) }
52
51
  return type if type
53
52
  end
54
53
  end
@@ -81,8 +80,6 @@ module Sinatra
81
80
  raise BadRequest, "Invalid query parameters: #{Rack::Utils.escape_html(e.message)}"
82
81
  end
83
82
 
84
- private
85
-
86
83
  class AcceptEntry
87
84
  attr_accessor :params
88
85
  attr_reader :entry
@@ -125,6 +122,35 @@ module Sinatra
125
122
  to_str.send(*args, &block)
126
123
  end
127
124
  end
125
+
126
+ class MimeTypeEntry
127
+ attr_reader :params
128
+
129
+ def initialize(entry)
130
+ params = entry.scan(HEADER_PARAM).map! do |s|
131
+ key, value = s.strip.split('=', 2)
132
+ value = value[1..-2].gsub(/\\(.)/, '\1') if value.start_with?('"')
133
+ [key, value]
134
+ end
135
+
136
+ @type = entry[/[^;]+/].delete(' ')
137
+ @params = Hash[params]
138
+ end
139
+
140
+ def accepts?(entry)
141
+ File.fnmatch(entry, self) && matches_params?(entry.params)
142
+ end
143
+
144
+ def to_str
145
+ @type
146
+ end
147
+
148
+ def matches_params?(params)
149
+ return true if @params.empty?
150
+
151
+ params.all? { |k,v| !@params.has_key?(k) || @params[k] == v }
152
+ end
153
+ end
128
154
  end
129
155
 
130
156
  # The response object. See Rack::Response and Rack::Response::Helpers for
@@ -133,10 +159,6 @@ module Sinatra
133
159
  # http://rubydoc.info/github/rack/rack/master/Rack/Response/Helpers
134
160
  class Response < Rack::Response
135
161
  DROP_BODY_RESPONSES = [204, 304]
136
- def initialize(*)
137
- super
138
- headers['Content-Type'] ||= 'text/html'
139
- end
140
162
 
141
163
  def body=(value)
142
164
  value = value.body while Rack::Response === value
@@ -163,7 +185,7 @@ module Sinatra
163
185
  if calculate_content_length?
164
186
  # if some other code has already set Content-Length, don't muck with it
165
187
  # currently, this would be the static file-handler
166
- headers["Content-Length"] = body.inject(0) { |l, p| l + p.bytesize }.to_s
188
+ headers["Content-Length"] = body.map(&:bytesize).reduce(0, :+).to_s
167
189
  end
168
190
 
169
191
  [status.to_i, headers, result]
@@ -184,7 +206,7 @@ module Sinatra
184
206
  end
185
207
  end
186
208
 
187
- # Some Rack handlers (Thin, Rainbows!) implement an extended body object protocol, however,
209
+ # Some Rack handlers (Rainbows!) implement an extended body object protocol, however,
188
210
  # some middleware (namely Rack::Lint) will break it by not mirroring the methods in question.
189
211
  # This middleware will detect an extended body object and will make sure it reaches the
190
212
  # handler directly. We do this here, so our middleware and middleware set up by the app will
@@ -451,7 +473,7 @@ module Sinatra
451
473
  #
452
474
  # The close parameter specifies whether Stream#close should be called
453
475
  # after the block has been executed. This is only relevant for evented
454
- # servers like Thin or Rainbows.
476
+ # servers like Rainbows.
455
477
  def stream(keep_open = false)
456
478
  scheduler = env['async.callback'] ? EventMachine : Stream
457
479
  current = @params.dup
@@ -647,8 +669,6 @@ module Sinatra
647
669
  end
648
670
  end
649
671
 
650
- private
651
-
652
672
  # Template rendering methods. Each method takes the name of a template
653
673
  # to render as a Symbol and returns a String with the rendered output,
654
674
  # as well as an optional hash with additional options.
@@ -722,6 +742,7 @@ module Sinatra
722
742
  end
723
743
 
724
744
  def markdown(template, options = {}, locals = {})
745
+ options[:exclude_outvar] = true
725
746
  render :markdown, template, options, locals
726
747
  end
727
748
 
@@ -786,15 +807,8 @@ module Sinatra
786
807
  def find_template(views, name, engine)
787
808
  yield ::File.join(views, "#{name}.#{@preferred_extension}")
788
809
 
789
- if Tilt.respond_to?(:mappings)
790
- Tilt.mappings.each do |ext, engines|
791
- next unless ext != @preferred_extension and engines.include? engine
792
- yield ::File.join(views, "#{name}.#{ext}")
793
- end
794
- else
795
- Tilt.default_mapping.extensions_for(engine).each do |ext|
796
- yield ::File.join(views, "#{name}.#{ext}") unless ext == @preferred_extension
797
- end
810
+ Tilt.default_mapping.extensions_for(engine).each do |ext|
811
+ yield ::File.join(views, "#{name}.#{ext}") unless ext == @preferred_extension
798
812
  end
799
813
  end
800
814
 
@@ -825,10 +839,11 @@ module Sinatra
825
839
  content_type = options.delete(:content_type) || content_type
826
840
  layout_engine = options.delete(:layout_engine) || engine
827
841
  scope = options.delete(:scope) || self
842
+ exclude_outvar = options.delete(:exclude_outvar)
828
843
  options.delete(:layout)
829
844
 
830
845
  # set some defaults
831
- options[:outvar] ||= '@_out_buf'
846
+ options[:outvar] ||= '@_out_buf' unless exclude_outvar
832
847
  options[:default_encoding] ||= settings.default_encoding
833
848
 
834
849
  # compile and render template
@@ -905,6 +920,7 @@ module Sinatra
905
920
  super()
906
921
  @app = app
907
922
  @template_cache = Tilt::Cache.new
923
+ @pinned_response = nil # whether a before! filter pinned the content-type
908
924
  yield self if block_given?
909
925
  end
910
926
 
@@ -920,15 +936,14 @@ module Sinatra
920
936
  @response = Response.new
921
937
  template_cache.clear if settings.reload_templates
922
938
 
923
- @response['Content-Type'] = nil
924
939
  invoke { dispatch! }
925
940
  invoke { error_block!(response.status) } unless @env['sinatra.error']
926
941
 
927
942
  unless @response['Content-Type']
928
- if Array === body and body[0].respond_to? :content_type
943
+ if Array === body && body[0].respond_to?(:content_type)
929
944
  content_type body[0].content_type
930
- else
931
- content_type :html
945
+ elsif default = settings.default_content_type
946
+ content_type default
932
947
  end
933
948
  end
934
949
 
@@ -978,15 +993,21 @@ module Sinatra
978
993
  private
979
994
 
980
995
  # Run filters defined on the class and all superclasses.
996
+ # Accepts an optional block to call after each filter is applied.
981
997
  def filter!(type, base = settings)
982
998
  filter! type, base.superclass if base.superclass.respond_to?(:filters)
983
- base.filters[type].each { |args| process_route(*args) }
999
+ base.filters[type].each do |args|
1000
+ result = process_route(*args)
1001
+ yield result if block_given?
1002
+ end
984
1003
  end
985
1004
 
986
1005
  # Run routes defined on the class and all superclasses.
987
1006
  def route!(base = settings, pass_block = nil)
988
1007
  if routes = base.routes[@request.request_method]
989
1008
  routes.each do |pattern, conditions, block|
1009
+ @response.delete_header('Content-Type') unless @pinned_response
1010
+
990
1011
  returned_pass_block = process_route(pattern, conditions) do |*args|
991
1012
  env['sinatra.route'] = "#{@request.request_method} #{pattern}"
992
1013
  route_eval { block[*args] }
@@ -1024,7 +1045,7 @@ module Sinatra
1024
1045
 
1025
1046
  params.delete("ignore") # TODO: better params handling, maybe turn it into "smart" object or detect changes
1026
1047
  force_encoding(params)
1027
- original, @params = @params, @params.merge(params) if params.any?
1048
+ @params = @params.merge(params) if params.any?
1028
1049
 
1029
1050
  regexp_exists = pattern.is_a?(Mustermann::Regular) || (pattern.respond_to?(:patterns) && pattern.patterns.any? {|subpattern| subpattern.is_a?(Mustermann::Regular)} )
1030
1051
  if regexp_exists
@@ -1043,7 +1064,8 @@ module Sinatra
1043
1064
  @env['sinatra.error.params'] = @params
1044
1065
  raise
1045
1066
  ensure
1046
- @params = original if original
1067
+ params ||= {}
1068
+ params.each { |k, _| @params.delete(k) } unless @env['sinatra.error.params']
1047
1069
  end
1048
1070
 
1049
1071
  # No matching route was found or all routes passed. The default
@@ -1055,7 +1077,7 @@ module Sinatra
1055
1077
  if @app
1056
1078
  forward
1057
1079
  else
1058
- raise NotFound
1080
+ raise NotFound, "#{request.request_method} #{request.path_info}"
1059
1081
  end
1060
1082
  end
1061
1083
 
@@ -1063,7 +1085,10 @@ module Sinatra
1063
1085
  # a matching file is found, returns nil otherwise.
1064
1086
  def static!(options = {})
1065
1087
  return if (public_dir = settings.public_folder).nil?
1066
- path = File.expand_path("#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}" )
1088
+ path = "#{public_dir}#{URI_INSTANCE.unescape(request.path_info)}"
1089
+ return unless valid_path?(path)
1090
+
1091
+ path = File.expand_path(path)
1067
1092
  return unless File.file?(path)
1068
1093
 
1069
1094
  env['sinatra.static_file'] = path
@@ -1089,11 +1114,18 @@ module Sinatra
1089
1114
 
1090
1115
  # Dispatch a request with error handling.
1091
1116
  def dispatch!
1092
- @params.merge!(@request.params).each { |key, val| @params[key] = force_encoding(val.dup) }
1117
+ # Avoid passing frozen string in force_encoding
1118
+ @params.merge!(@request.params).each do |key, val|
1119
+ next unless val.respond_to?(:force_encoding)
1120
+ val = val.dup if val.frozen?
1121
+ @params[key] = force_encoding(val)
1122
+ end
1093
1123
 
1094
1124
  invoke do
1095
1125
  static! if settings.static? && (request.get? || request.head?)
1096
- filter! :before
1126
+ filter! :before do
1127
+ @pinned_response = !@response['Content-Type'].nil?
1128
+ end
1097
1129
  route!
1098
1130
  end
1099
1131
  rescue ::Exception => boom
@@ -1123,19 +1155,27 @@ module Sinatra
1123
1155
 
1124
1156
  status(500) unless status.between? 400, 599
1125
1157
 
1126
- boom_message = boom.message if boom.message && boom.message != boom.class.name
1127
1158
  if server_error?
1128
1159
  dump_errors! boom if settings.dump_errors?
1129
1160
  raise boom if settings.show_exceptions? and settings.show_exceptions != :after_handler
1130
1161
  elsif not_found?
1131
1162
  headers['X-Cascade'] = 'pass' if settings.x_cascade?
1132
- body boom_message || '<h1>Not Found</h1>'
1133
- elsif bad_request?
1134
- body boom_message || '<h1>Bad Request</h1>'
1135
1163
  end
1136
1164
 
1137
- res = error_block!(boom.class, boom) || error_block!(status, boom)
1138
- return res if res or not server_error?
1165
+ if res = error_block!(boom.class, boom) || error_block!(status, boom)
1166
+ return res
1167
+ end
1168
+
1169
+ if not_found? || bad_request?
1170
+ if boom.message && boom.message != boom.class.name
1171
+ body boom.message
1172
+ else
1173
+ content_type 'text/html'
1174
+ body '<h1>' + (not_found? ? 'Not Found' : 'Bad Request') + '</h1>'
1175
+ end
1176
+ end
1177
+
1178
+ return unless server_error?
1139
1179
  raise boom if settings.raise_errors? or settings.show_exceptions?
1140
1180
  error_block! Exception, boom
1141
1181
  end
@@ -1168,7 +1208,7 @@ module Sinatra
1168
1208
  /^\(.*\)$/, # generated code
1169
1209
  /rubygems\/(custom|core_ext\/kernel)_require\.rb$/, # rubygems require hacks
1170
1210
  /active_support/, # active_support require hacks
1171
- /bundler(\/runtime)?\.rb/, # bundler require hacks
1211
+ /bundler(\/(?:runtime|inline))?\.rb/, # bundler require hacks
1172
1212
  /<internal:/, # internal in ruby >= 1.9.2
1173
1213
  /src\/kernel\/bootstrap\/[A-Z]/ # maglev kernel files
1174
1214
  ]
@@ -1345,19 +1385,19 @@ module Sinatra
1345
1385
  # context as route handlers and may access/modify the request and
1346
1386
  # response.
1347
1387
  def before(path = /.*/, **options, &block)
1348
- add_filter(:before, path, options, &block)
1388
+ add_filter(:before, path, **options, &block)
1349
1389
  end
1350
1390
 
1351
1391
  # Define an after filter; runs after all requests within the same
1352
1392
  # context as route handlers and may access/modify the request and
1353
1393
  # response.
1354
1394
  def after(path = /.*/, **options, &block)
1355
- add_filter(:after, path, options, &block)
1395
+ add_filter(:after, path, **options, &block)
1356
1396
  end
1357
1397
 
1358
1398
  # add a filter
1359
1399
  def add_filter(type, path = /.*/, **options, &block)
1360
- filters[type] << compile!(type, path, block, options)
1400
+ filters[type] << compile!(type, path, block, **options)
1361
1401
  end
1362
1402
 
1363
1403
  # Add a route condition. The route is considered non-matching when the
@@ -1402,7 +1442,7 @@ module Sinatra
1402
1442
  # in `extensions` available to the handlers and templates
1403
1443
  def helpers(*extensions, &block)
1404
1444
  class_eval(&block) if block_given?
1405
- include(*extensions) if extensions.any?
1445
+ prepend(*extensions) if extensions.any?
1406
1446
  end
1407
1447
 
1408
1448
  # Register an extension. Alternatively take a block from which an
@@ -1445,7 +1485,7 @@ module Sinatra
1445
1485
  alias_method :stop!, :quit!
1446
1486
 
1447
1487
  # Run the Sinatra app as a self-hosted server using
1448
- # Thin, Puma, Mongrel, or WEBrick (in that order). If given a block, will call
1488
+ # Puma, Mongrel, or WEBrick (in that order). If given a block, will call
1449
1489
  # with the constructed handler once we have taken the stage.
1450
1490
  def run!(options = {}, &block)
1451
1491
  return if running?
@@ -1522,7 +1562,7 @@ module Sinatra
1522
1562
  # behavior, by ensuring an instance exists:
1523
1563
  prototype
1524
1564
  # Run the instance we created:
1525
- handler.run(self, server_settings) do |server|
1565
+ handler.run(self, **server_settings) do |server|
1526
1566
  unless suppress_messages?
1527
1567
  $stderr.puts "== Sinatra (v#{Sinatra::VERSION}) has taken the stage on #{port} for #{environment} with backup from #{handler_name}"
1528
1568
  end
@@ -1601,7 +1641,7 @@ module Sinatra
1601
1641
 
1602
1642
  def route(verb, path, options = {}, &block)
1603
1643
  enable :empty_path_info if path == "" and empty_path_info.nil?
1604
- signature = compile!(verb, path, block, options)
1644
+ signature = compile!(verb, path, block, **options)
1605
1645
  (@routes[verb] ||= []) << signature
1606
1646
  invoke_hook(:route_added, verb, path, block)
1607
1647
  signature
@@ -1638,7 +1678,7 @@ module Sinatra
1638
1678
  end
1639
1679
 
1640
1680
  def compile(path, route_mustermann_opts = {})
1641
- Mustermann.new(path, mustermann_opts.merge(route_mustermann_opts))
1681
+ Mustermann.new(path, **mustermann_opts.merge(route_mustermann_opts))
1642
1682
  end
1643
1683
 
1644
1684
  def setup_default_middleware(builder)
@@ -1743,29 +1783,22 @@ module Sinatra
1743
1783
  end
1744
1784
  end
1745
1785
 
1746
- # Fixes encoding issues by
1747
- # * defaulting to UTF-8
1748
- # * casting params to Encoding.default_external
1749
- #
1750
- # The latter might not be necessary if Rack handles it one day.
1751
- # Keep an eye on Rack's LH #100.
1752
- def force_encoding(*args) settings.force_encoding(*args) end
1753
- if defined? Encoding
1754
- def self.force_encoding(data, encoding = default_encoding)
1755
- return if data == settings || data.is_a?(Tempfile)
1756
- if data.respond_to? :force_encoding
1757
- data.force_encoding(encoding).encode!
1758
- elsif data.respond_to? :each_value
1759
- data.each_value { |v| force_encoding(v, encoding) }
1760
- elsif data.respond_to? :each
1761
- data.each { |v| force_encoding(v, encoding) }
1762
- end
1763
- data
1786
+ # Force data to specified encoding. It defaults to settings.default_encoding
1787
+ # which is UTF-8 by default
1788
+ def self.force_encoding(data, encoding = default_encoding)
1789
+ return if data == settings || data.is_a?(Tempfile)
1790
+ if data.respond_to? :force_encoding
1791
+ data.force_encoding(encoding).encode!
1792
+ elsif data.respond_to? :each_value
1793
+ data.each_value { |v| force_encoding(v, encoding) }
1794
+ elsif data.respond_to? :each
1795
+ data.each { |v| force_encoding(v, encoding) }
1764
1796
  end
1765
- else
1766
- def self.force_encoding(data, *) data end
1797
+ data
1767
1798
  end
1768
1799
 
1800
+ def force_encoding(*args) settings.force_encoding(*args) end
1801
+
1769
1802
  reset!
1770
1803
 
1771
1804
  set :environment, (ENV['APP_ENV'] || ENV['RACK_ENV'] || :development).to_sym
@@ -1783,6 +1816,7 @@ module Sinatra
1783
1816
  set :add_charset, %w[javascript xml xhtml+xml].map { |t| "application/#{t}" }
1784
1817
  settings.add_charset << /^text\//
1785
1818
  set :mustermann_opts, {}
1819
+ set :default_content_type, 'text/html'
1786
1820
 
1787
1821
  # explicitly generating a session secret eagerly to play nice with preforking
1788
1822
  begin
@@ -1843,7 +1877,7 @@ module Sinatra
1843
1877
 
1844
1878
  configure :development do
1845
1879
  get '/__sinatra__/:image.png' do
1846
- filename = File.dirname(__FILE__) + "/images/#{params[:image].to_i}.png"
1880
+ filename = __dir__ + "/images/#{params[:image].to_i}.png"
1847
1881
  content_type :png
1848
1882
  send_file filename
1849
1883
  end