sinatra 3.2.0 → 4.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6eddf8c0c677b8b8b7f15bb03834147034ead41bc6310bf773ac84712bb43a14
4
- data.tar.gz: c35de3457f199d57a3c8a4419bd0ad113df38ba071cfffbcc79311db910bc1cb
3
+ metadata.gz: 491154a9e29e4c218d9245fd73024818e7dfa6c75ba1d74220e46498841bb54e
4
+ data.tar.gz: 42259b9becde7268d9b95abc783d896c864a6c84b3e1dd6d40d7f351a350f626
5
5
  SHA512:
6
- metadata.gz: 33e0785425af5a32c7e09d95e2d11e02d83cdda1d907b34197c63642bfec81cd04a40ffc2e25486fe45af66d9a681f57c41d083d7bc56f24b69f1cf4b3a478f6
7
- data.tar.gz: 6aa65f3b65c819171bcadb61a3a43c3ff7af748d29a9177dbd02549229e3b9fa64b338d0404383b97615e74aa5381dd8a4c997edbf86ca0e8a2970e0213b2ece
6
+ metadata.gz: 43a69c7f07afab191eacc80d7837d9bdbd81701a51973309395b47e9efacb010234a0a66e27503b6edc213f5f8321e426f2f8ad9f7cc7e247e908613d14081c6
7
+ data.tar.gz: f2fb4deeb5f8e44a5a6a59663080f143c2a1dac1d21a5ca8301728b265a8ba2fcf3e0815c692af0791230289d4ddaf548a317e2f4295cf24b45e5cdec47dc86e
data/CHANGELOG.md CHANGED
@@ -1,6 +1,47 @@
1
- ## Unreleased
1
+ ## 4.1.1 / 2024-11-20
2
2
 
