sinatra 3.0.6 → 4.0.0
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 +4 -4
- data/AUTHORS.md +14 -8
- data/CHANGELOG.md +67 -2
- data/Gemfile +19 -17
- data/README.md +126 -117
- data/Rakefile +17 -5
- data/SECURITY.md +1 -1
- data/VERSION +1 -1
- data/examples/lifecycle_events.rb +20 -0
- data/examples/stream.ru +0 -2
- data/lib/sinatra/base.rb +134 -37
- 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 +36 -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,71 @@
|
|
|
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
|
|
48
|
+
|
|
49
|
+
## 3.1.0 / 2023-08-07
|
|
50
|
+
|
|
51
|
+
* New: Add sass support via sass-embedded [#1911] by なつき
|
|
52
|
+
|
|
53
|
+
* New: Add start and stop callbacks [#1913] by Jevin Sew
|
|
54
|
+
|
|
55
|
+
* New: Warn on dropping sessions [#1900] by Jonathan del Strother
|
|
56
|
+
|
|
57
|
+
* New: Make Puma the default server [#1924] by Patrik Ragnarsson
|
|
58
|
+
|
|
59
|
+
* Fix: Remove use of Tilt::Cache [#1922] by Jeremy Evans (allows use of Tilt 2.2.0 without deprecation warning)
|
|
60
|
+
|
|
61
|
+
* Fix: rack-protection: specify rack version requirement [#1932] by Patrik Ragnarsson
|
|
62
|
+
|
|
63
|
+
[#1911]: https://github.com/sinatra/sinatra/pull/1911
|
|
64
|
+
[#1913]: https://github.com/sinatra/sinatra/pull/1913
|
|
65
|
+
[#1900]: https://github.com/sinatra/sinatra/pull/1900
|
|
66
|
+
[#1924]: https://github.com/sinatra/sinatra/pull/1924
|
|
67
|
+
[#1922]: https://github.com/sinatra/sinatra/pull/1922
|
|
68
|
+
[#1932]: https://github.com/sinatra/sinatra/pull/1932
|
|
4
69
|
|
|
5
70
|
## 3.0.6 / 2023-04-11
|
|
6
71
|
|
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,23 +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
|
-
gem 'activesupport', '~> 6.1'
|
|
35
|
-
|
|
36
33
|
gem 'asciidoctor'
|
|
37
34
|
gem 'builder'
|
|
35
|
+
gem 'childprocess', '>= 5'
|
|
38
36
|
gem 'commonmarker', '~> 0.23.4', platforms: [:ruby]
|
|
39
37
|
gem 'erubi'
|
|
40
38
|
gem 'eventmachine'
|
|
@@ -46,14 +44,18 @@ gem 'markaby'
|
|
|
46
44
|
gem 'nokogiri', '> 1.5.0'
|
|
47
45
|
gem 'pandoc-ruby', '~> 2.0.2'
|
|
48
46
|
gem 'rabl'
|
|
49
|
-
gem 'rainbows', platforms: [:mri] # uses #fork
|
|
50
47
|
gem 'rdiscount', platforms: [:ruby]
|
|
51
48
|
gem 'rdoc'
|
|
52
49
|
gem 'redcarpet', platforms: [:ruby]
|
|
53
50
|
gem 'simplecov', require: false
|
|
54
51
|
gem 'slim', '~> 4'
|
|
55
52
|
gem 'yajl-ruby', platforms: [:ruby]
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
@@ -54,6 +54,8 @@ pick up if available.
|
|
|
54
54
|
- [Erb Templates](#erb-templates)
|
|
55
55
|
- [Builder Templates](#builder-templates)
|
|
56
56
|
- [Nokogiri Templates](#nokogiri-templates)
|
|
57
|
+
- [Sass Templates](#sass-templates)
|
|
58
|
+
- [Scss Templates](#scss-templates)
|
|
57
59
|
- [Liquid Templates](#liquid-templates)
|
|
58
60
|
- [Markdown Templates](#markdown-templates)
|
|
59
61
|
- [RDoc Templates](#rdoc-templates)
|
|
@@ -93,6 +95,7 @@ pick up if available.
|
|
|
93
95
|
- [Configuration](#configuration)
|
|
94
96
|
- [Configuring attack protection](#configuring-attack-protection)
|
|
95
97
|
- [Available Settings](#available-settings)
|
|
98
|
+
- [Lifecycle Events](#lifecycle-events)
|
|
96
99
|
- [Environments](#environments)
|
|
97
100
|
- [Error Handling](#error-handling)
|
|
98
101
|
- [Not Found](#not-found)
|
|
@@ -649,6 +652,39 @@ It also takes a block for inline templates (see [example](#inline-templates)).
|
|
|
649
652
|
|
|
650
653
|
It also takes a block for inline templates (see [example](#inline-templates)).
|
|
651
654
|
|
|
655
|
+
#### Sass Templates
|
|
656
|
+
|
|
657
|
+
<table>
|
|
658
|
+
<tr>
|
|
659
|
+
<td>Dependency</td>
|
|
660
|
+
<td><a href="https://github.com/ntkme/sass-embedded-host-ruby" title="sass-embedded">sass-embedded</a></td>
|
|
661
|
+
</tr>
|
|
662
|
+
<tr>
|
|
663
|
+
<td>File Extension</td>
|
|
664
|
+
<td><tt>.sass</tt></td>
|
|
665
|
+
</tr>
|
|
666
|
+
<tr>
|
|
667
|
+
<td>Example</td>
|
|
668
|
+
<td><tt>sass :stylesheet, :style => :expanded</tt></td>
|
|
669
|
+
</tr>
|
|
670
|
+
</table>
|
|
671
|
+
|
|
672
|
+
#### Scss Templates
|
|
673
|
+
|
|
674
|
+
<table>
|
|
675
|
+
<tr>
|
|
676
|
+
<td>Dependency</td>
|
|
677
|
+
<td><a href="https://github.com/ntkme/sass-embedded-host-ruby" title="sass-embedded">sass-embedded</a></td>
|
|
678
|
+
</tr>
|
|
679
|
+
<tr>
|
|
680
|
+
<td>File Extension</td>
|
|
681
|
+
<td><tt>.scss</tt></td>
|
|
682
|
+
</tr>
|
|
683
|
+
<tr>
|
|
684
|
+
<td>Example</td>
|
|
685
|
+
<td><tt>scss :stylesheet, :style => :expanded</tt></td>
|
|
686
|
+
</tr>
|
|
687
|
+
</table>
|
|
652
688
|
|
|
653
689
|
#### Liquid Templates
|
|
654
690
|
|
|
@@ -810,7 +846,7 @@ It also takes a block for inline templates (see [example](#inline-templates)).
|
|
|
810
846
|
<table>
|
|
811
847
|
<tr>
|
|
812
848
|
<td>Dependency</td>
|
|
813
|
-
<td><a href="
|
|
849
|
+
<td><a href="https://slim-template.github.io/" title="Slim Lang">Slim Lang</a></td>
|
|
814
850
|
</tr>
|
|
815
851
|
<tr>
|
|
816
852
|
<td>File Extension</td>
|
|
@@ -1163,22 +1199,6 @@ $ ruby -e "require 'securerandom'; puts SecureRandom.hex(64)"
|
|
|
1163
1199
|
99ae8af...snip...ec0f262ac
|
|
1164
1200
|
```
|
|
1165
1201
|
|
|
1166
|
-
**Session Secret Generation (Bonus Points)**
|
|
1167
|
-
|
|
1168
|
-
Use the [sysrandom gem](https://github.com/cryptosphere/sysrandom#readme) to
|
|
1169
|
-
use the system RNG facilities to generate random values instead of
|
|
1170
|
-
userspace `OpenSSL` which MRI Ruby currently defaults to:
|
|
1171
|
-
|
|
1172
|
-
```text
|
|
1173
|
-
$ gem install sysrandom
|
|
1174
|
-
Building native extensions. This could take a while...
|
|
1175
|
-
Successfully installed sysrandom-1.x
|
|
1176
|
-
1 gem installed
|
|
1177
|
-
|
|
1178
|
-
$ ruby -e "require 'sysrandom/securerandom'; puts SecureRandom.hex(64)"
|
|
1179
|
-
99ae8af...snip...ec0f262ac
|
|
1180
|
-
```
|
|
1181
|
-
|
|
1182
1202
|
**Session Secret Environment Variable**
|
|
1183
1203
|
|
|
1184
1204
|
Set a `SESSION_SECRET` environment variable for Sinatra to the value you
|
|
@@ -1193,14 +1213,10 @@ purposes only:
|
|
|
1193
1213
|
**Session Secret App Config**
|
|
1194
1214
|
|
|
1195
1215
|
Set up your app config to fail-safe to a secure random secret
|
|
1196
|
-
if the `SESSION_SECRET` environment variable is not available
|
|
1197
|
-
|
|
1198
|
-
For bonus points use the [sysrandom
|
|
1199
|
-
gem](https://github.com/cryptosphere/sysrandom#readme) here as well:
|
|
1216
|
+
if the `SESSION_SECRET` environment variable is not available:
|
|
1200
1217
|
|
|
1201
1218
|
```ruby
|
|
1202
1219
|
require 'securerandom'
|
|
1203
|
-
# -or- require 'sysrandom/securerandom'
|
|
1204
1220
|
set :session_secret, ENV.fetch('SESSION_SECRET') { SecureRandom.hex(64) }
|
|
1205
1221
|
```
|
|
1206
1222
|
|
|
@@ -1405,53 +1421,9 @@ to `stream` finishes executing. Streaming does not work at all with Shotgun.
|
|
|
1405
1421
|
|
|
1406
1422
|
If the optional parameter is set to `keep_open`, it will not call `close` on
|
|
1407
1423
|
the stream object, allowing you to close it at any later point in the
|
|
1408
|
-
execution flow.
|
|
1409
|
-
Other servers will still close the stream:
|
|
1410
|
-
|
|
1411
|
-
```ruby
|
|
1412
|
-
# config.ru
|
|
1413
|
-
require 'sinatra/base'
|
|
1414
|
-
|
|
1415
|
-
class App < Sinatra::Base
|
|
1416
|
-
connections = []
|
|
1424
|
+
execution flow.
|
|
1417
1425
|
|
|
1418
|
-
|
|
1419
|
-
# register a client's interest in server events
|
|
1420
|
-
stream(:keep_open) do |out|
|
|
1421
|
-
connections << out
|
|
1422
|
-
# purge dead connections
|
|
1423
|
-
connections.reject!(&:closed?)
|
|
1424
|
-
end
|
|
1425
|
-
end
|
|
1426
|
-
|
|
1427
|
-
post '/' do
|
|
1428
|
-
connections.each do |out|
|
|
1429
|
-
# notify client that a new message has arrived
|
|
1430
|
-
out << "data: #{params[:msg]}\n\n"
|
|
1431
|
-
|
|
1432
|
-
# indicate client to connect again
|
|
1433
|
-
out.close
|
|
1434
|
-
end
|
|
1435
|
-
|
|
1436
|
-
204 # response without entity body
|
|
1437
|
-
end
|
|
1438
|
-
end
|
|
1439
|
-
|
|
1440
|
-
run App
|
|
1441
|
-
```
|
|
1442
|
-
|
|
1443
|
-
```ruby
|
|
1444
|
-
# rainbows.conf
|
|
1445
|
-
Rainbows! do
|
|
1446
|
-
use :EventMachine
|
|
1447
|
-
end
|
|
1448
|
-
````
|
|
1449
|
-
|
|
1450
|
-
Run:
|
|
1451
|
-
|
|
1452
|
-
```shell
|
|
1453
|
-
rainbows -c rainbows.conf
|
|
1454
|
-
```
|
|
1426
|
+
You can have a look at the [chat example](https://github.com/sinatra/sinatra/blob/main/examples/chat.rb)
|
|
1455
1427
|
|
|
1456
1428
|
It's also possible for the client to close the connection when trying to
|
|
1457
1429
|
write to the socket. Because of this, it's recommended to check
|
|
@@ -1950,7 +1922,7 @@ set :protection, :except => :path_traversal
|
|
|
1950
1922
|
You can also hand in an array in order to disable a list of protections:
|
|
1951
1923
|
|
|
1952
1924
|
```ruby
|
|
1953
|
-
set :protection, :except => [:path_traversal, :
|
|
1925
|
+
set :protection, :except => [:path_traversal, :remote_token]
|
|
1954
1926
|
```
|
|
1955
1927
|
|
|
1956
1928
|
By default, Sinatra will only set up session based protection if `:sessions`
|
|
@@ -2089,9 +2061,13 @@ set :protection, :session => true
|
|
|
2089
2061
|
|
|
2090
2062
|
<dt>raise_errors</dt>
|
|
2091
2063
|
<dd>
|
|
2092
|
-
Raise
|
|
2064
|
+
Raise unhandled errors (will stop application). Enabled by default when
|
|
2093
2065
|
<tt>environment</tt> is set to <tt>"test"</tt>, disabled otherwise.
|
|
2094
2066
|
</dd>
|
|
2067
|
+
<dd>
|
|
2068
|
+
Any explicitly defined error handlers always override this setting. See
|
|
2069
|
+
the "Error" section below.
|
|
2070
|
+
</dd>
|
|
2095
2071
|
|
|
2096
2072
|
<dt>run</dt>
|
|
2097
2073
|
<dd>
|
|
@@ -2184,6 +2160,24 @@ set :protection, :session => true
|
|
|
2184
2160
|
</dd>
|
|
2185
2161
|
</dl>
|
|
2186
2162
|
|
|
2163
|
+
## Lifecycle Events
|
|
2164
|
+
|
|
2165
|
+
There are 2 lifecycle events currently exposed by Sinatra. One when the server starts and one when it stops.
|
|
2166
|
+
|
|
2167
|
+
They can be used like this:
|
|
2168
|
+
|
|
2169
|
+
```ruby
|
|
2170
|
+
on_start do
|
|
2171
|
+
puts "===== Booting up ====="
|
|
2172
|
+
end
|
|
2173
|
+
|
|
2174
|
+
on_stop do
|
|
2175
|
+
puts "===== Shutting down ====="
|
|
2176
|
+
end
|
|
2177
|
+
```
|
|
2178
|
+
|
|
2179
|
+
Note that these callbacks only work when using Sinatra to start the web server.
|
|
2180
|
+
|
|
2187
2181
|
## Environments
|
|
2188
2182
|
|
|
2189
2183
|
There are three predefined `environments`: `"development"`,
|
|
@@ -2240,6 +2234,14 @@ show exceptions option to `:after_handler`:
|
|
|
2240
2234
|
set :show_exceptions, :after_handler
|
|
2241
2235
|
```
|
|
2242
2236
|
|
|
2237
|
+
A catch-all error handler can be defined with `error` and a block:
|
|
2238
|
+
|
|
2239
|
+
```ruby
|
|
2240
|
+
error do
|
|
2241
|
+
'Sorry there was a nasty error'
|
|
2242
|
+
end
|
|
2243
|
+
```
|
|
2244
|
+
|
|
2243
2245
|
The exception object can be obtained from the `sinatra.error` Rack variable:
|
|
2244
2246
|
|
|
2245
2247
|
```ruby
|
|
@@ -2248,7 +2250,7 @@ error do
|
|
|
2248
2250
|
end
|
|
2249
2251
|
```
|
|
2250
2252
|
|
|
2251
|
-
|
|
2253
|
+
Pass an error class as an argument to create handlers for custom errors:
|
|
2252
2254
|
|
|
2253
2255
|
```ruby
|
|
2254
2256
|
error MyCustomError do
|
|
@@ -2294,6 +2296,51 @@ Sinatra installs special `not_found` and `error` handlers when
|
|
|
2294
2296
|
running under the development environment to display nice stack traces
|
|
2295
2297
|
and additional debugging information in your browser.
|
|
2296
2298
|
|
|
2299
|
+
### Behavior with `raise_errors` option
|
|
2300
|
+
|
|
2301
|
+
When `raise_errors` option is `true`, errors that are unhandled are raised
|
|
2302
|
+
outside of the application. Additionally, any errors that would have been
|
|
2303
|
+
caught by the catch-all error handler are raised.
|
|
2304
|
+
|
|
2305
|
+
For example, consider the following configuration:
|
|
2306
|
+
|
|
2307
|
+
```ruby
|
|
2308
|
+
# First handler
|
|
2309
|
+
error MyCustomError do
|
|
2310
|
+
'A custom message'
|
|
2311
|
+
end
|
|
2312
|
+
|
|
2313
|
+
# Second handler
|
|
2314
|
+
error do
|
|
2315
|
+
'A catch-all message'
|
|
2316
|
+
end
|
|
2317
|
+
```
|
|
2318
|
+
|
|
2319
|
+
If `raise_errors` is `false`:
|
|
2320
|
+
|
|
2321
|
+
* When `MyCustomError` or descendant is raised, the first handler is invoked.
|
|
2322
|
+
The HTTP response body will contain `"A custom message"`.
|
|
2323
|
+
* When any other error is raised, the second handler is invoked. The HTTP
|
|
2324
|
+
response body will contain `"A catch-all message"`.
|
|
2325
|
+
|
|
2326
|
+
If `raise_errors` is `true`:
|
|
2327
|
+
|
|
2328
|
+
* When `MyCustomError` or descendant is raised, the behavior is identical to
|
|
2329
|
+
when `raise_errors` is `false`, described above.
|
|
2330
|
+
* When any other error is raised, the second handler is *not* invoked, and
|
|
2331
|
+
the error is raised outside of the application.
|
|
2332
|
+
* If the environment is `production`, the HTTP response body will contain
|
|
2333
|
+
a generic error message, e.g. `"An unhandled lowlevel error occurred. The
|
|
2334
|
+
application logs may have details."`
|
|
2335
|
+
* If the environment is not `production`, the HTTP response body will contain
|
|
2336
|
+
the verbose error backtrace.
|
|
2337
|
+
* Regardless of environment, if `show_exceptions` is set to `:after_handler`,
|
|
2338
|
+
the HTTP response body will contain the verbose error backtrace.
|
|
2339
|
+
|
|
2340
|
+
In the `test` environment, `raise_errors` is set to `true` by default. This
|
|
2341
|
+
means that in order to write a test for a catch-all error handler,
|
|
2342
|
+
`raise_errors` must temporarily be set to `false` for that particular test.
|
|
2343
|
+
|
|
2297
2344
|
## Rack Middleware
|
|
2298
2345
|
|
|
2299
2346
|
Sinatra rides on [Rack](https://rack.github.io/), a minimal standard
|
|
@@ -2767,68 +2814,30 @@ by Konstantin_
|
|
|
2767
2814
|
Sinatra doesn't impose any concurrency model but leaves that to the
|
|
2768
2815
|
underlying Rack handler (server) like Puma or WEBrick. Sinatra
|
|
2769
2816
|
itself is thread-safe, so there won't be any problem if the Rack handler
|
|
2770
|
-
uses a threaded model of concurrency.
|
|
2771
|
-
the server, you'd have to specify the correct invocation method for the
|
|
2772
|
-
specific Rack handler. The following example is a demonstration of how
|
|
2773
|
-
to start a multi-threaded Rainbows server:
|
|
2774
|
-
|
|
2775
|
-
```ruby
|
|
2776
|
-
# config.ru
|
|
2777
|
-
|
|
2778
|
-
require 'sinatra/base'
|
|
2779
|
-
|
|
2780
|
-
class App < Sinatra::Base
|
|
2781
|
-
get '/' do
|
|
2782
|
-
"Hello, World"
|
|
2783
|
-
end
|
|
2784
|
-
end
|
|
2785
|
-
|
|
2786
|
-
run App
|
|
2787
|
-
```
|
|
2788
|
-
|
|
2789
|
-
```ruby
|
|
2790
|
-
# rainbows.conf
|
|
2791
|
-
|
|
2792
|
-
# Rainbows configurator is based on Unicorn.
|
|
2793
|
-
Rainbows! do
|
|
2794
|
-
use :ThreadSpawn
|
|
2795
|
-
end
|
|
2796
|
-
```
|
|
2797
|
-
|
|
2798
|
-
To start the server, the command would be:
|
|
2799
|
-
|
|
2800
|
-
```shell
|
|
2801
|
-
rainbows -c rainbows.conf
|
|
2802
|
-
```
|
|
2817
|
+
uses a threaded model of concurrency.
|
|
2803
2818
|
|
|
2804
2819
|
## Requirement
|
|
2805
2820
|
|
|
2806
2821
|
The following Ruby versions are officially supported:
|
|
2807
2822
|
<dl>
|
|
2808
|
-
<dt>Ruby
|
|
2823
|
+
<dt>Ruby</dt>
|
|
2809
2824
|
<dd>
|
|
2810
|
-
|
|
2811
|
-
drop official support for it.
|
|
2825
|
+
<a href="https://www.ruby-lang.org/en/downloads/">The stable releases</a> are fully supported and recommended.
|
|
2812
2826
|
</dd>
|
|
2813
2827
|
|
|
2814
|
-
<dt>
|
|
2828
|
+
<dt>TruffleRuby</dt>
|
|
2815
2829
|
<dd>
|
|
2816
|
-
|
|
2817
|
-
<tt>gem install puma</tt>.
|
|
2830
|
+
The latest stable release of TruffleRuby is supported.
|
|
2818
2831
|
</dd>
|
|
2819
2832
|
|
|
2820
2833
|
<dt>JRuby</dt>
|
|
2821
2834
|
<dd>
|
|
2822
|
-
The latest stable release of JRuby is
|
|
2823
|
-
recommended to use C extensions with JRuby.
|
|
2824
|
-
<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.
|
|
2825
2837
|
</dd>
|
|
2826
2838
|
</dl>
|
|
2827
2839
|
|
|
2828
|
-
Versions of Ruby before 2.
|
|
2829
|
-
|
|
2830
|
-
We also keep an eye on upcoming Ruby versions. Expect upcoming
|
|
2831
|
-
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.
|
|
2832
2841
|
|
|
2833
2842
|
Sinatra should work on any operating system supported by the chosen Ruby
|
|
2834
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
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -I ../lib -I lib
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'sinatra'
|
|
5
|
+
|
|
6
|
+
get('/') do
|
|
7
|
+
'This shows how lifecycle events work'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
on_start do
|
|
11
|
+
puts "=============="
|
|
12
|
+
puts " Booting up"
|
|
13
|
+
puts "=============="
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
on_stop do
|
|
17
|
+
puts "================="
|
|
18
|
+
puts " Shutting down"
|
|
19
|
+
puts "================="
|
|
20
|
+
end
|
data/examples/stream.ru
CHANGED
|
@@ -4,10 +4,8 @@
|
|
|
4
4
|
#
|
|
5
5
|
# run *one* of these:
|
|
6
6
|
#
|
|
7
|
-
# rackup -s mongrel stream.ru # gem install mongrel
|
|
8
7
|
# unicorn stream.ru # gem install unicorn
|
|
9
8
|
# puma stream.ru # gem install puma
|
|
10
|
-
# rainbows -c rainbows.conf stream.ru # gem install rainbows eventmachine
|
|
11
9
|
|
|
12
10
|
require 'sinatra/base'
|
|
13
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 '
|
|
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
|
|
@@ -726,7 +731,7 @@ module Sinatra
|
|
|
726
731
|
# Possible options are:
|
|
727
732
|
# :content_type The content type to use, same arguments as content_type.
|
|
728
733
|
# :layout If set to something falsy, no layout is rendered, otherwise
|
|
729
|
-
# the specified layout is used
|
|
734
|
+
# the specified layout is used (Ignored for `sass`)
|
|
730
735
|
# :layout_engine Engine to use for rendering the layout.
|
|
731
736
|
# :locals A hash with local variables that should be available
|
|
732
737
|
# in the template
|
|
@@ -752,6 +757,20 @@ module Sinatra
|
|
|
752
757
|
render(:haml, template, options, locals, &block)
|
|
753
758
|
end
|
|
754
759
|
|
|
760
|
+
def sass(template, options = {}, locals = {})
|
|
761
|
+
options[:default_content_type] = :css
|
|
762
|
+
options[:exclude_outvar] = true
|
|
763
|
+
options[:layout] = nil
|
|
764
|
+
render :sass, template, options, locals
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
def scss(template, options = {}, locals = {})
|
|
768
|
+
options[:default_content_type] = :css
|
|
769
|
+
options[:exclude_outvar] = true
|
|
770
|
+
options[:layout] = nil
|
|
771
|
+
render :scss, template, options, locals
|
|
772
|
+
end
|
|
773
|
+
|
|
755
774
|
def builder(template = nil, options = {}, locals = {}, &block)
|
|
756
775
|
options[:default_content_type] = :xml
|
|
757
776
|
render_ruby(:builder, template, options, locals, &block)
|
|
@@ -862,7 +881,11 @@ module Sinatra
|
|
|
862
881
|
catch(:layout_missing) { return render(layout_engine, layout, options, locals) { output } }
|
|
863
882
|
end
|
|
864
883
|
|
|
865
|
-
|
|
884
|
+
if content_type
|
|
885
|
+
# sass-embedded returns a frozen string
|
|
886
|
+
output = +output
|
|
887
|
+
output.extend(ContentTyped).content_type = content_type
|
|
888
|
+
end
|
|
866
889
|
output
|
|
867
890
|
end
|
|
868
891
|
|
|
@@ -914,6 +937,35 @@ module Sinatra
|
|
|
914
937
|
end
|
|
915
938
|
end
|
|
916
939
|
|
|
940
|
+
# Extremely simple template cache implementation.
|
|
941
|
+
# * Not thread-safe.
|
|
942
|
+
# * Size is unbounded.
|
|
943
|
+
# * Keys are not copied defensively, and should not be modified after
|
|
944
|
+
# being passed to #fetch. More specifically, the values returned by
|
|
945
|
+
# key#hash and key#eql? should not change.
|
|
946
|
+
#
|
|
947
|
+
# Implementation copied from Tilt::Cache.
|
|
948
|
+
class TemplateCache
|
|
949
|
+
def initialize
|
|
950
|
+
@cache = {}
|
|
951
|
+
end
|
|
952
|
+
|
|
953
|
+
# Caches a value for key, or returns the previously cached value.
|
|
954
|
+
# If a value has been previously cached for key then it is
|
|
955
|
+
# returned. Otherwise, block is yielded to and its return value
|
|
956
|
+
# which may be nil, is cached under key and returned.
|
|
957
|
+
def fetch(*key)
|
|
958
|
+
@cache.fetch(key) do
|
|
959
|
+
@cache[key] = yield
|
|
960
|
+
end
|
|
961
|
+
end
|
|
962
|
+
|
|
963
|
+
# Clears the cache.
|
|
964
|
+
def clear
|
|
965
|
+
@cache = {}
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
|
|
917
969
|
# Base class for all Sinatra applications and middleware.
|
|
918
970
|
class Base
|
|
919
971
|
include Rack::Utils
|
|
@@ -928,7 +980,7 @@ module Sinatra
|
|
|
928
980
|
def initialize(app = nil, **_kwargs)
|
|
929
981
|
super()
|
|
930
982
|
@app = app
|
|
931
|
-
@template_cache =
|
|
983
|
+
@template_cache = TemplateCache.new
|
|
932
984
|
@pinned_response = nil # whether a before! filter pinned the content-type
|
|
933
985
|
yield self if block_given?
|
|
934
986
|
end
|
|
@@ -949,7 +1001,7 @@ module Sinatra
|
|
|
949
1001
|
invoke { dispatch! }
|
|
950
1002
|
invoke { error_block!(response.status) } unless @env['sinatra.error']
|
|
951
1003
|
|
|
952
|
-
unless @response['
|
|
1004
|
+
unless @response['content-type']
|
|
953
1005
|
if Array === body && body[0].respond_to?(:content_type)
|
|
954
1006
|
content_type body[0].content_type
|
|
955
1007
|
elsif (default = settings.default_content_type)
|
|
@@ -1012,7 +1064,7 @@ module Sinatra
|
|
|
1012
1064
|
routes = base.routes[@request.request_method]
|
|
1013
1065
|
|
|
1014
1066
|
routes&.each do |pattern, conditions, block|
|
|
1015
|
-
response.delete_header('
|
|
1067
|
+
response.delete_header('content-type') unless @pinned_response
|
|
1016
1068
|
|
|
1017
1069
|
returned_pass_block = process_route(pattern, conditions) do |*args|
|
|
1018
1070
|
env['sinatra.route'] = "#{@request.request_method} #{pattern}"
|
|
@@ -1133,7 +1185,7 @@ module Sinatra
|
|
|
1133
1185
|
invoke do
|
|
1134
1186
|
static! if settings.static? && (request.get? || request.head?)
|
|
1135
1187
|
filter! :before do
|
|
1136
|
-
@pinned_response = !response['
|
|
1188
|
+
@pinned_response = !response['content-type'].nil?
|
|
1137
1189
|
end
|
|
1138
1190
|
route!
|
|
1139
1191
|
end
|
|
@@ -1214,7 +1266,19 @@ module Sinatra
|
|
|
1214
1266
|
end
|
|
1215
1267
|
|
|
1216
1268
|
def dump_errors!(boom)
|
|
1217
|
-
|
|
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")
|
|
1218
1282
|
@env['rack.errors'].puts(msg)
|
|
1219
1283
|
end
|
|
1220
1284
|
|
|
@@ -1223,6 +1287,7 @@ module Sinatra
|
|
|
1223
1287
|
%r{/sinatra(/(base|main|show_exceptions))?\.rb$}, # all sinatra code
|
|
1224
1288
|
%r{lib/tilt.*\.rb$}, # all tilt code
|
|
1225
1289
|
/^\(.*\)$/, # generated code
|
|
1290
|
+
/\/bundled_gems.rb$/, # ruby >= 3.3 with bundler >= 2.5
|
|
1226
1291
|
%r{rubygems/(custom|core_ext/kernel)_require\.rb$}, # rubygems require hacks
|
|
1227
1292
|
/active_support/, # active_support require hacks
|
|
1228
1293
|
%r{bundler(/(?:runtime|inline))?\.rb}, # bundler require hacks
|
|
@@ -1230,7 +1295,7 @@ module Sinatra
|
|
|
1230
1295
|
%r{zeitwerk/kernel\.rb} # Zeitwerk kernel#require decorator
|
|
1231
1296
|
].freeze
|
|
1232
1297
|
|
|
1233
|
-
attr_reader :routes, :filters, :templates, :errors
|
|
1298
|
+
attr_reader :routes, :filters, :templates, :errors, :on_start_callback, :on_stop_callback
|
|
1234
1299
|
|
|
1235
1300
|
def callers_to_ignore
|
|
1236
1301
|
CALLERS_TO_IGNORE
|
|
@@ -1401,7 +1466,13 @@ module Sinatra
|
|
|
1401
1466
|
# mime_types :js # => ['application/javascript', 'text/javascript']
|
|
1402
1467
|
def mime_types(type)
|
|
1403
1468
|
type = mime_type type
|
|
1404
|
-
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
|
|
1405
1476
|
end
|
|
1406
1477
|
|
|
1407
1478
|
# Define a before filter; runs before all requests within the same
|
|
@@ -1423,6 +1494,14 @@ module Sinatra
|
|
|
1423
1494
|
filters[type] << compile!(type, path, block, **options)
|
|
1424
1495
|
end
|
|
1425
1496
|
|
|
1497
|
+
def on_start(&on_start_callback)
|
|
1498
|
+
@on_start_callback = on_start_callback
|
|
1499
|
+
end
|
|
1500
|
+
|
|
1501
|
+
def on_stop(&on_stop_callback)
|
|
1502
|
+
@on_stop_callback = on_stop_callback
|
|
1503
|
+
end
|
|
1504
|
+
|
|
1426
1505
|
# Add a route condition. The route is considered non-matching when the
|
|
1427
1506
|
# block returns false.
|
|
1428
1507
|
def condition(name = "#{caller.first[/`.*'/]} condition", &block)
|
|
@@ -1512,18 +1591,37 @@ module Sinatra
|
|
|
1512
1591
|
warn '== Sinatra has ended his set (crowd applauds)' unless suppress_messages?
|
|
1513
1592
|
set :running_server, nil
|
|
1514
1593
|
set :handler_name, nil
|
|
1594
|
+
|
|
1595
|
+
on_stop_callback.call unless on_stop_callback.nil?
|
|
1515
1596
|
end
|
|
1516
1597
|
|
|
1517
1598
|
alias stop! quit!
|
|
1518
1599
|
|
|
1519
1600
|
# Run the Sinatra app as a self-hosted server using
|
|
1520
|
-
# Puma, Falcon,
|
|
1601
|
+
# Puma, Falcon, or WEBrick (in that order). If given a block, will call
|
|
1521
1602
|
# with the constructed handler once we have taken the stage.
|
|
1522
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
|
+
|
|
1523
1621
|
return if running?
|
|
1524
1622
|
|
|
1525
1623
|
set options
|
|
1526
|
-
handler =
|
|
1624
|
+
handler = Rackup::Handler.pick(server)
|
|
1527
1625
|
handler_name = handler.name.gsub(/.*::/, '')
|
|
1528
1626
|
server_settings = settings.respond_to?(:server_settings) ? settings.server_settings : {}
|
|
1529
1627
|
server_settings.merge!(Port: port, Host: bind)
|
|
@@ -1599,7 +1697,7 @@ module Sinatra
|
|
|
1599
1697
|
set :running_server, server
|
|
1600
1698
|
set :handler_name, handler_name
|
|
1601
1699
|
server.threaded = settings.threaded if server.respond_to? :threaded=
|
|
1602
|
-
|
|
1700
|
+
on_start_callback.call unless on_start_callback.nil?
|
|
1603
1701
|
yield server if block_given?
|
|
1604
1702
|
end
|
|
1605
1703
|
end
|
|
@@ -1655,7 +1753,7 @@ module Sinatra
|
|
|
1655
1753
|
types.map! { |t| mime_types(t) }
|
|
1656
1754
|
types.flatten!
|
|
1657
1755
|
condition do
|
|
1658
|
-
response_content_type = response['
|
|
1756
|
+
response_content_type = response['content-type']
|
|
1659
1757
|
preferred_type = request.preferred_type(types)
|
|
1660
1758
|
|
|
1661
1759
|
if response_content_type
|
|
@@ -1832,7 +1930,7 @@ module Sinatra
|
|
|
1832
1930
|
set :dump_errors, proc { !test? }
|
|
1833
1931
|
set :show_exceptions, proc { development? }
|
|
1834
1932
|
set :sessions, false
|
|
1835
|
-
set :session_store, Rack::
|
|
1933
|
+
set :session_store, Rack::Session::Cookie
|
|
1836
1934
|
set :logging, false
|
|
1837
1935
|
set :protection, true
|
|
1838
1936
|
set :method_override, false
|
|
@@ -1870,11 +1968,10 @@ module Sinatra
|
|
|
1870
1968
|
|
|
1871
1969
|
ruby_engine = defined?(RUBY_ENGINE) && RUBY_ENGINE
|
|
1872
1970
|
|
|
1873
|
-
server.unshift 'puma'
|
|
1874
|
-
server.unshift 'falcon' if ruby_engine != 'jruby'
|
|
1875
|
-
server.unshift 'mongrel' if ruby_engine.nil?
|
|
1876
1971
|
server.unshift 'thin' if ruby_engine != 'jruby'
|
|
1972
|
+
server.unshift 'falcon' if ruby_engine != 'jruby'
|
|
1877
1973
|
server.unshift 'trinidad' if ruby_engine == 'jruby'
|
|
1974
|
+
server.unshift 'puma'
|
|
1878
1975
|
|
|
1879
1976
|
set :absolute_redirects, true
|
|
1880
1977
|
set :prefixed_redirects, false
|
|
@@ -1939,7 +2036,7 @@ module Sinatra
|
|
|
1939
2036
|
</head>
|
|
1940
2037
|
<body>
|
|
1941
2038
|
<h2>Sinatra doesn’t know this ditty.</h2>
|
|
1942
|
-
<img src='#{
|
|
2039
|
+
<img src='#{request.script_name}/__sinatra__/404.png'>
|
|
1943
2040
|
<div id="c">
|
|
1944
2041
|
Try this:
|
|
1945
2042
|
<pre>#{Rack::Utils.escape_html(code)}</pre>
|
|
@@ -1991,7 +2088,7 @@ module Sinatra
|
|
|
1991
2088
|
delegate :get, :patch, :put, :post, :delete, :head, :options, :link, :unlink,
|
|
1992
2089
|
:template, :layout, :before, :after, :error, :not_found, :configure,
|
|
1993
2090
|
:set, :mime_type, :enable, :disable, :use, :development?, :test?,
|
|
1994
|
-
:production?, :helpers, :settings, :register
|
|
2091
|
+
:production?, :helpers, :settings, :register, :on_start, :on_stop
|
|
1995
2092
|
|
|
1996
2093
|
class << self
|
|
1997
2094
|
attr_accessor :target
|
|
@@ -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
|
|
@@ -110,8 +116,7 @@ files:
|
|
|
110
116
|
- SECURITY.md
|
|
111
117
|
- VERSION
|
|
112
118
|
- examples/chat.rb
|
|
113
|
-
- examples/
|
|
114
|
-
- examples/rainbows.rb
|
|
119
|
+
- examples/lifecycle_events.rb
|
|
115
120
|
- examples/simple.rb
|
|
116
121
|
- examples/stream.ru
|
|
117
122
|
- lib/sinatra.rb
|
|
@@ -133,7 +138,7 @@ metadata:
|
|
|
133
138
|
bug_tracker_uri: https://github.com/sinatra/sinatra/issues
|
|
134
139
|
mailing_list_uri: http://groups.google.com/group/sinatrarb
|
|
135
140
|
documentation_uri: https://www.rubydoc.info/gems/sinatra
|
|
136
|
-
post_install_message:
|
|
141
|
+
post_install_message:
|
|
137
142
|
rdoc_options:
|
|
138
143
|
- "--line-numbers"
|
|
139
144
|
- "--title"
|
|
@@ -147,15 +152,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
147
152
|
requirements:
|
|
148
153
|
- - ">="
|
|
149
154
|
- !ruby/object:Gem::Version
|
|
150
|
-
version: 2.
|
|
155
|
+
version: 2.7.8
|
|
151
156
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
157
|
requirements:
|
|
153
158
|
- - ">="
|
|
154
159
|
- !ruby/object:Gem::Version
|
|
155
160
|
version: '0'
|
|
156
161
|
requirements: []
|
|
157
|
-
rubygems_version: 3.
|
|
158
|
-
signing_key:
|
|
162
|
+
rubygems_version: 3.5.3
|
|
163
|
+
signing_key:
|
|
159
164
|
specification_version: 4
|
|
160
165
|
summary: Classy web-development dressed in a DSL
|
|
161
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
|