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 +4 -4
- data/AUTHORS.md +14 -8
- data/CHANGELOG.md +47 -2
- data/Gemfile +19 -24
- data/README.md +13 -115
- data/Rakefile +17 -5
- data/SECURITY.md +1 -1
- data/VERSION +1 -1
- data/examples/stream.ru +0 -1
- data/lib/sinatra/base.rb +68 -27
- data/lib/sinatra/indifferent_hash.rb +10 -8
- data/lib/sinatra/show_exceptions.rb +2 -2
- data/lib/sinatra/version.rb +1 -1
- data/sinatra.gemspec +3 -4
- metadata +35 -31
- data/examples/rainbows.conf +0 -3
- data/examples/rainbows.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71d0bb379c736d6c251ceb424cac84dbe3a8b22d80a54473a0af1085b93b7dbf
|
4
|
+
data.tar.gz: 489d48a5e4f934127e04cdafa2d0d582c5143cc2a8f476239ea5b5b0f0e492c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
* **
|
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](
|
24
|
-
[Engine Yard](http://www.engineyard.com/)
|
25
|
-
[
|
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
|
-
##
|
1
|
+
## 4.0.0. / 2024-01-19
|
2
2
|
|
3
|
-
*
|
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'
|
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
|
-
|
65
|
-
|
66
|
-
|
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="
|
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.
|
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
|
-
|
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, :
|
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.
|
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
|
2823
|
+
<dt>Ruby</dt>
|
2920
2824
|
<dd>
|
2921
|
-
|
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>
|
2828
|
+
<dt>TruffleRuby</dt>
|
2926
2829
|
<dd>
|
2927
|
-
|
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
|
2934
|
-
recommended to use C extensions with JRuby.
|
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.
|
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
|
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
|
207
|
-
|
208
|
-
|
209
|
-
|
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
|
-
*
|
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
|
-
|
1
|
+
4.0.0
|
data/examples/stream.ru
CHANGED
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 '
|
180
|
-
headers.delete '
|
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
|
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['
|
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['
|
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
|
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 '
|
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
|
-
|
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
|
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['
|
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['
|
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['
|
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['
|
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['
|
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.
|
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['
|
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('
|
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['
|
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
|
-
|
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)$}
|
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 =
|
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['
|
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::
|
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='#{
|
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
|
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
|
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)
|
data/lib/sinatra/version.rb
CHANGED
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.
|
46
|
+
s.required_ruby_version = '>= 2.7.8'
|
47
47
|
|
48
48
|
s.add_dependency 'mustermann', '~> 3.0'
|
49
|
-
s.add_dependency 'rack', '
|
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:
|
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:
|
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:
|
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:
|
46
|
+
version: 3.0.0
|
47
|
+
- - "<"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '4'
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
|
-
name: rack-
|
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
|
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
|
69
|
+
version: '3'
|
64
70
|
- !ruby/object:Gem::Dependency
|
65
|
-
name:
|
71
|
+
name: rack-protection
|
66
72
|
requirement: !ruby/object:Gem::Requirement
|
67
73
|
requirements:
|
68
|
-
- -
|
74
|
+
- - '='
|
69
75
|
- !ruby/object:Gem::Version
|
70
|
-
version:
|
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:
|
83
|
+
version: 4.0.0
|
78
84
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
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: :
|
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.
|
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.
|
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: []
|
data/examples/rainbows.conf
DELETED
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
|