sinatra 3.1.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 315dee3d85d7778ffa48e041bd60370e9e89ecd3c01dbf0cf9450e41c62dc0d8
4
- data.tar.gz: '083a914c0b520684471e2715ec091c67ca8121bfb8b5d4cf410307d6e14e4ac5'
3
+ metadata.gz: 71d0bb379c736d6c251ceb424cac84dbe3a8b22d80a54473a0af1085b93b7dbf
4
+ data.tar.gz: 489d48a5e4f934127e04cdafa2d0d582c5143cc2a8f476239ea5b5b0f0e492c9
5
5
  SHA512:
6
- metadata.gz: 2790a4d58595f0f89667c5fd4530dde2de532ddaf02628f373162cc47d393732b1c9475ab59775c756750dfb52e60e7091118936ac8e70739fb266b46f82d3bd
7
- data.tar.gz: eb74f34bf0b9a681557809c656754312eb266e66c3b68fcabbf95699c3273cf4d998e3969224b09df9127ff90f5d34fba5bc93b1ff0c321b4a7646ddfcc0b6b7
6
+ metadata.gz: fbe92c1867d3ebe8ddc3f707c4e9f9cf2b68bddf2556164b85083ac635650725d63f8c847b4c70d0ad2abf6793b5f1054918b0b7c4e04d303119867be84c3253
7
+ data.tar.gz: 0727d88e9f5574c304dd3f31c6107a2b3e1cde96914e258c86fee529a1e922b0ff1d023f109fcc3b232f010ae21d9bdb4c365001dc7c3f658c0bd75b95e8d24d
data/AUTHORS.md CHANGED
@@ -2,31 +2,37 @@ Sinatra was designed and developed by Blake Mizerany in California.
2
2
 
3
3
  ### Current Team
4
4
 
5
- * **Konstantin Haase** (maintainer)
5
+ * **Eloy Perez**
6
+ * **Jordan Owens**
7
+ * **Olle Jonsson**
8
+ * **Patrik Ragnarsson**
6
9
  * **Zachary Scott**
7
- * **Kashyap Kondamudi**
8
- * **Ashley Williams**
9
- * **Trevor Bramble**
10
- * **Kunpei Sakai**
11
10
 
12
11
  ### Alumni
13
12
 
14
13
  * **Blake Mizerany** (creator)
14
+ * **Konstantin Haase** (maintainer)
15
15
  * **Ryan Tomayko**
16
16
  * **Simon Rozet**
17
17
  * **Katrina Owen**
18
+ * **Kashyap Kondamudi**
19
+ * **Ashley Williams**
20
+ * **Trevor Bramble**
21
+ * **Kunpei Sakai**
18
22
 
19
23
  ### Thanks
20
24
 
21
25
  Sinatra would not have been possible without strong company backing.
22
26
  In the past, financial and emotional support have been provided mainly by