3
- * _Your new feature here._
3
+ * Fix: Restore WEBrick support ([#2067](https://github.com/sinatra/sinatra/pull/2067))
4
+
5
+ ## 4.1.0 / 2024-11-18
6
+
7
+ * New: Add `host_authorization` setting ([#2053](https://github.com/sinatra/sinatra/pull/2053))
8
+ * Defaults to `.localhost`, `.test` and any IP address in development mode.
9
+ * Security: addresses [CVE-2024-21510](https://github.com/advisories/GHSA-hxx2-7vcw-mqr3).
10
+ * Fix: Return an instance of `Sinatra::IndifferentHash` when calling `#except` ([#2044](https://github.com/sinatra/sinatra/pull/2044))
11
+ * Fix: Address warning from `URI` for Ruby 3.4 ([#2060](https://github.com/sinatra/sinatra/pull/2060))
12
+ * Fix: `rackup` no longer depends on WEBrick, recommend Puma instead ([`4a558503`](https://github.com/sinatra/sinatra/commit/4a558503a0ee41f26d4ebc07b478340e8a8a5ed6))
13
+ * Fix: Zeitwerk 2.7.0+ compatibility ([#2050](https://github.com/sinatra/sinatra/pull/2050))
14
+ * Fix: Address warning about Hash construction for Ruby 3.4 ([#2028](https://github.com/sinatra/sinatra/pull/2028))
15
+ * Fix: Declare missing dependencies for Ruby 3.5 ([#2032](https://github.com/sinatra/sinatra/pull/2032))
16
+ * Fix: Compatibility with `--enable-frozen-string-literal` ([#2033](https://github.com/sinatra/sinatra/pull/2033))
17
+ * Fix: Rack 3.1 compatibility ([#2035](https://github.com/sinatra/sinatra/pull/2035))
18
+ * Don't depend on `Rack::Logger`
19
+ * Don't delete `content-length` header when `Rack::Files` is used
20
+
21
+ ## 4.0.0. / 2024-01-19
22
+
23
+ * New: Add support for Rack 3 ([#1857])
24
+ * Note: you may want to read the [Rack 3 Upgrade Guide]
25
+
26
+ * Require Ruby 2.7.8 as minimum Ruby version ([#1993])
27
+
28
+ * Breaking change: Drop support for Rack 2 ([#1857])
29
+ * Note: when using Sinatra to start the web server, you now need the `rackup` gem installed
30
+
31
+ * Breaking change: Remove the `IndifferentHash` initializer ([#1982])
32
+
33
+ * Breaking change: Disable `session_hijacking` protection by default ([#1984])
34
+
35
+ * Breaking change: Remove `Rack::Protection::EncryptedCookie` ([#1989])
36
+ * Note: cookies are still encrypted (by [`Rack::Session::Cookie`])
37
+
38
+ [#1857]: https://github.com/sinatra/sinatra/pull/1857
39
+ [#1993]: https://github.com/sinatra/sinatra/pull/1993
40
+ [#1982]: https://github.com/sinatra/sinatra/pull/1982
41
+ [#1984]: https://github.com/sinatra/sinatra/pull/1984
42
+ [#1989]: https://github.com/sinatra/sinatra/pull/1989
43
+ [`Rack::Session::Cookie`]: https://github.com/rack/rack-session
44
+ [Rack 3 Upgrade Guide]: https://github.com/rack/rack/blob/main/UPGRADE-GUIDE.md
4
45
 
5
46
  ## 3.2.0 / 2023-12-29
6
47
 
@@ -23,7 +64,7 @@
23
64
  [#1949]: https://github.com/sinatra/sinatra/pull/1949
24
65
  [#1952]: https://github.com/sinatra/sinatra/pull/1952
25
66
  [#1960]: https://github.com/sinatra/sinatra/pull/1960
26
- [#1975]: https://github.com/sinatra/sinatra/pull/1960
67
+ [#1975]: https://github.com/sinatra/sinatra/pull/1975
27
68
 
28
69
  ## 3.1.0 / 2023-08-07
29
70
 
@@ -222,7 +263,7 @@
222
263
 
223
264
  * Fix issue with passed routes and provides Fixes [#1095](https://github.com/sinatra/sinatra/pull/1095) [#1606](https://github.com/sinatra/sinatra/pull/1606) by Mike Pastore, Jordan Owens
224
265
 
225
- * Add QuietLogger that excludes pathes from Rack::CommonLogger [1250](https://github.com/sinatra/sinatra/pull/1250) by Christoph Wagner
266
+ * Add QuietLogger that excludes paths from Rack::CommonLogger [1250](https://github.com/sinatra/sinatra/pull/1250) by Christoph Wagner
226
267
 
227
268
  * Sinatra::Contrib dependency updates. Fixes [#1207](https://github.com/sinatra/sinatra/pull/1207) [#1411](https://github.com/sinatra/sinatra/pull/1411) by Mike Pastore
228
269
 
@@ -1588,7 +1629,7 @@ the 1.0 release:
1588
1629
  Hash structure. e.g., "post[title]=Hello&post[body]=World" yields
1589
1630
  params: {'post' => {'title' => 'Hello', 'body' => 'World'}}.
1590
1631
 
1591
- * Regular expressions may now be used in route pattens; captures are
1632
+ * Regular expressions may now be used in route patterns; captures are
1592
1633
  available at "params[:captures]".
1593
1634
 
1594
1635
  * New ":provides" route condition takes an array of mime types and
data/Gemfile CHANGED
@@ -1,13 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Why use bundler?
4
- # Well, not all development dependencies install on all rubies. Moreover, `gem
5
- # install sinatra --development` doesn't work, as it will also try to install
6
- # development dependencies of our dependencies, and those are not conflict free.
7
- # So, here we are, `bundle install`.
8
- #
9
- # If you have issues with a gem: `bundle install --without-coffee-script`.
10
-
11
3
  source 'https://rubygems.org'
12
4
  gemspec
13
5
 
@@ -18,11 +10,22 @@ rack_version = nil if rack_version.empty? || (rack_version == 'stable')
18
10
  rack_version = { github: 'rack/rack' } if rack_version == 'head'
19
11
  gem 'rack', rack_version
20
12
 
13
+ rack_session_version = ENV['rack_session'].to_s
14
+ rack_session_version = nil if rack_session_version.empty? || (rack_session_version == 'stable')
15
+ rack_session_version = { github: 'rack/rack-session' } if rack_session_version == 'head'
16
+ gem 'rack-session', rack_session_version
17
+
18
+ gem 'rackup'
19
+
21
20
  puma_version = ENV['puma'].to_s
22
21
  puma_version = nil if puma_version.empty? || (puma_version == 'stable')
23
22
  puma_version = { github: 'puma/puma' } if puma_version == 'head'
24
23
  gem 'puma', puma_version
25
24
 
25
+ zeitwerk_version = ENV['zeitwerk'].to_s
26
+ zeitwerk_version = nil if zeitwerk_version.empty? || (zeitwerk_version == 'stable')
27
+ gem 'zeitwerk', zeitwerk_version
28
+
26
29
  gem 'minitest', '~> 5.0'
27
30
  gem 'rack-test'
28
31
  gem 'rubocop', '~> 1.32.0', require: false
@@ -31,15 +34,9 @@ gem 'yard' # used by rake doc
31
34
  gem 'rack-protection', path: 'rack-protection'
32
35
  gem 'sinatra-contrib', path: 'sinatra-contrib'
33
36
 
34
- # traces 0.10.0 started to use Ruby 2.7 syntax without specifying required Ruby version
35
- # https://github.com/socketry/traces/pull/8#discussion_r1237988182
36
- # async-http 0.60.2 added traces 0.10.0 as dependency
37
- # https://github.com/socketry/async-http/pull/124/files#r1237988899
38
- gem 'traces', '< 0.10.0' if RUBY_VERSION >= '2.6.0' && RUBY_VERSION < '2.7.0'
39
-
40
37
  gem 'asciidoctor'
41
38
  gem 'builder'
42
- gem 'childprocess'
39
+ gem 'childprocess', '>= 5'
43
40
  gem 'commonmarker', '~> 0.23.4', platforms: [:ruby]
44
41
  gem 'erubi'
45
42
  gem 'eventmachine'
@@ -47,25 +44,23 @@ gem 'falcon', '~> 0.40', platforms: [:ruby]
47
44
  gem 'haml', '~> 6'
48
45
  gem 'kramdown'
49
46
  gem 'liquid'
50
- # markaby 0.9.1 introduced Ruby 2.7 syntax in https://github.com/markaby/markaby/pull/44
51
- # and does not specify required_ruby_version
52
- if RUBY_VERSION >= '2.6.0' && RUBY_VERSION < '2.7.0'
53
- gem 'markaby', '< 0.9.1'
54
- else
55
- gem 'markaby'
56
- end
47
+ gem 'markaby'
57
48
  gem 'nokogiri', '> 1.5.0'
49
+ gem 'ostruct'
58
50
  gem 'pandoc-ruby', '~> 2.0.2'
59
51
  gem 'rabl'
60
- if RUBY_ENGINE == 'truffleruby'
61
- gem 'rdiscount', '< 2.2.7.2' # https://github.com/oracle/truffleruby/issues/3362
62
- else
63
- gem 'rdiscount', platforms: [:ruby]
64
- end
52
+ gem 'rdiscount', platforms: [:ruby]
65
53
  gem 'rdoc'
66
54
  gem 'redcarpet', platforms: [:ruby]
67
- gem 'sass-embedded', '~> 1.54'
68
55
  gem 'simplecov', require: false
69
- gem 'slim', '~> 4'
56
+ gem 'slim', '~> 5'
70
57
  gem 'yajl-ruby', platforms: [:ruby]
71
- gem 'zeitwerk'
58
+ gem 'webrick'
59
+
60
+ # sass-embedded depends on google-protobuf
61
+ # which fails to be installed on JRuby and TruffleRuby under aarch64
62
+ # https://github.com/jruby/jruby/issues/8062
63
+ # https://github.com/protocolbuffers/protobuf/issues/11935
64
+ java = %w(jruby truffleruby).include?(RUBY_ENGINE)
65
+ aarch64 = RbConfig::CONFIG["target_cpu"] == 'aarch64'
66
+ gem 'sass-embedded', '~> 1.54' unless java && aarch64
data/README.md CHANGED
@@ -15,11 +15,10 @@ get '/' do
15
15
  end
16
16
  ```
17
17
 
18
- Install the gem:
18
+ Install the gems needed:
19
19
 
20
20
  ```shell
21
- gem install sinatra
22
- gem install puma # or any other server
21
+ gem install sinatra rackup puma
23
22
  ```
24
23
 
25
24
  And run with:
@@ -1922,7 +1921,7 @@ set :protection, :except => :path_traversal
1922
1921
  You can also hand in an array in order to disable a list of protections:
1923
1922
 
1924
1923
  ```ruby
1925
- set :protection, :except => [:path_traversal, :session_hijacking]
1924
+ set :protection, :except => [:path_traversal, :remote_token]
1926
1925
  ```
1927
1926
 
1928
1927
  By default, Sinatra will only set up session based protection if `:sessions`
@@ -1993,6 +1992,33 @@ set :protection, :session => true
1993
1992
  <tt>"development"</tt> if not available.
1994
1993
  </dd>
1995
1994
 
1995
+ <dt>host_authorization</dt>
1996
+ <dd>
1997
+ <p>
1998
+ You can pass a hash of options to <tt>host_authorization</tt>,
1999
+ to be used by the <tt>Rack::Protection::HostAuthorization</tt> middleware.
2000
+ </p>
2001
+ <p>
2002
+ The middleware can block requests with unrecognized hostnames, to prevent DNS rebinding
2003
+ and other host header attacks. It checks the <tt>Host</tt>, <tt>X-Forwarded-Host</tt>
2004
+ and <tt>Forwarded</tt> headers.
2005
+ </p>
2006
+ <p>
2007
+ Useful options are:
2008
+ <ul>
2009
+ <li><tt>permitted_hosts</tt> – an array of hostnames (and <tt>IPAddr</tt> objects) your app recognizes
2010
+ <ul>
2011
+ <li>in the <tt>development</tt> environment, it is set to <tt>.localhost</tt>, <tt>.test</tt> and any IPv4/IPv6 address</li>
2012
+ <li>if empty, any hostname is permitted (the default for any other environment)</li>
2013
+ </ul>
2014
+ </li>
2015
+ <li><tt>status</tt> – the HTTP status code used in the response when a request is blocked (defaults to <tt>403</tt>)</li>
2016
+ <li><tt>message</tt> – the body used in the response when a request is blocked (defaults to <tt>Host not permitted</tt>)</li>
2017
+ <li><tt>allow_if</tt> – supply a <tt>Proc</tt> to use custom allow/deny logic, the proc is passed the request environment</li>
2018
+ </ul>
2019
+ </p>
2020
+ </dd>
2021
+
1996
2022
  <dt>logging</dt>
1997
2023
  <dd>Use the logger.</dd>
1998
2024
 
@@ -2086,12 +2112,8 @@ set :protection, :session => true
2086
2112
 
2087
2113
  <dt>server_settings</dt>
2088
2114
  <dd>
2089
- If you are using a WEBrick web server, presumably for your development
2090
- environment, you can pass a hash of options to <tt>server_settings</tt>,
2091
- such as <tt>SSLEnable</tt> or <tt>SSLVerifyClient</tt>. However, web
2092
- servers such as Puma do not support this, so you can set
2093
- <tt>server_settings</tt> by defining it as a method when you call
2094
- <tt>configure</tt>.
2115
+ You can pass a hash of options to <tt>server_settings</tt>,
2116
+ such as <tt>Host</tt> or <tt>Port</tt>.
2095
2117
  </dd>
2096
2118
 
2097
2119
  <dt>sessions</dt>
@@ -2812,7 +2834,7 @@ _Paraphrasing from
2812
2834
  by Konstantin_
2813
2835
 
2814
2836
  Sinatra doesn't impose any concurrency model but leaves that to the
2815
- underlying Rack handler (server) like Puma or WEBrick. Sinatra
2837
+ underlying Rack handler (server) like Puma or Falcon. Sinatra
2816
2838
  itself is thread-safe, so there won't be any problem if the Rack handler
2817
2839
  uses a threaded model of concurrency.
2818
2840
 
@@ -2820,30 +2842,24 @@ uses a threaded model of concurrency.
2820
2842
 
2821
2843
  The following Ruby versions are officially supported:
2822
2844
  <dl>
2823
- <dt>Ruby 2.6</dt>
2845
+ <dt>Ruby</dt>
2824
2846
  <dd>
2825
- 2.6 is fully supported and recommended. There are currently no plans to
2826
- drop official support for it.
2847
+ <a href="https://www.ruby-lang.org/en/downloads/">The stable releases</a> are fully supported and recommended.
2827
2848
  </dd>
2828
2849
 
2829
- <dt>Rubinius</dt>
2850
+ <dt>TruffleRuby</dt>
2830
2851
  <dd>
2831
- Rubinius is officially supported (Rubinius >= 2.x). It is recommended to
2832
- <tt>gem install puma</tt>.
2852
+ The latest stable release of TruffleRuby is supported.
2833
2853
  </dd>
2834
2854
 
2835
2855
  <dt>JRuby</dt>
2836
2856
  <dd>
2837
- The latest stable release of JRuby is officially supported. It is not
2838
- recommended to use C extensions with JRuby. It is recommended to
2839
- <tt>gem install trinidad</tt>.
2857
+ The latest stable release of JRuby is supported. It is not
2858
+ recommended to use C extensions with JRuby.
2840
2859
  </dd>
2841
2860
  </dl>
2842
2861
 
2843
- Versions of Ruby before 2.6 are no longer supported as of Sinatra 3.0.0.
2844
-
2845
- We also keep an eye on upcoming Ruby versions. Expect upcoming
2846
- 3.x releases to be fully supported.
2862
+ Versions of Ruby before 2.7.8 are no longer supported as of Sinatra 4.0.0.
2847
2863
 
2848
2864
  Sinatra should work on any operating system supported by the chosen Ruby
2849
2865
  implementation.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0
1
+ 4.1.1
data/lib/sinatra/base.rb CHANGED
@@ -2,13 +2,19 @@
2
2
 
3
3
  # external dependencies
4
4
  require 'rack'
5
+ begin
6
+ require 'rackup'
7
+ rescue LoadError
8
+ end
5
9
  require 'tilt'
6
10
  require 'rack/protection'
11
+ require 'rack/session'
7
12
  require 'mustermann'
8
13
  require 'mustermann/sinatra'
9
14
  require 'mustermann/regular'
10
15
 
11
16
  # stdlib dependencies
17
+ require 'ipaddr'
12
18
  require 'time'
13
19
  require 'uri'
14
20
 
@@ -17,6 +23,8 @@ require 'sinatra/indifferent_hash'
17
23
  require 'sinatra/show_exceptions'
18
24
  require 'sinatra/version'
19
25
 
26
+ require_relative 'middleware/logger'
27
+
20
28
  module Sinatra
21
29
  # The request object. See Rack::Request for more info:
22
30
  # https://rubydoc.info/github/rack/rack/main/Rack/Request
@@ -56,7 +64,7 @@ module Sinatra
56
64
  alias secure? ssl?
57
65
 
58
66
  def forwarded?
59
- @env.include? 'HTTP_X_FORWARDED_HOST'
67
+ !forwarded_authority.nil?
60
68
  end
61
69
 
62
70
  def safe?
@@ -176,8 +184,8 @@ module Sinatra
176
184
  result = body
177
185
 
178
186
  if drop_content_info?
179
- headers.delete 'Content-Length'
180
- headers.delete 'Content-Type'
187
+ headers.delete 'content-length'
188
+ headers.delete 'content-type'
181
189
  end
182
190
 
183
191
  if drop_body?
@@ -186,9 +194,9 @@ module Sinatra
186
194
  end
187
195
 
188
196
  if calculate_content_length?
189
- # if some other code has already set Content-Length, don't muck with it
197
+ # if some other code has already set content-length, don't muck with it
190
198
  # currently, this would be the static file-handler
191
- headers['Content-Length'] = body.map(&:bytesize).reduce(0, :+).to_s
199
+ headers['content-length'] = body.map(&:bytesize).reduce(0, :+).to_s
192
200
  end
193
201
 
194
202
  [status, headers, result]
@@ -197,7 +205,7 @@ module Sinatra
197
205
  private
198
206
 
199
207
  def calculate_content_length?
200
- headers['Content-Type'] && !headers['Content-Length'] && (Array === body)
208
+ headers['content-type'] && !headers['content-length'] && (Array === body)
201
209
  end
202
210
 
203
211
  def drop_content_info?
@@ -289,10 +297,8 @@ module Sinatra
289
297
  def block.each; yield(call) end
290
298
  response.body = block
291
299
  elsif value
292
- # Rack 2.0 returns a Rack::File::Iterator here instead of
293
- # Rack::File as it was in the previous API.
294
- unless request.head? || value.is_a?(Rack::Files::Iterator) || value.is_a?(Stream)
295
- headers.delete 'Content-Length'
300
+ unless request.head? || value.is_a?(Rack::Files::BaseIterator) || value.is_a?(Stream)
301
+ headers.delete 'content-length'
296
302
  end
297
303
  response.body = value
298
304
  else
@@ -302,7 +308,10 @@ module Sinatra
302
308
 
303
309
  # Halt processing and redirect to the URI provided.
304
310
  def redirect(uri, *args)
305
- if (env['HTTP_VERSION'] == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET')
311
+ # SERVER_PROTOCOL is required in Rack 3, fall back to HTTP_VERSION
312
+ # for servers not updated for Rack 3 (like Puma 5)
313
+ http_version = env['SERVER_PROTOCOL'] || env['HTTP_VERSION']
314
+ if (http_version == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET')
306
315
  status 303
307
316
  else
308
317
  status 302
@@ -372,10 +381,10 @@ module Sinatra
372
381
  Base.mime_type(type)
373
382
  end
374
383
 
375
- # Set the Content-Type of the response body given a media type or file
384
+ # Set the content-type of the response body given a media type or file
376
385
  # extension.
377
386
  def content_type(type = nil, params = {})
378
- return response['Content-Type'] unless type
387
+ return response['content-type'] unless type
379
388
 
380
389
  default = params.delete :default
381
390
  mime_type = mime_type(type) || default
@@ -393,7 +402,7 @@ module Sinatra
393
402
  "#{key}=#{val}"
394
403
  end.join(', ')
395
404
  end
396
- response['Content-Type'] = mime_type
405
+ response['content-type'] = mime_type
397
406
  end
398
407
 
399
408
  # https://html.spec.whatwg.org/#multipart-form-data
@@ -412,12 +421,12 @@ module Sinatra
412
421
  params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE))
413
422
  response['Content-Disposition'] << params
414
423
  ext = File.extname(filename)
415
- content_type(ext) unless response['Content-Type'] || ext.empty?
424
+ content_type(ext) unless response['content-type'] || ext.empty?
416
425
  end
417
426
 
418
427
  # Use the contents of the file at +path+ as the response body.
419
428
  def send_file(path, opts = {})
420
- if opts[:type] || !response['Content-Type']
429
+ if opts[:type] || !response['content-type']
421
430
  content_type opts[:type] || File.extname(path), default: 'application/octet-stream'
422
431
  end
423
432
 
@@ -433,7 +442,7 @@ module Sinatra
433
442
  result = file.serving(request, path)
434
443
 
435
444
  result[1].each { |k, v| headers[k] ||= v }
436
- headers['Content-Length'] = result[1]['Content-Length']
445
+ headers['content-length'] = result[1]['content-length']
437
446
  opts[:status] &&= Integer(opts[:status])
438
447
  halt (opts[:status] || result[0]), result[2]
439
448
  rescue Errno::ENOENT
@@ -966,7 +975,7 @@ module Sinatra
966
975
  include Helpers
967
976
  include Templates
968
977
 
969
- URI_INSTANCE = URI::Parser.new
978
+ URI_INSTANCE = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::RFC2396_Parser.new
970
979
 
971
980
  attr_accessor :app, :env, :request, :response, :params
972
981
  attr_reader :template_cache
@@ -995,7 +1004,7 @@ module Sinatra
995
1004
  invoke { dispatch! }
996
1005
  invoke { error_block!(response.status) } unless @env['sinatra.error']
997
1006
 
998
- unless @response['Content-Type']
1007
+ unless @response['content-type']
999
1008
  if Array === body && body[0].respond_to?(:content_type)
1000
1009
  content_type body[0].content_type
1001
1010
  elsif (default = settings.default_content_type)
@@ -1058,7 +1067,7 @@ module Sinatra
1058
1067
  routes = base.routes[@request.request_method]
1059
1068
 
1060
1069
  routes&.each do |pattern, conditions, block|
1061
- response.delete_header('Content-Type') unless @pinned_response
1070
+ response.delete_header('content-type') unless @pinned_response
1062
1071
 
1063
1072
  returned_pass_block = process_route(pattern, conditions) do |*args|
1064
1073
  env['sinatra.route'] = "#{@request.request_method} #{pattern}"
@@ -1179,7 +1188,7 @@ module Sinatra
1179
1188
  invoke do
1180
1189
  static! if settings.static? && (request.get? || request.head?)
1181
1190
  filter! :before do
1182
- @pinned_response = !response['Content-Type'].nil?
1191
+ @pinned_response = !response['content-type'].nil?
1183
1192
  end
1184
1193
  route!
1185
1194
  end
@@ -1286,7 +1295,7 @@ module Sinatra
1286
1295
  /active_support/, # active_support require hacks
1287
1296
  %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
1288
1297
  /<internal:/, # internal in ruby >= 1.9.2
1289
- %r{zeitwerk/kernel\.rb} # Zeitwerk kernel#require decorator
1298
+ %r{zeitwerk/(core_ext/)?kernel\.rb} # Zeitwerk kernel#require decorator
1290
1299
  ].freeze
1291
1300
 
1292
1301
  attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
@@ -1460,7 +1469,13 @@ module Sinatra
1460
1469
  # mime_types :js # => ['application/javascript', 'text/javascript']
1461
1470
  def mime_types(type)
1462
1471
  type = mime_type type
1463
- type =~ %r{^application/(xml|javascript)$} ? [type, "text/#{$1}"] : [type]
1472
+ if type =~ %r{^application/(xml|javascript)$}
1473
+ [type, "text/#{$1}"]
1474
+ elsif type =~ %r{^text/(xml|javascript)$}
1475
+ [type, "application/#{$1}"]
1476
+ else
1477
+ [type]
1478
+ end
1464
1479
  end
1465
1480
 
1466
1481
  # Define a before filter; runs before all requests within the same
@@ -1586,13 +1601,30 @@ module Sinatra
1586
1601
  alias stop! quit!
1587
1602
 
1588
1603
  # Run the Sinatra app as a self-hosted server using
1589
- # Puma, Falcon, or WEBrick (in that order). If given a block, will call
1604
+ # Puma, Falcon (in that order). If given a block, will call
1590
1605
  # with the constructed handler once we have taken the stage.
1591
1606
  def run!(options = {}, &block)
1607
+ unless defined?(Rackup::Handler)
1608
+ rackup_warning = <<~MISSING_RACKUP
1609
+ Sinatra could not start, the required gems weren't found!
1610
+
1611
+ Add them to your bundle with:
1612
+
1613
+ bundle add rackup puma
1614
+
1615
+ or install them with:
1616
+
1617
+ gem install rackup puma
1618
+
1619
+ MISSING_RACKUP
1620
+ warn rackup_warning
1621
+ exit 1
1622
+ end
1623
+
1592
1624
  return if running?
1593
1625
 
1594
1626
  set options
1595
- handler = Rack::Handler.pick(server)
1627
+ handler = Rackup::Handler.pick(server)
1596
1628
  handler_name = handler.name.gsub(/.*::/, '')
1597
1629
  server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
1598
1630
  server_settings.merge!(Port: port, Host: bind)
@@ -1724,7 +1756,7 @@ module Sinatra
1724
1756
  types.map! { |t| mime_types(t) }
1725
1757
  types.flatten!
1726
1758
  condition do
1727
- response_content_type = response['Content-Type']
1759
+ response_content_type = response['content-type']
1728
1760
  preferred_type = request.preferred_type(types)
1729
1761
 
1730
1762
  if response_content_type
@@ -1790,6 +1822,7 @@ module Sinatra
1790
1822
  setup_logging builder
1791
1823
  setup_sessions builder
1792
1824
  setup_protection builder
1825
+ setup_host_authorization builder
1793
1826
  end
1794
1827
 
1795
1828
  def setup_middleware(builder)
@@ -1806,7 +1839,7 @@ module Sinatra
1806
1839
  end
1807
1840
 
1808
1841
  def setup_null_logger(builder)
1809
- builder.use Rack::NullLogger
1842
+ builder.use Sinatra::Middleware::Logger, ::Logger::FATAL
1810
1843
  end
1811
1844
 
1812
1845
  def setup_common_logger(builder)
@@ -1815,9 +1848,9 @@ module Sinatra
1815
1848
 
1816
1849
  def setup_custom_logger(builder)
1817
1850
  if logging.respond_to? :to_int
1818
- builder.use Rack::Logger, logging
1851
+ builder.use Sinatra::Middleware::Logger, logging
1819
1852
  else
1820
- builder.use Rack::Logger
1853
+ builder.use Sinatra::Middleware::Logger
1821
1854
  end
1822
1855
  end
1823
1856
 
@@ -1838,6 +1871,10 @@ module Sinatra
1838
1871
  builder.use Rack::Protection, options
1839
1872
  end
1840
1873
 
1874
+ def setup_host_authorization(builder)
1875
+ builder.use Rack::Protection::HostAuthorization, host_authorization
1876
+ end
1877
+
1841
1878
  def setup_sessions(builder)
1842
1879
  return unless sessions?
1843
1880
 
@@ -1901,7 +1938,7 @@ module Sinatra
1901
1938
  set :dump_errors, proc { !test? }
1902
1939
  set :show_exceptions, proc { development? }
1903
1940
  set :sessions, false
1904
- set :session_store, Rack::Protection::EncryptedCookie
1941
+ set :session_store, Rack::Session::Cookie
1905
1942
  set :logging, false
1906
1943
  set :protection, true
1907
1944
  set :method_override, false
@@ -1932,10 +1969,25 @@ module Sinatra
1932
1969
  set :running_server, nil
1933
1970
  set :handler_name, nil
1934
1971
  set :traps, true
1935
- set :server, %w[HTTP webrick]
1972
+ set :server, %w[webrick]
1936
1973
  set :bind, proc { development? ? 'localhost' : '0.0.0.0' }
1937
1974
  set :port, Integer(ENV['PORT'] && !ENV['PORT'].empty? ? ENV['PORT'] : 4567)
1938
1975
  set :quiet, false
1976
+ set :host_authorization, ->() do
1977
+ if development?
1978
+ {
1979
+ permitted_hosts: [
1980
+ "localhost",
1981
+ ".localhost",
1982
+ ".test",
1983
+ IPAddr.new("0.0.0.0/0"),
1984
+ IPAddr.new("::/0"),
1985
+ ]
1986
+ }
1987
+ else
1988
+ {}
1989
+ end
1990
+ end
1939
1991
 
1940
1992
  ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
1941
1993
 
@@ -43,12 +43,6 @@ module Sinatra
43
43
  new.merge!(Hash[*args])
44
44
  end
45
45
 
46
- def initialize(*args)
47
- args.map!(&method(:convert_value))
48
-
49
- super(*args)
50
- end
51
-
52
46
  def default(*args)
53
47
  args.map!(&method(:convert_key))
54
48
 
@@ -191,7 +185,7 @@ module Sinatra
191
185
  def except(*keys)
192
186
  keys.map!(&method(:convert_key))
193
187
 
194
- super(*keys)
188
+ self.class[super(*keys)]
195
189
  end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0")
196
190
 
197
191
  private
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module Sinatra
6
+ module Middleware
7
+ class Logger
8
+ def initialize(app, level = ::Logger::INFO)
9
+ @app, @level = app, level
10
+ end
11
+
12
+ def call(env)
13
+ logger = ::Logger.new(env[Rack::RACK_ERRORS])
14
+ logger.level = @level
15
+
16
+ env[Rack::RACK_LOGGER] = logger
17
+ @app.call(env)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -38,8 +38,8 @@ module Sinatra
38
38
  [
39
39
  500,
40
40
  {
41
- 'Content-Type' => content_type,
42
- 'Content-Length' => body.bytesize.to_s
41
+ 'content-type' => content_type,
42
+ 'content-length' => body.bytesize.to_s
43
43
  },
44
44
  [body]
45
45
  ]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sinatra
4
- VERSION = '3.2.0'
4
+ VERSION = '4.1.1'
5
5
  end
data/sinatra.gemspec CHANGED
@@ -43,10 +43,12 @@ RubyGems 2.0 or newer is required to protect against public gem pushes. You can
43
43
  'documentation_uri' => 'https://www.rubydoc.info/gems/sinatra'
44
44
  }
45
45
 
46
- s.required_ruby_version = '>= 2.6.0'
46
+ s.required_ruby_version = '>= 2.7.8'
47
47
 
48
+ s.add_dependency 'logger', '>= 1.6.0'
48
49
  s.add_dependency 'mustermann', '~> 3.0'
49
- s.add_dependency 'rack', '~> 2.2', '>= 2.2.4'
50
+ s.add_dependency 'rack', '>= 3.0.0', '< 4'
50
51
  s.add_dependency 'rack-protection', version
52
+ s.add_dependency 'rack-session', '>= 2.0.0', '< 3'
51
53
  s.add_dependency 'tilt', '~> 2.0'
52
54
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 4.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Mizerany
@@ -11,8 +11,22 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-12-29 00:00:00.000000000 Z
14
+ date: 2024-11-20 00:00:00.000000000 Z
15
15
  dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: logger
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.6.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 1.6.0
16
30
  - !ruby/object:Gem::Dependency
17
31
  name: mustermann
18
32
  requirement: !ruby/object:Gem::Requirement
@@ -31,36 +45,56 @@ dependencies:
31
45
  name: rack
32
46
  requirement: !ruby/object:Gem::Requirement
33
47
  requirements:
34
- - - "~>"
35
- - !ruby/object:Gem::Version
36
- version: '2.2'
37
48
  - - ">="
38
49
  - !ruby/object:Gem::Version
39
- version: 2.2.4
50
+ version: 3.0.0
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: '4'
40
54
  type: :runtime
41
55
  prerelease: false
42
56
  version_requirements: !ruby/object:Gem::Requirement
43
57
  requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '2.2'
47
58
  - - ">="
48
59
  - !ruby/object:Gem::Version
49
- version: 2.2.4
60
+ version: 3.0.0
61
+ - - "<"
62
+ - !ruby/object:Gem::Version
63
+ version: '4'
50
64
  - !ruby/object:Gem::Dependency
51
65
  name: rack-protection
52
66
  requirement: !ruby/object:Gem::Requirement
53
67
  requirements:
54
68
  - - '='
55
69
  - !ruby/object:Gem::Version
56
- version: 3.2.0
70
+ version: 4.1.1
57
71
  type: :runtime
58
72
  prerelease: false
59
73
  version_requirements: !ruby/object:Gem::Requirement
60
74
  requirements:
61
75
  - - '='
62
76
  - !ruby/object:Gem::Version
63
- version: 3.2.0
77
+ version: 4.1.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: rack-session
80
+ requirement: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 2.0.0
85
+ - - "<"
86
+ - !ruby/object:Gem::Version
87
+ version: '3'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 2.0.0
95
+ - - "<"
96
+ - !ruby/object:Gem::Version
97
+ version: '3'
64
98
  - !ruby/object:Gem::Dependency
65
99
  name: tilt
66
100
  requirement: !ruby/object:Gem::Requirement
@@ -105,6 +139,7 @@ files:
105
139
  - lib/sinatra/images/500.png
106
140
  - lib/sinatra/indifferent_hash.rb
107
141
  - lib/sinatra/main.rb
142
+ - lib/sinatra/middleware/logger.rb
108
143
  - lib/sinatra/show_exceptions.rb
109
144
  - lib/sinatra/version.rb
110
145
  - sinatra.gemspec
@@ -132,14 +167,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
167
  requirements:
133
168
  - - ">="
134
169
  - !ruby/object:Gem::Version
135
- version: 2.6.0
170
+ version: 2.7.8
136
171
  required_rubygems_version: !ruby/object:Gem::Requirement
137
172
  requirements:
138
173
  - - ">="
139
174
  - !ruby/object:Gem::Version
140
175
  version: '0'
141
176
  requirements: []
142
- rubygems_version: 3.5.3
177
+ rubygems_version: 3.5.22
143
178
  signing_key:
144
179
  specification_version: 4
145
180
  summary: Classy web-development dressed in a DSL