23
- [Heroku](http://heroku.com), [GitHub](https://github.com) and
24
- [Engine Yard](http://www.engineyard.com/), and is now taken care of by
25
- [Travis CI](http://travis-ci.com/).
27
+ [Heroku](https://heroku.com), [GitHub](https://github.com),
28
+ [Engine Yard](http://www.engineyard.com/) and [Travis CI](https://travis-ci.com/),
29
+ and is now taken care of by [84codes](https://www.84codes.com/).
26
30
 
27
31
  Special thanks to the following extraordinary individuals, without whom
28
32
  Sinatra would not be possible:
29
33
 
34
+ * [Benoit Daloze](https://eregon.me/blog/) (eregon) for help around TruffleRuby
35
+ and keyword arguments use in mustermann.
30
36
  * [Ryan Tomayko](http://tomayko.com/) (rtomayko) for constantly fixing
31
37
  whitespace errors __60d5006__
32
38
  * [Ezra Zygmuntowicz](http://brainspl.at/) (ezmobius) for initial help and
data/CHANGELOG.md CHANGED
@@ -1,6 +1,50 @@
1
- ## Unreleased
1
+ ## 4.0.0. / 2024-01-19
2
2
 
3
- * _Your new feature here._
3
+ * New: Add support for Rack 3 ([#1857])
4
+ * Note: you may want to read the [Rack 3 Upgrade Guide]
5
+
6
+ * Require Ruby 2.7.8 as minimum Ruby version ([#1993])
7
+
8
+ * Breaking change: Drop support for Rack 2 ([#1857])
9
+ * Note: when using Sinatra to start the web server, you now need the `rackup` gem installed
10
+
11
+ * Breaking change: Remove the `IndifferentHash` initializer ([#1982])
12
+
13
+ * Breaking change: Disable `session_hijacking` protection by default ([#1984])
14
+
15
+ * Breaking change: Remove `Rack::Protection::EncryptedCookie` ([#1989])
16
+ * Note: cookies are still encrypted (by [`Rack::Session::Cookie`])
17
+
18
+ [#1857]: https://github.com/sinatra/sinatra/pull/1857
19
+ [#1993]: https://github.com/sinatra/sinatra/pull/1993
20
+ [#1982]: https://github.com/sinatra/sinatra/pull/1982
21
+ [#1984]: https://github.com/sinatra/sinatra/pull/1984
22
+ [#1989]: https://github.com/sinatra/sinatra/pull/1989
23
+ [`Rack::Session::Cookie`]: https://github.com/rack/rack-session
24
+ [Rack 3 Upgrade Guide]: https://github.com/rack/rack/blob/main/UPGRADE-GUIDE.md
25
+
26
+ ## 3.2.0 / 2023-12-29
27
+
28
+ * New: Add `#except` method to `Sinatra::IndifferentHash` ([#1940])
29
+
30
+ * New: Use `Exception#detailed_message` to show backtrace ([#1952])
31
+
32
+ * New: Add `Sinatra::HamlHelpers` to sinatra-contrib ([#1960])
33
+
34
+ * Fix: Add `base64` to rack-protection runtime dependencies ([#1946])
35
+
36
+ * Fix: Avoid open-ended dependencies for sinatra-contrib and rack-protection ([#1949])
37
+
38
+ * Fix: Helpful message when `Sinatra::Runner` times out ([#1975])
39
+
40
+ * Fix: Ruby 3.3 + Bundler 2.5 compatibility ([#1975])
41
+
42
+ [#1940]: https://github.com/sinatra/sinatra/pull/1940
43
+ [#1946]: https://github.com/sinatra/sinatra/pull/1946
44
+ [#1949]: https://github.com/sinatra/sinatra/pull/1949
45
+ [#1952]: https://github.com/sinatra/sinatra/pull/1952
46
+ [#1960]: https://github.com/sinatra/sinatra/pull/1960
47
+ [#1975]: https://github.com/sinatra/sinatra/pull/1975
4
48
 
5
49
  ## 3.1.0 / 2023-08-07
6
50
 
@@ -16,6 +60,7 @@
16
60
 
17
61
  * Fix: rack-protection: specify rack version requirement [#1932] by Patrik Ragnarsson
18
62
 
63
+ [#1911]: https://github.com/sinatra/sinatra/pull/1911
19
64
  [#1913]: https://github.com/sinatra/sinatra/pull/1913
20
65
  [#1900]: https://github.com/sinatra/sinatra/pull/1900
21
66
  [#1924]: https://github.com/sinatra/sinatra/pull/1924
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,29 +10,29 @@ 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
 
26
25
  gem 'minitest', '~> 5.0'
27
- gem 'rack-test', github: 'rack/rack-test'
26
+ gem 'rack-test'
28
27
  gem 'rubocop', '~> 1.32.0', require: false
29
- gem 'yard'
28
+ gem 'yard' # used by rake doc
30
29
 
31
30
  gem 'rack-protection', path: 'rack-protection'
32
31
  gem 'sinatra-contrib', path: 'sinatra-contrib'
33
32
 
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
- gem 'activesupport', '~> 6.1'
41
-
42
33
  gem 'asciidoctor'
43
34
  gem 'builder'
35
+ gem 'childprocess', '>= 5'
44
36
  gem 'commonmarker', '~> 0.23.4', platforms: [:ruby]
45
37
  gem 'erubi'
46
38
  gem 'eventmachine'
@@ -52,15 +44,18 @@ gem 'markaby'
52
44
  gem 'nokogiri', '> 1.5.0'
53
45
  gem 'pandoc-ruby', '~> 2.0.2'
54
46
  gem 'rabl'
55
- gem 'rainbows', platforms: [:mri] # uses #fork
56
47
  gem 'rdiscount', platforms: [:ruby]
57
48
  gem 'rdoc'
58
49
  gem 'redcarpet', platforms: [:ruby]
59
- gem 'sass-embedded', '~> 1.54'
60
50
  gem 'simplecov', require: false
61
51
  gem 'slim', '~> 4'
62
52
  gem 'yajl-ruby', platforms: [:ruby]
63
-
64
- gem 'json', platforms: %i[jruby mri]
65
-
66
- gem 'jar-dependencies', '= 0.4.1', platforms: [:jruby] # Gem::LoadError with jar-dependencies 0.4.2
53
+ gem 'zeitwerk'
54
+
55
+ # sass-embedded depends on google-protobuf
56
+ # which fails to be installed on JRuby and TruffleRuby under aarch64
57
+ # https://github.com/jruby/jruby/issues/8062
58
+ # https://github.com/protocolbuffers/protobuf/issues/11935
59
+ java = %w(jruby truffleruby).include?(RUBY_ENGINE)
60
+ aarch64 = RbConfig::CONFIG["target_cpu"] == 'aarch64'
61
+ gem 'sass-embedded', '~> 1.54' unless java && aarch64
data/README.md CHANGED
@@ -846,7 +846,7 @@ It also takes a block for inline templates (see [example](#inline-templates)).
846
846
  <table>
847
847
  <tr>
848
848
  <td>Dependency</td>
849
- <td><a href="http://slim-lang.com/" title="Slim Lang">Slim Lang</a></td>
849
+ <td><a href="https://slim-template.github.io/" title="Slim Lang">Slim Lang</a></td>
850
850
  </tr>
851
851
  <tr>
852
852
  <td>File Extension</td>
@@ -1199,22 +1199,6 @@ $ ruby -e "require 'securerandom'; puts SecureRandom.hex(64)"
1199
1199
  99ae8af...snip...ec0f262ac
1200
1200
  ```
1201
1201
 
1202
- **Session Secret Generation (Bonus Points)**
1203
-
1204
- Use the [sysrandom gem](https://github.com/cryptosphere/sysrandom#readme) to
1205
- use the system RNG facilities to generate random values instead of
1206
- userspace `OpenSSL` which MRI Ruby currently defaults to:
1207
-
1208
- ```text
1209
- $ gem install sysrandom
1210
- Building native extensions. This could take a while...
1211
- Successfully installed sysrandom-1.x
1212
- 1 gem installed
1213
-
1214
- $ ruby -e "require 'sysrandom/securerandom'; puts SecureRandom.hex(64)"
1215
- 99ae8af...snip...ec0f262ac
1216
- ```
1217
-
1218
1202
  **Session Secret Environment Variable**
1219
1203
 
1220
1204
  Set a `SESSION_SECRET` environment variable for Sinatra to the value you
@@ -1229,14 +1213,10 @@ purposes only:
1229
1213
  **Session Secret App Config**
1230
1214
 
1231
1215
  Set up your app config to fail-safe to a secure random secret
1232
- if the `SESSION_SECRET` environment variable is not available.
1233
-
1234
- For bonus points use the [sysrandom
1235
- gem](https://github.com/cryptosphere/sysrandom#readme) here as well:
1216
+ if the `SESSION_SECRET` environment variable is not available:
1236
1217
 
1237
1218
  ```ruby
1238
1219
  require 'securerandom'
1239
- # -or- require 'sysrandom/securerandom'
1240
1220
  set :session_secret, ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) }
1241
1221
  ```
1242
1222
 
@@ -1441,53 +1421,9 @@ to `stream` finishes executing. Streaming does not work at all with Shotgun.
1441
1421
 
1442
1422
  If the optional parameter is set to `keep_open`, it will not call `close` on
1443
1423
  the stream object, allowing you to close it at any later point in the
1444
- execution flow. This only works on evented servers, like Rainbows.
1445
- Other servers will still close the stream:
1446
-
1447
- ```ruby
1448
- # config.ru
1449
- require 'sinatra/base'
1450
-
1451
- class App < Sinatra::Base
1452
- connections = []
1453
-
1454
- get '/subscribe', provides: 'text/event-stream' do
1455
- # register a client's interest in server events
1456
- stream(:keep_open) do |out|
1457
- connections << out
1458
- # purge dead connections
1459
- connections.reject!(&:closed?)
1460
- end
1461
- end
1462
-
1463
- post '/' do
1464
- connections.each do |out|
1465
- # notify client that a new message has arrived
1466
- out << "data: #{params[:msg]}\n\n"
1467
-
1468
- # indicate client to connect again
1469
- out.close
1470
- end
1471
-
1472
- 204 # response without entity body
1473
- end
1474
- end
1475
-
1476
- run App
1477
- ```
1478
-
1479
- ```ruby
1480
- # rainbows.conf
1481
- Rainbows! do
1482
- use :EventMachine
1483
- end
1484
- ````
1424
+ execution flow.
1485
1425
 
1486
- Run:
1487
-
1488
- ```shell
1489
- rainbows -c rainbows.conf
1490
- ```
1426
+ You can have a look at the [chat example](https://github.com/sinatra/sinatra/blob/main/examples/chat.rb)
1491
1427
 
1492
1428
  It's also possible for the client to close the connection when trying to
1493
1429
  write to the socket. Because of this, it's recommended to check
@@ -1986,7 +1922,7 @@ set :protection, :except => :path_traversal
1986
1922
  You can also hand in an array in order to disable a list of protections:
1987
1923
 
1988
1924
  ```ruby
1989
- set :protection, :except => [:path_traversal, :session_hijacking]
1925
+ set :protection, :except => [:path_traversal, :remote_token]
1990
1926
  ```
1991
1927
 
1992
1928
  By default, Sinatra will only set up session based protection if `:sessions`
@@ -2878,68 +2814,30 @@ by Konstantin_
2878
2814
  Sinatra doesn't impose any concurrency model but leaves that to the
2879
2815
  underlying Rack handler (server) like Puma or WEBrick. Sinatra
2880
2816
  itself is thread-safe, so there won't be any problem if the Rack handler
2881
- uses a threaded model of concurrency. This would mean that when starting
2882
- the server, you'd have to specify the correct invocation method for the
2883
- specific Rack handler. The following example is a demonstration of how
2884
- to start a multi-threaded Rainbows server:
2885
-
2886
- ```ruby
2887
- # config.ru
2888
-
2889
- require 'sinatra/base'
2890
-
2891
- class App < Sinatra::Base
2892
- get '/' do
2893
- "Hello, World"
2894
- end
2895
- end
2896
-
2897
- run App
2898
- ```
2899
-
2900
- ```ruby
2901
- # rainbows.conf
2902
-
2903
- # Rainbows configurator is based on Unicorn.
2904
- Rainbows! do
2905
- use :ThreadSpawn
2906
- end
2907
- ```
2908
-
2909
- To start the server, the command would be:
2910
-
2911
- ```shell
2912
- rainbows -c rainbows.conf
2913
- ```
2817
+ uses a threaded model of concurrency.
2914
2818
 
2915
2819
  ## Requirement
2916
2820
 
2917
2821
  The following Ruby versions are officially supported:
2918
2822
  <dl>
2919
- <dt>Ruby 2.6</dt>
2823
+ <dt>Ruby</dt>
2920
2824
  <dd>
2921
- 2.6 is fully supported and recommended. There are currently no plans to
2922
- drop official support for it.
2825
+ <a href="https://www.ruby-lang.org/en/downloads/">The stable releases</a> are fully supported and recommended.
2923
2826
  </dd>
2924
2827
 
2925
- <dt>Rubinius</dt>
2828
+ <dt>TruffleRuby</dt>
2926
2829
  <dd>
2927
- Rubinius is officially supported (Rubinius >= 2.x). It is recommended to
2928
- <tt>gem install puma</tt>.
2830
+ The latest stable release of TruffleRuby is supported.
2929
2831
  </dd>
2930
2832
 
2931
2833
  <dt>JRuby</dt>
2932
2834
  <dd>
2933
- The latest stable release of JRuby is officially supported. It is not
2934
- recommended to use C extensions with JRuby. It is recommended to
2935
- <tt>gem install trinidad</tt>.
2835
+ The latest stable release of JRuby is supported. It is not
2836
+ recommended to use C extensions with JRuby.
2936
2837
  </dd>
2937
2838
  </dl>
2938
2839
 
2939
- Versions of Ruby before 2.6 are no longer supported as of Sinatra 3.0.0.
2940
-
2941
- We also keep an eye on upcoming Ruby versions. Expect upcoming
2942
- 3.x releases to be fully supported.
2840
+ Versions of Ruby before 2.7.8 are no longer supported as of Sinatra 4.0.0.
2943
2841
 
2944
2842
  Sinatra should work on any operating system supported by the chosen Ruby
2945
2843
  implementation.
data/Rakefile CHANGED
@@ -191,7 +191,7 @@ if defined?(Gem)
191
191
  end
192
192
  end
193
193
 
194
- desc 'Commits the version to github repository'
194
+ desc 'Commits the version to git (no push)'
195
195
  task :commit_version do
196
196
  %w[
197
197
  lib/sinatra
@@ -203,10 +203,22 @@ if defined?(Gem)
203
203
  end
204
204
 
205
205
  sh <<-SH
206
- git commit --allow-empty -a -m '#{source_version} release' &&
207
- git tag -s v#{source_version} -m '#{source_version} release' &&
208
- git push && (git push origin || true) &&
209
- git push --tags && (git push origin --tags || true)
206
+ git commit --allow-empty --all --message '#{source_version} release'
207
+ SH
208
+ end
209
+
210
+ desc 'Tags the version in git (no push)'
211
+ task :tag_version do
212
+ sh <<-SH
213
+ git tag --sign v#{source_version} --message '#{source_version} release'
214
+ SH
215
+ end
216
+
217
+ desc 'Watch the release workflow run'
218
+ task :watch do
219
+ sh <<-SH
220
+ runId=$(gh run list --workflow=release.yml --limit 1 --json databaseId --jq '.[].databaseId')
221
+ gh run watch --interval 1 --exit-status $runId
210
222
  SH
211
223
  end
212
224
 
data/SECURITY.md CHANGED
@@ -6,7 +6,7 @@ After the initial reply to your report the security team will endeavor to keep y
6
6
 
7
7
  If you have not received a reply to your email within 48 hours, or have not heard from the security team for the past five days there are a few steps you can take:
8
8
 
9
- * Contact the current security coordinator [Zachary Scott](mailto:zzak@ruby-lang.org) directly
9
+ * Reach out to us on [discord](https://discord.gg/ncjsfsNHh7)
10
10
 
11
11
  ## Disclosure Policy
12
12
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.0
1
+ 4.0.0
data/examples/stream.ru CHANGED
@@ -6,7 +6,6 @@
6
6
  #
7
7
  # unicorn stream.ru # gem install unicorn
8
8
  # puma stream.ru # gem install puma
9
- # rainbows -c rainbows.conf stream.ru # gem install rainbows eventmachine
10
9
 
11
10
  require 'sinatra/base'
12
11
 
data/lib/sinatra/base.rb CHANGED
@@ -2,8 +2,13 @@
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'
@@ -176,8 +181,8 @@ module Sinatra
176
181
  result = body
177
182
 
178
183
  if drop_content_info?
179
- headers.delete 'Content-Length'
180
- headers.delete 'Content-Type'
184
+ headers.delete 'content-length'
185
+ headers.delete 'content-type'
181
186
  end
182
187
 
183
188
  if drop_body?
@@ -186,9 +191,9 @@ module Sinatra
186
191
  end
187
192
 
188
193
  if calculate_content_length?
189
- # if some other code has already set Content-Length, don't muck with it
194
+ # if some other code has already set content-length, don't muck with it
190
195
  # currently, this would be the static file-handler
191
- headers['Content-Length'] = body.map(&:bytesize).reduce(0, :+).to_s
196
+ headers['content-length'] = body.map(&:bytesize).reduce(0, :+).to_s
192
197
  end
193
198
 
194
199
  [status, headers, result]
@@ -197,7 +202,7 @@ module Sinatra
197
202
  private
198
203
 
199
204
  def calculate_content_length?
200
- headers['Content-Type'] && !headers['Content-Length'] && (Array === body)
205
+ headers['content-type'] && !headers['content-length'] && (Array === body)
201
206
  end
202
207
 
203
208
  def drop_content_info?
@@ -209,7 +214,7 @@ module Sinatra
209
214
  end
210
215
  end
211
216
 
212
- # Some Rack handlers (Rainbows!) implement an extended body object protocol, however,
217
+ # Some Rack handlers implement an extended body object protocol, however,
213
218
  # some middleware (namely Rack::Lint) will break it by not mirroring the methods in question.
214
219
  # This middleware will detect an extended body object and will make sure it reaches the
215
220
  # handler directly. We do this here, so our middleware and middleware set up by the app will
@@ -289,10 +294,8 @@ module Sinatra
289
294
  def block.each; yield(call) end
290
295
  response.body = block
291
296
  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
297
  unless request.head? || value.is_a?(Rack::Files::Iterator) || value.is_a?(Stream)
295
- headers.delete 'Content-Length'
298
+ headers.delete 'content-length'
296
299
  end
297
300
  response.body = value
298
301
  else
@@ -302,7 +305,10 @@ module Sinatra
302
305
 
303
306
  # Halt processing and redirect to the URI provided.
304
307
  def redirect(uri, *args)
305
- if (env['HTTP_VERSION'] == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET')
308
+ # SERVER_PROTOCOL is required in Rack 3, fall back to HTTP_VERSION
309
+ # for servers not updated for Rack 3 (like Puma 5)
310
+ http_version = env['SERVER_PROTOCOL'] || env['HTTP_VERSION']
311
+ if (http_version == 'HTTP/1.1') && (env['REQUEST_METHOD'] != 'GET')
306
312
  status 303
307
313
  else
308
314
  status 302
@@ -372,10 +378,10 @@ module Sinatra
372
378
  Base.mime_type(type)
373
379
  end
374
380
 
375
- # Set the Content-Type of the response body given a media type or file
381
+ # Set the content-type of the response body given a media type or file
376
382
  # extension.
377
383
  def content_type(type = nil, params = {})
378
- return response['Content-Type'] unless type
384
+ return response['content-type'] unless type
379
385
 
380
386
  default = params.delete :default
381
387
  mime_type = mime_type(type) || default
@@ -393,7 +399,7 @@ module Sinatra
393
399
  "#{key}=#{val}"
394
400
  end.join(', ')
395
401
  end
396
- response['Content-Type'] = mime_type
402
+ response['content-type'] = mime_type
397
403
  end
398
404
 
399
405
  # https://html.spec.whatwg.org/#multipart-form-data
@@ -412,12 +418,12 @@ module Sinatra
412
418
  params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE))
413
419
  response['Content-Disposition'] << params
414
420
  ext = File.extname(filename)
415
- content_type(ext) unless response['Content-Type'] || ext.empty?
421
+ content_type(ext) unless response['content-type'] || ext.empty?
416
422
  end
417
423
 
418
424
  # Use the contents of the file at +path+ as the response body.
419
425
  def send_file(path, opts = {})
420
- if opts[:type] || !response['Content-Type']
426
+ if opts[:type] || !response['content-type']
421
427
  content_type opts[:type] || File.extname(path), default: 'application/octet-stream'
422
428
  end
423
429
 
@@ -433,7 +439,7 @@ module Sinatra
433
439
  result = file.serving(request, path)
434
440
 
435
441
  result[1].each { |k, v| headers[k] ||= v }
436
- headers['Content-Length'] = result[1]['Content-Length']
442
+ headers['content-length'] = result[1]['content-length']
437
443
  opts[:status] &&= Integer(opts[:status])
438
444
  halt (opts[:status] || result[0]), result[2]
439
445
  rescue Errno::ENOENT
@@ -502,8 +508,7 @@ module Sinatra
502
508
  # the response body have not yet been generated.
503
509
  #
504
510
  # The close parameter specifies whether Stream#close should be called
505
- # after the block has been executed. This is only relevant for evented
506
- # servers like Rainbows.
511
+ # after the block has been executed.
507
512
  def stream(keep_open = false)
508
513
  scheduler = env['async.callback'] ? EventMachine : Stream
509
514
  current = @params.dup
@@ -996,7 +1001,7 @@ module Sinatra
996
1001
  invoke { dispatch! }
997
1002
  invoke { error_block!(response.status) } unless @env['sinatra.error']
998
1003
 
999
- unless @response['Content-Type']
1004
+ unless @response['content-type']
1000
1005
  if Array === body && body[0].respond_to?(:content_type)
1001
1006
  content_type body[0].content_type
1002
1007
  elsif (default = settings.default_content_type)
@@ -1059,7 +1064,7 @@ module Sinatra
1059
1064
  routes = base.routes[@request.request_method]
1060
1065
 
1061
1066
  routes&.each do |pattern, conditions, block|
1062
- response.delete_header('Content-Type') unless @pinned_response
1067
+ response.delete_header('content-type') unless @pinned_response
1063
1068
 
1064
1069
  returned_pass_block = process_route(pattern, conditions) do |*args|
1065
1070
  env['sinatra.route'] = "#{@request.request_method} #{pattern}"
@@ -1180,7 +1185,7 @@ module Sinatra
1180
1185
  invoke do
1181
1186
  static! if settings.static? && (request.get? || request.head?)
1182
1187
  filter! :before do
1183
- @pinned_response = !response['Content-Type'].nil?
1188
+ @pinned_response = !response['content-type'].nil?
1184
1189
  end
1185
1190
  route!
1186
1191
  end
@@ -1261,7 +1266,19 @@ module Sinatra
1261
1266
  end
1262
1267
 
1263
1268
  def dump_errors!(boom)
1264
- msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{boom.message}:", *boom.backtrace].join("\n\t")
1269
+ if boom.respond_to?(:detailed_message)
1270
+ msg = boom.detailed_message(highlight: false)
1271
+ if msg =~ /\A(.*?)(?: \(#{ Regexp.quote(boom.class.to_s) }\))?\n/
1272
+ msg = $1
1273
+ additional_msg = $'.lines(chomp: true)
1274
+ else
1275
+ additional_msg = []
1276
+ end
1277
+ else
1278
+ msg = boom.message
1279
+ additional_msg = []
1280
+ end
1281
+ msg = ["#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} - #{boom.class} - #{msg}:", *additional_msg, *boom.backtrace].join("\n\t")
1265
1282
  @env['rack.errors'].puts(msg)
1266
1283
  end
1267
1284
 
@@ -1270,6 +1287,7 @@ module Sinatra
1270
1287
  %r{/sinatra(/(base|main|show_exceptions))?\.rb$}, # all sinatra code
1271
1288
  %r{lib/tilt.*\.rb$}, # all tilt code
1272
1289
  /^\(.*\)$/, # generated code
1290
+ /\/bundled_gems.rb$/, # ruby >= 3.3 with bundler >= 2.5
1273
1291
  %r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
1274
1292
  /active_support/, # active_support require hacks
1275
1293
  %r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
@@ -1448,7 +1466,13 @@ module Sinatra
1448
1466
  # mime_types :js # => ['application/javascript', 'text/javascript']
1449
1467
  def mime_types(type)
1450
1468
  type = mime_type type
1451
- type =~ %r{^application/(xml|javascript)$} ? [type, "text/#{$1}"] : [type]
1469
+ if type =~ %r{^application/(xml|javascript)$}
1470
+ [type, "text/#{$1}"]
1471
+ elsif type =~ %r{^text/(xml|javascript)$}
1472
+ [type, "application/#{$1}"]
1473
+ else
1474
+ [type]
1475
+ end
1452
1476
  end
1453
1477
 
1454
1478
  # Define a before filter; runs before all requests within the same
@@ -1577,10 +1601,27 @@ module Sinatra
1577
1601
  # Puma, Falcon, or WEBrick (in that order). If given a block, will call
1578
1602
  # with the constructed handler once we have taken the stage.
1579
1603
  def run!(options = {}, &block)
1604
+ unless defined?(Rackup::Handler)
1605
+ rackup_warning = <<~MISSING_RACKUP
1606
+ Sinatra could not start, the "rackup" gem was not found!
1607
+
1608
+ Add it to your bundle with:
1609
+
1610
+ bundle add rackup
1611
+
1612
+ or install it with:
1613
+
1614
+ gem install rackup
1615
+
1616
+ MISSING_RACKUP
1617
+ warn rackup_warning
1618
+ exit 1
1619
+ end
1620
+
1580
1621
  return if running?
1581
1622
 
1582
1623
  set options
1583
- handler = Rack::Handler.pick(server)
1624
+ handler = Rackup::Handler.pick(server)
1584
1625
  handler_name = handler.name.gsub(/.*::/, '')
1585
1626
  server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
1586
1627
  server_settings.merge!(Port: port, Host: bind)
@@ -1712,7 +1753,7 @@ module Sinatra
1712
1753
  types.map! { |t| mime_types(t) }
1713
1754
  types.flatten!
1714
1755
  condition do
1715
- response_content_type = response['Content-Type']
1756
+ response_content_type = response['content-type']
1716
1757
  preferred_type = request.preferred_type(types)
1717
1758
 
1718
1759
  if response_content_type
@@ -1889,7 +1930,7 @@ module Sinatra
1889
1930
  set :dump_errors, proc { !test? }
1890
1931
  set :show_exceptions, proc { development? }
1891
1932
  set :sessions, false
1892
- set :session_store, Rack::Protection::EncryptedCookie
1933
+ set :session_store, Rack::Session::Cookie
1893
1934
  set :logging, false
1894
1935
  set :protection, true
1895
1936
  set :method_override, false
@@ -1995,7 +2036,7 @@ module Sinatra
1995
2036
  </head>
1996
2037
  <body>
1997
2038
  <h2>Sinatra doesn’t know this ditty.</h2>
1998
- <img src='#{uri '/__sinatra__/404.png'}'>
2039
+ <img src='#{request.script_name}/__sinatra__/404.png'>
1999
2040
  <div id="c">
2000
2041
  Try this:
2001
2042
  <pre>#{Rack::Utils.escape_html(code)}</pre>
@@ -21,7 +21,8 @@ module Sinatra
21
21
  # writing interface (calling e.g. <tt>[]=</tt>, <tt>merge</tt>). This mapping
22
22
  # belongs to the public interface. For example, given:
23
23
  #
24
- # hash = Sinatra::IndifferentHash.new(:a=>1)
24
+ # hash = Sinatra::IndifferentHash.new
25
+ # hash[:a] = 1
25
26
  #
26
27
  # You are guaranteed that the key is returned as a string:
27
28
  #
@@ -29,7 +30,8 @@ module Sinatra
29
30
  #
30
31
  # Technically other types of keys are accepted:
31
32
  #
32
- # hash = Sinatra::IndifferentHash.new(:a=>1)
33
+ # hash = Sinatra::IndifferentHash
34
+ # hash[:a] = 1
33
35
  # hash[0] = 0
34
36
  # hash # => { "a"=>1, 0=>0 }
35
37
  #
@@ -41,12 +43,6 @@ module Sinatra
41
43
  new.merge!(Hash[*args])
42
44
  end
43
45
 
44
- def initialize(*args)
45
- args.map!(&method(:convert_value))
46
-
47
- super(*args)
48
- end
49
-
50
46
  def default(*args)
51
47
  args.map!(&method(:convert_key))
52
48
 
@@ -186,6 +182,12 @@ module Sinatra
186
182
  dup.tap(&:compact!)
187
183
  end
188
184
 
185
+ def except(*keys)
186
+ keys.map!(&method(:convert_key))
187
+
188
+ super(*keys)
189
+ end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0")
190
+
189
191
  private
190
192
 
191
193
  def convert_key(key)
@@ -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.1.0'
4
+ VERSION = '4.0.0'
5
5
  end
data/sinatra.gemspec CHANGED
@@ -43,12 +43,11 @@ 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
48
  s.add_dependency 'mustermann', '~> 3.0'
49
- s.add_dependency 'rack', '~> 2.2', '>= 2.2.4'
49
+ s.add_dependency 'rack', '>= 3.0.0', '< 4'
50
+ s.add_dependency 'rack-session', '>= 2.0.0', '< 3'
50
51
  s.add_dependency 'rack-protection', version
51
52
  s.add_dependency 'tilt', '~> 2.0'
52
-
53
- s.add_development_dependency 'rack-test', '~> 2'
54
53
  end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Blake Mizerany
8
8
  - Ryan Tomayko
9
9
  - Simon Rozet
10
10
  - Konstantin Haase
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2023-08-07 00:00:00.000000000 Z
14
+ date: 2024-01-19 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: mustermann
@@ -31,64 +31,70 @@ dependencies:
31
31
  name: rack
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
- - - "~>"
35
- - !ruby/object:Gem::Version
36
- version: '2.2'
37
34
  - - ">="
38
35
  - !ruby/object:Gem::Version
39
- version: 2.2.4
36
+ version: 3.0.0
37
+ - - "<"
38
+ - !ruby/object:Gem::Version
39
+ version: '4'
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '2.2'
47
44
  - - ">="
48
45
  - !ruby/object:Gem::Version
49
- version: 2.2.4
46
+ version: 3.0.0
47
+ - - "<"
48
+ - !ruby/object:Gem::Version
49
+ version: '4'
50
50
  - !ruby/object:Gem::Dependency
51
- name: rack-protection
51
+ name: rack-session
52
52
  requirement: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - '='
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.0.0
57
+ - - "<"
55
58
  - !ruby/object:Gem::Version
56
- version: 3.1.0
59
+ version: '3'
57
60
  type: :runtime
58
61
  prerelease: false
59
62
  version_requirements: !ruby/object:Gem::Requirement
60
63
  requirements:
61
- - - '='
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.0.0
67
+ - - "<"
62
68
  - !ruby/object:Gem::Version
63
- version: 3.1.0
69
+ version: '3'
64
70
  - !ruby/object:Gem::Dependency
65
- name: tilt
71
+ name: rack-protection
66
72
  requirement: !ruby/object:Gem::Requirement
67
73
  requirements:
68
- - - "~>"
74
+ - - '='
69
75
  - !ruby/object:Gem::Version
70
- version: '2.0'
76
+ version: 4.0.0
71
77
  type: :runtime
72
78
  prerelease: false
73
79
  version_requirements: !ruby/object:Gem::Requirement
74
80
  requirements:
75
- - - "~>"
81
+ - - '='
76
82
  - !ruby/object:Gem::Version
77
- version: '2.0'
83
+ version: 4.0.0
78
84
  - !ruby/object:Gem::Dependency
79
- name: rack-test
85
+ name: tilt
80
86
  requirement: !ruby/object:Gem::Requirement
81
87
  requirements:
82
88
  - - "~>"
83
89
  - !ruby/object:Gem::Version
84
- version: '2'
85
- type: :development
90
+ version: '2.0'
91
+ type: :runtime
86
92
  prerelease: false
87
93
  version_requirements: !ruby/object:Gem::Requirement
88
94
  requirements:
89
95
  - - "~>"
90
96
  - !ruby/object:Gem::Version
91
- version: '2'
97
+ version: '2.0'
92
98
  description: Sinatra is a DSL for quickly creating web applications in Ruby with minimal
93
99
  effort.
94
100
  email: sinatrarb@googlegroups.com
@@ -111,8 +117,6 @@ files:
111
117
  - VERSION
112
118
  - examples/chat.rb
113
119
  - examples/lifecycle_events.rb
114
- - examples/rainbows.conf
115
- - examples/rainbows.rb
116
120
  - examples/simple.rb
117
121
  - examples/stream.ru
118
122
  - lib/sinatra.rb
@@ -134,7 +138,7 @@ metadata:
134
138
  bug_tracker_uri: https://github.com/sinatra/sinatra/issues
135
139
  mailing_list_uri: http://groups.google.com/group/sinatrarb
136
140
  documentation_uri: https://www.rubydoc.info/gems/sinatra
137
- post_install_message:
141
+ post_install_message:
138
142
  rdoc_options:
139
143
  - "--line-numbers"
140
144
  - "--title"
@@ -148,15 +152,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
152
  requirements:
149
153
  - - ">="
150
154
  - !ruby/object:Gem::Version
151
- version: 2.6.0
155
+ version: 2.7.8
152
156
  required_rubygems_version: !ruby/object:Gem::Requirement
153
157
  requirements:
154
158
  - - ">="
155
159
  - !ruby/object:Gem::Version
156
160
  version: '0'
157
161
  requirements: []
158
- rubygems_version: 3.4.18
159
- signing_key:
162
+ rubygems_version: 3.5.3
163
+ signing_key:
160
164
  specification_version: 4
161
165
  summary: Classy web-development dressed in a DSL
162
166
  test_files: []
@@ -1,3 +0,0 @@
1
- Rainbows! do
2
- use :EventMachine
3
- end
data/examples/rainbows.rb DELETED
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rainbows'
4
-
5
- module Rack
6
- module Handler
7
- class Rainbows
8
- def self.run(app, **options)
9
- rainbows_options = {
10
- listeners: ["#{options[:Host]}:#{options[:Port]}"],
11
- worker_processes: 1,
12
- timeout: 30,
13
- config_file: ::File.expand_path('rainbows.conf', __dir__)
14
- }
15
-
16
- ::Rainbows::HttpServer.new(app, rainbows_options).start.join
17
- end
18
- end
19
-
20
- register :rainbows, ::Rack::Handler::Rainbows
21
- end
22
- end