rack 3.1.14 → 3.1.18
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/CHANGELOG.md +85 -14
- data/README.md +8 -0
- data/lib/rack/mock_response.rb +32 -3
- data/lib/rack/multipart/parser.rb +57 -5
- data/lib/rack/query_parser.rb +3 -1
- data/lib/rack/request.rb +4 -1
- data/lib/rack/sendfile.rb +50 -20
- data/lib/rack/version.rb +1 -1
- metadata +4 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 627b4fe8d3af482f544229eaa2a32868adf887decbc3616669646c0ecdb514e5
|
4
|
+
data.tar.gz: f5c0b0b49232d4dd4630e4ccf71f30a322bf7cf91f8e38711e9a203b2e2c03c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f61477c3fc2f135ee874290de05f1c18c015fe9285348e5d673a41d86782bd00f61f83d8fea2a81af15158e3d87acea8c2edcf5600c7e292df79c2e40480f98
|
7
|
+
data.tar.gz: 6e22900f3d703d4db6d14e4a7960a52f835df19df2796cf1669e1c4415b4243a5e9097cf87ab1b37102090a98109408524ca6c2762a77f69eeda9755ed47aef1
|
data/CHANGELOG.md
CHANGED
@@ -2,11 +2,36 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file. For info on how to format all future additions to this file please reference [Keep A Changelog](https://keepachangelog.com/en/1.0.0/).
|
4
4
|
|
5
|
+
## [3.1.18] - 2025-10-10
|
6
|
+
|
7
|
+
### Security
|
8
|
+
|
9
|
+
- [CVE-2025-61780](https://github.com/advisories/GHSA-r657-rxjc-j557) Improper handling of headers in `Rack::Sendfile` may allow proxy bypass.
|
10
|
+
- [CVE-2025-61919](https://github.com/advisories/GHSA-6xw4-3v39-52mm) Unbounded read in `Rack::Request` form parsing can lead to memory exhaustion.
|
11
|
+
|
12
|
+
## [3.1.17] - 2025-10-07
|
13
|
+
|
14
|
+
### Security
|
15
|
+
|
16
|
+
- [CVE-2025-61772](https://github.com/advisories/GHSA-wpv5-97wm-hp9c) Multipart parser buffers unbounded per-part headers, enabling DoS (memory exhaustion)
|
17
|
+
- [CVE-2025-61771](https://github.com/advisories/GHSA-w9pc-fmgc-vxvw) Multipart parser buffers large non‑file fields entirely in memory, enabling DoS (memory exhaustion)
|
18
|
+
- [CVE-2025-61770](https://github.com/advisories/GHSA-p543-xpfm-54cp) Unbounded multipart preamble buffering enables DoS (memory exhaustion)
|
19
|
+
|
20
|
+
## [3.1.16] - 2025-06-04
|
21
|
+
|
22
|
+
### Security
|
23
|
+
|
24
|
+
- [CVE-2025-49007](https://github.com/advisories/GHSA-47m2-26rw-j2jw) Fix ReDoS in multipart request.
|
25
|
+
|
26
|
+
## [3.1.15] - 2025-05-18
|
27
|
+
|
28
|
+
- Optional support for `CGI::Cookie` if not available. ([#2327](https://github.com/rack/rack/pull/2327), [#2333](https://github.com/rack/rack/pull/2333), [@earlopain])
|
29
|
+
|
5
30
|
## [3.1.14] - 2025-05-06
|
6
31
|
|
7
32
|
### Security
|
8
33
|
|
9
|
-
- [CVE-2025-46727](https://github.com/
|
34
|
+
- [CVE-2025-46727](https://github.com/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
|
10
35
|
|
11
36
|
## [3.1.13] - 2025-04-13
|
12
37
|
|
@@ -16,19 +41,19 @@ All notable changes to this project will be documented in this file. For info on
|
|
16
41
|
|
17
42
|
### Security
|
18
43
|
|
19
|
-
- [CVE-2025-27610](https://github.com/
|
44
|
+
- [CVE-2025-27610](https://github.com/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
|
20
45
|
|
21
46
|
## [3.1.11] - 2025-03-04
|
22
47
|
|
23
48
|
### Security
|
24
49
|
|
25
|
-
- [CVE-2025-27111](https://github.com/
|
50
|
+
- [CVE-2025-27111](https://github.com/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
|
26
51
|
|
27
52
|
## [3.1.10] - 2025-02-12
|
28
53
|
|
29
54
|
### Security
|
30
55
|
|
31
|
-
- [CVE-2025-25184](https://github.com/
|
56
|
+
- [CVE-2025-25184](https://github.com/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
|
32
57
|
|
33
58
|
## [3.1.9] - 2025-01-31
|
34
59
|
|
@@ -61,7 +86,7 @@ All notable changes to this project will be documented in this file. For info on
|
|
61
86
|
|
62
87
|
### Security
|
63
88
|
|
64
|
-
- Fix potential ReDoS attack in `Rack::Request#parse_http_accept_header`. ([GHSA-cj83-2ww7-mvq7](https://github.com/
|
89
|
+
- Fix potential ReDoS attack in `Rack::Request#parse_http_accept_header`. ([GHSA-cj83-2ww7-mvq7](https://github.com/advisories/GHSA-cj83-2ww7-mvq7), [@dwisiswant0](https://github.com/dwisiswant0))
|
65
90
|
|
66
91
|
## [3.1.4] - 2024-06-22
|
67
92
|
|
@@ -139,11 +164,19 @@ Rack v3.1 is primarily a maintenance release that removes features deprecated in
|
|
139
164
|
|
140
165
|
- In `Rack::Files`, ignore the `Range` header if served file is 0 bytes. ([#2159](https://github.com/rack/rack/pull/2159), [@zarqman])
|
141
166
|
|
167
|
+
## [3.0.18] - 2025-05-22
|
168
|
+
|
169
|
+
- Fix incorrect backport of optional `CGI::Cookie` support. ([#2335](https://github.com/rack/rack/pull/2335), [@jeremyevans])
|
170
|
+
|
171
|
+
## [3.0.17] - 2025-05-18
|
172
|
+
|
173
|
+
- Optional support for `CGI::Cookie` if not available. ([#2327](https://github.com/rack/rack/pull/2327), [#2333](https://github.com/rack/rack/pull/2333), [@earlopain])
|
174
|
+
|
142
175
|
## [3.0.16] - 2025-05-06
|
143
176
|
|
144
177
|
### Security
|
145
178
|
|
146
|
-
- [CVE-2025-46727](https://github.com/
|
179
|
+
- [CVE-2025-46727](https://github.com/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
|
147
180
|
|
148
181
|
## [3.0.15] - 2025-04-13
|
149
182
|
|
@@ -153,19 +186,23 @@ Rack v3.1 is primarily a maintenance release that removes features deprecated in
|
|
153
186
|
|
154
187
|
### Security
|
155
188
|
|
156
|
-
- [CVE-2025-27610](https://github.com/
|
189
|
+
- [CVE-2025-27610](https://github.com/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
|
157
190
|
|
158
191
|
## [3.0.13] - 2025-03-04
|
159
192
|
|
160
193
|
### Security
|
161
194
|
|
162
|
-
- [CVE-2025-27111](https://github.com/
|
195
|
+
- [CVE-2025-27111](https://github.com/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
|
196
|
+
|
197
|
+
### Fixed
|
198
|
+
|
199
|
+
- Remove autoloads for constants no longer shipped with Rack. ([#2269](https://github.com/rack/rack/pull/2269), [@ccutrer](https://github.com/ccutrer))
|
163
200
|
|
164
201
|
## [3.0.12] - 2025-02-12
|
165
202
|
|
166
203
|
### Security
|
167
204
|
|
168
|
-
- [CVE-2025-25184](https://github.com/
|
205
|
+
- [CVE-2025-25184](https://github.com/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
|
169
206
|
|
170
207
|
## [3.0.11] - 2024-05-10
|
171
208
|
|
@@ -295,7 +332,7 @@ Rack v3.1 is primarily a maintenance release that removes features deprecated in
|
|
295
332
|
- Remove deprecated Rack::Request::SCHEME_WHITELIST. ([@jeremyevans])
|
296
333
|
- Remove internal cookie deletion using pattern matching, there are very few practical cases where it would be useful and browsers handle it correctly without us doing anything special. ([#1844](https://github.com/rack/rack/pull/1844), [@ioquatix])
|
297
334
|
- Remove `rack.version` as it comes too late to be useful. ([#1938](https://github.com/rack/rack/pull/1938), [@ioquatix])
|
298
|
-
- Extract `rackup` command, `Rack::Server`, `Rack::Handler
|
335
|
+
- Extract `rackup` command, `Rack::Server`, `Rack::Handler` and related code into a separate gem. ([#1937](https://github.com/rack/rack/pull/1937), [@ioquatix])
|
299
336
|
|
300
337
|
### Added
|
301
338
|
|
@@ -343,29 +380,62 @@ Rack v3.1 is primarily a maintenance release that removes features deprecated in
|
|
343
380
|
- Fix multipart filename generation for filenames that contain spaces. Encode spaces as "%20" instead of "+" which will be decoded properly by the multipart parser. ([#1736](https://github.com/rack/rack/pull/1645), [@muirdm](https://github.com/muirdm))
|
344
381
|
- `Rack::Request#scheme` returns `ws` or `wss` when one of the `X-Forwarded-Scheme` / `X-Forwarded-Proto` headers is set to `ws` or `wss`, respectively. ([#1730](https://github.com/rack/rack/issues/1730), [@erwanst](https://github.com/erwanst))
|
345
382
|
|
383
|
+
## [2.2.20] - 2025-10-10
|
384
|
+
|
385
|
+
### Security
|
386
|
+
|
387
|
+
- [CVE-2025-61780](https://github.com/advisories/GHSA-r657-rxjc-j557) Improper handling of headers in `Rack::Sendfile` may allow proxy bypass.
|
388
|
+
- [CVE-2025-61919](https://github.com/advisories/GHSA-6xw4-3v39-52mm) Unbounded read in `Rack::Request` form parsing can lead to memory exhaustion.
|
389
|
+
|
390
|
+
## [2.2.19] - 2025-10-07
|
391
|
+
|
392
|
+
### Security
|
393
|
+
|
394
|
+
- [CVE-2025-61772](https://github.com/advisories/GHSA-wpv5-97wm-hp9c) Multipart parser buffers unbounded per-part headers, enabling DoS (memory exhaustion)
|
395
|
+
- [CVE-2025-61771](https://github.com/advisories/GHSA-w9pc-fmgc-vxvw) Multipart parser buffers large non‑file fields entirely in memory, enabling DoS (memory exhaustion)
|
396
|
+
- [CVE-2025-61770](https://github.com/advisories/GHSA-p543-xpfm-54cp) Unbounded multipart preamble buffering enables DoS (memory exhaustion)
|
397
|
+
|
398
|
+
## [2.2.18] - 2025-09-25
|
399
|
+
|
400
|
+
### Security
|
401
|
+
|
402
|
+
- [CVE-2025-59830](https://github.com/advisories/GHSA-625h-95r8-8xpm) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion via semicolon-separated parameters.
|
403
|
+
|
404
|
+
## [2.2.17] - 2025-06-03
|
405
|
+
|
406
|
+
- Backport `Rack::MediaType#params` now handles parameters without values. ([#2263](https://github.com/rack/rack/pull/2263), [@AllyMarthaJ](https://github.com/AllyMarthaJ))
|
407
|
+
|
408
|
+
## [2.2.16] - 2025-05-22
|
409
|
+
|
410
|
+
- Fix incorrect backport of optional `CGI::Cookie` support. ([#2335](https://github.com/rack/rack/pull/2335), [@jeremyevans])
|
411
|
+
|
412
|
+
## [2.2.15] - 2025-05-18
|
413
|
+
|
414
|
+
- Optional support for `CGI::Cookie` if not available. ([#2327](https://github.com/rack/rack/pull/2327), [#2333](https://github.com/rack/rack/pull/2333), [@earlopain])
|
415
|
+
|
346
416
|
## [2.2.14] - 2025-05-06
|
347
417
|
|
348
418
|
### Security
|
349
419
|
|
350
|
-
- [CVE-2025-46727](https://github.com/
|
420
|
+
- [CVE-2025-46727](https://github.com/advisories/GHSA-gjh7-p2fx-99vx) Unbounded parameter parsing in `Rack::QueryParser` can lead to memory exhaustion.
|
351
421
|
|
352
422
|
## [2.2.13] - 2025-03-11
|
353
423
|
|
354
424
|
### Security
|
355
425
|
|
356
|
-
- [CVE-2025-27610](https://github.com/
|
426
|
+
- [CVE-2025-27610](https://github.com/advisories/GHSA-7wqh-767x-r66v) Local file inclusion in `Rack::Static`.
|
357
427
|
|
358
428
|
## [2.2.12] - 2025-03-04
|
359
429
|
|
360
430
|
### Security
|
361
431
|
|
362
|
-
- [CVE-2025-27111](https://github.com/
|
432
|
+
- [CVE-2025-27111](https://github.com/advisories/GHSA-8cgq-6mh2-7j6v) Possible Log Injection in `Rack::Sendfile`.
|
363
433
|
|
364
434
|
## [2.2.11] - 2025-02-12
|
365
435
|
|
366
436
|
### Security
|
367
437
|
|
368
|
-
- [CVE-2025-25184](https://github.com/
|
438
|
+
- [CVE-2025-25184](https://github.com/advisories/GHSA-7g2v-jj9q-g3rg) Possible Log Injection in `Rack::CommonLogger`.
|
369
439
|
|
370
440
|
## [2.2.10] - 2024-10-14
|
371
441
|
|
@@ -1130,3 +1200,4 @@ Items below this line are from the previously maintained HISTORY.md and NEWS.md
|
|
1130
1200
|
[@wjordan]: https://github.com/wjordan "Will Jordan"
|
1131
1201
|
[@BlakeWilliams]: https://github.com/BlakeWilliams "Blake Williams"
|
1132
1202
|
[@davidstosik]: https://github.com/davidstosik "David Stosik"
|
1203
|
+
[@earlopain]: https://github.com/earlopain "Earlopain"
|
data/README.md
CHANGED
@@ -210,6 +210,14 @@ query string, before attempting parsing, so if the same parameter key is
|
|
210
210
|
used multiple times in the query, each counts as a separate parameter for
|
211
211
|
this check.
|
212
212
|
|
213
|
+
### `RACK_MULTIPART_BUFFERED_UPLOAD_BYTESIZE_LIMIT`
|
214
|
+
|
215
|
+
This environment variable sets the maximum amount of memory Rack will use
|
216
|
+
to buffer multipart parameters when parsing a request body. This considers
|
217
|
+
the size of the multipart mime headers and the body part for multipart
|
218
|
+
parameters that are buffered in memory and do not use tempfiles. This
|
219
|
+
defaults to 16MB if not provided.
|
220
|
+
|
213
221
|
### `param_depth_limit`
|
214
222
|
|
215
223
|
```ruby
|
data/lib/rack/mock_response.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'cgi/cookie'
|
4
3
|
require 'time'
|
5
4
|
|
6
5
|
require_relative 'response'
|
@@ -11,6 +10,36 @@ module Rack
|
|
11
10
|
# MockRequest.
|
12
11
|
|
13
12
|
class MockResponse < Rack::Response
|
13
|
+
begin
|
14
|
+
# Recent versions of the CGI gem may not provide `CGI::Cookie`.
|
15
|
+
require 'cgi/cookie'
|
16
|
+
Cookie = CGI::Cookie
|
17
|
+
rescue LoadError
|
18
|
+
class Cookie
|
19
|
+
attr_reader :name, :value, :path, :domain, :expires, :secure
|
20
|
+
|
21
|
+
def initialize(args)
|
22
|
+
@name = args["name"]
|
23
|
+
@value = args["value"]
|
24
|
+
@path = args["path"]
|
25
|
+
@domain = args["domain"]
|
26
|
+
@expires = args["expires"]
|
27
|
+
@secure = args["secure"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(method_name, *args, &block)
|
31
|
+
@value.send(method_name, *args, &block)
|
32
|
+
end
|
33
|
+
# :nocov:
|
34
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
35
|
+
# :nocov:
|
36
|
+
|
37
|
+
def respond_to_missing?(method_name, include_all = false)
|
38
|
+
@value.respond_to?(method_name, include_all) || super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
14
43
|
class << self
|
15
44
|
alias [] new
|
16
45
|
end
|
@@ -83,7 +112,7 @@ module Rack
|
|
83
112
|
Array(set_cookie_header).each do |cookie|
|
84
113
|
cookie_name, cookie_filling = cookie.split('=', 2)
|
85
114
|
cookie_attributes = identify_cookie_attributes cookie_filling
|
86
|
-
parsed_cookie =
|
115
|
+
parsed_cookie = Cookie.new(
|
87
116
|
'name' => cookie_name.strip,
|
88
117
|
'value' => cookie_attributes.fetch('value'),
|
89
118
|
'path' => cookie_attributes.fetch('path', nil),
|
@@ -100,7 +129,7 @@ module Rack
|
|
100
129
|
def identify_cookie_attributes(cookie_filling)
|
101
130
|
cookie_bits = cookie_filling.split(';')
|
102
131
|
cookie_attributes = Hash.new
|
103
|
-
cookie_attributes.store('value', cookie_bits[0].strip)
|
132
|
+
cookie_attributes.store('value', Array(cookie_bits[0].strip))
|
104
133
|
cookie_bits.drop(1).each do |bit|
|
105
134
|
if bit.include? '='
|
106
135
|
cookie_attribute, attribute_value = bit.split('=', 2)
|
@@ -31,10 +31,12 @@ module Rack
|
|
31
31
|
Error = BoundaryTooLongError
|
32
32
|
|
33
33
|
EOL = "\r\n"
|
34
|
+
FWS = /[ \t]+(?:\r\n[ \t]+)?/ # whitespace with optional folding
|
35
|
+
HEADER_VALUE = "(?:[^\r\n]|\r\n[ \t])*" # anything but a non-folding CRLF
|
34
36
|
MULTIPART = %r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|ni
|
35
|
-
MULTIPART_CONTENT_TYPE =
|
36
|
-
MULTIPART_CONTENT_DISPOSITION =
|
37
|
-
MULTIPART_CONTENT_ID =
|
37
|
+
MULTIPART_CONTENT_TYPE = /^Content-Type:#{FWS}?(#{HEADER_VALUE})/ni
|
38
|
+
MULTIPART_CONTENT_DISPOSITION = /^Content-Disposition:#{FWS}?(#{HEADER_VALUE})/ni
|
39
|
+
MULTIPART_CONTENT_ID = /^Content-ID:#{FWS}?(#{HEADER_VALUE})/ni
|
38
40
|
|
39
41
|
class Parser
|
40
42
|
BUFSIZE = 1_048_576
|
@@ -45,6 +47,27 @@ module Rack
|
|
45
47
|
Tempfile.new(["RackMultipart", extension])
|
46
48
|
}
|
47
49
|
|
50
|
+
BOUNDARY_START_LIMIT = 16 * 1024
|
51
|
+
private_constant :BOUNDARY_START_LIMIT
|
52
|
+
|
53
|
+
MIME_HEADER_BYTESIZE_LIMIT = 64 * 1024
|
54
|
+
private_constant :MIME_HEADER_BYTESIZE_LIMIT
|
55
|
+
|
56
|
+
env_int = lambda do |key, val|
|
57
|
+
if str_val = ENV[key]
|
58
|
+
begin
|
59
|
+
val = Integer(str_val, 10)
|
60
|
+
rescue ArgumentError
|
61
|
+
raise ArgumentError, "non-integer value provided for environment variable #{key}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
val
|
66
|
+
end
|
67
|
+
|
68
|
+
BUFFERED_UPLOAD_BYTESIZE_LIMIT = env_int.call("RACK_MULTIPART_BUFFERED_UPLOAD_BYTESIZE_LIMIT", 16 * 1024 * 1024)
|
69
|
+
private_constant :BUFFERED_UPLOAD_BYTESIZE_LIMIT
|
70
|
+
|
48
71
|
class BoundedIO # :nodoc:
|
49
72
|
def initialize(io, content_length)
|
50
73
|
@io = io
|
@@ -204,6 +227,8 @@ module Rack
|
|
204
227
|
|
205
228
|
@state = :FAST_FORWARD
|
206
229
|
@mime_index = 0
|
230
|
+
@body_retained = nil
|
231
|
+
@retained_size = 0
|
207
232
|
@collector = Collector.new tempfile
|
208
233
|
|
209
234
|
@sbuf = StringScanner.new("".dup)
|
@@ -285,6 +310,10 @@ module Rack
|
|
285
310
|
|
286
311
|
# retry for opening boundary
|
287
312
|
else
|
313
|
+
# We raise if we don't find the multipart boundary, to avoid unbounded memory
|
314
|
+
# buffering. Note that the actual limit is the higher of 16KB and the buffer size (1MB by default)
|
315
|
+
raise Error, "multipart boundary not found within limit" if @sbuf.string.bytesize > BOUNDARY_START_LIMIT
|
316
|
+
|
288
317
|
# no boundary found, keep reading data
|
289
318
|
return :want_read
|
290
319
|
end
|
@@ -401,16 +430,30 @@ module Rack
|
|
401
430
|
name = filename || "#{content_type || TEXT_PLAIN}[]".dup
|
402
431
|
end
|
403
432
|
|
433
|
+
# Mime part head data is retained for both TempfilePart and BufferPart
|
434
|
+
# for the entireity of the parse, even though it isn't used for BufferPart.
|
435
|
+
update_retained_size(head.bytesize)
|
436
|
+
|
437
|
+
# If a filename is given, a TempfilePart will be used, so the body will
|
438
|
+
# not be buffered in memory. However, if a filename is not given, a BufferPart
|
439
|
+
# will be used, and the body will be buffered in memory.
|
440
|
+
@body_retained = !filename
|
441
|
+
|
404
442
|
@collector.on_mime_head @mime_index, head, filename, content_type, name
|
405
443
|
@state = :MIME_BODY
|
406
444
|
else
|
407
|
-
|
445
|
+
# We raise if the mime part header is too large, to avoid unbounded memory
|
446
|
+
# buffering. Note that the actual limit is the higher of 64KB and the buffer size (1MB by default)
|
447
|
+
raise Error, "multipart mime part header too large" if @sbuf.string.bytesize > MIME_HEADER_BYTESIZE_LIMIT
|
448
|
+
|
449
|
+
return :want_read
|
408
450
|
end
|
409
451
|
end
|
410
452
|
|
411
453
|
def handle_mime_body
|
412
454
|
if (body_with_boundary = @sbuf.check_until(@body_regex)) # check but do not advance the pointer yet
|
413
455
|
body = body_with_boundary.sub(@body_regex_at_end, '') # remove the boundary from the string
|
456
|
+
update_retained_size(body.bytesize) if @body_retained
|
414
457
|
@collector.on_mime_body @mime_index, body
|
415
458
|
@sbuf.pos += body.length + 2 # skip \r\n after the content
|
416
459
|
@state = :CONSUME_TOKEN
|
@@ -419,7 +462,9 @@ module Rack
|
|
419
462
|
# Save what we have so far
|
420
463
|
if @rx_max_size < @sbuf.rest_size
|
421
464
|
delta = @sbuf.rest_size - @rx_max_size
|
422
|
-
|
465
|
+
body = @sbuf.peek(delta)
|
466
|
+
update_retained_size(body.bytesize) if @body_retained
|
467
|
+
@collector.on_mime_body @mime_index, body
|
423
468
|
@sbuf.pos += delta
|
424
469
|
@sbuf.string = @sbuf.rest
|
425
470
|
end
|
@@ -427,6 +472,13 @@ module Rack
|
|
427
472
|
end
|
428
473
|
end
|
429
474
|
|
475
|
+
def update_retained_size(size)
|
476
|
+
@retained_size += size
|
477
|
+
if @retained_size > BUFFERED_UPLOAD_BYTESIZE_LIMIT
|
478
|
+
raise Error, "multipart data over retained size limit"
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
430
482
|
# Scan until the we find the start or end of the boundary.
|
431
483
|
# If we find it, return the appropriate symbol for the start or
|
432
484
|
# end of the boundary. If we don't find the start or end of the
|
data/lib/rack/query_parser.rb
CHANGED
@@ -57,6 +57,8 @@ module Rack
|
|
57
57
|
PARAMS_LIMIT = env_int.call("RACK_QUERY_PARSER_PARAMS_LIMIT", 4096)
|
58
58
|
private_constant :PARAMS_LIMIT
|
59
59
|
|
60
|
+
attr_reader :bytesize_limit
|
61
|
+
|
60
62
|
def initialize(params_class, param_depth_limit, bytesize_limit: BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT)
|
61
63
|
@params_class = params_class
|
62
64
|
@param_depth_limit = param_depth_limit
|
@@ -218,7 +220,7 @@ module Rack
|
|
218
220
|
def check_query_string(qs, sep)
|
219
221
|
if qs
|
220
222
|
if qs.bytesize > @bytesize_limit
|
221
|
-
raise QueryLimitError, "total query size
|
223
|
+
raise QueryLimitError, "total query size exceeds limit (#{@bytesize_limit})"
|
222
224
|
end
|
223
225
|
|
224
226
|
if (param_count = qs.count(sep.is_a?(String) ? sep : '&')) >= @params_limit
|
data/lib/rack/request.rb
CHANGED
@@ -528,7 +528,10 @@ module Rack
|
|
528
528
|
set_header RACK_REQUEST_FORM_PAIRS, pairs
|
529
529
|
set_header RACK_REQUEST_FORM_HASH, expand_param_pairs(pairs)
|
530
530
|
else
|
531
|
-
|
531
|
+
# Add 2 bytes. One to check whether it is over the limit, and a second
|
532
|
+
# in case the slice! call below removes the last byte
|
533
|
+
# If read returns nil, use the empty string
|
534
|
+
form_vars = get_header(RACK_INPUT).read(query_parser.bytesize_limit + 2) || ''
|
532
535
|
|
533
536
|
# Fix for Safari Ajax postings that always append \0
|
534
537
|
# form_vars.sub!(/\0\z/, '') # performance replacement:
|
data/lib/rack/sendfile.rb
CHANGED
@@ -16,21 +16,21 @@ module Rack
|
|
16
16
|
# delivery code.
|
17
17
|
#
|
18
18
|
# In order to take advantage of this middleware, the response body must
|
19
|
-
# respond to +to_path+ and the request must include an x-sendfile-type
|
19
|
+
# respond to +to_path+ and the request must include an `x-sendfile-type`
|
20
20
|
# header. Rack::Files and other components implement +to_path+ so there's
|
21
|
-
# rarely anything you need to do in your application. The x-sendfile-type
|
21
|
+
# rarely anything you need to do in your application. The `x-sendfile-type`
|
22
22
|
# header is typically set in your web servers configuration. The following
|
23
23
|
# sections attempt to document
|
24
24
|
#
|
25
25
|
# === Nginx
|
26
26
|
#
|
27
|
-
# Nginx supports the x-accel-redirect header. This is similar to x-sendfile
|
27
|
+
# Nginx supports the `x-accel-redirect` header. This is similar to `x-sendfile`
|
28
28
|
# but requires parts of the filesystem to be mapped into a private URL
|
29
29
|
# hierarchy.
|
30
30
|
#
|
31
31
|
# The following example shows the Nginx configuration required to create
|
32
|
-
# a private "/files/" area, enable x-accel-redirect
|
33
|
-
# x-
|
32
|
+
# a private "/files/" area, enable `x-accel-redirect`, and pass the special
|
33
|
+
# `x-accel-mapping` header to the backend:
|
34
34
|
#
|
35
35
|
# location ~ /files/(.*) {
|
36
36
|
# internal;
|
@@ -44,24 +44,29 @@ module Rack
|
|
44
44
|
# proxy_set_header X-Real-IP $remote_addr;
|
45
45
|
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
46
46
|
#
|
47
|
-
# proxy_set_header x-sendfile-type x-accel-redirect;
|
48
47
|
# proxy_set_header x-accel-mapping /var/www/=/files/;
|
49
48
|
#
|
50
49
|
# proxy_pass http://127.0.0.1:8080/;
|
51
50
|
# }
|
52
51
|
#
|
53
|
-
#
|
54
|
-
# The x-accel-mapping header should specify the location on the file system,
|
52
|
+
# The `x-accel-mapping` header should specify the location on the file system,
|
55
53
|
# followed by an equals sign (=), followed name of the private URL pattern
|
56
54
|
# that it maps to. The middleware performs a simple substitution on the
|
57
55
|
# resulting path.
|
58
56
|
#
|
57
|
+
# To enable `x-accel-redirect`, you must configure the middleware explicitly:
|
58
|
+
#
|
59
|
+
# use Rack::Sendfile, "x-accel-redirect"
|
60
|
+
#
|
61
|
+
# For security reasons, the `x-sendfile-type` header from requests is ignored.
|
62
|
+
# The sendfile variation must be set via the middleware constructor.
|
63
|
+
#
|
59
64
|
# See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile
|
60
65
|
#
|
61
66
|
# === lighttpd
|
62
67
|
#
|
63
|
-
# Lighttpd has supported some variation of the x-sendfile header for some
|
64
|
-
# time, although only recent version support x-sendfile in a reverse proxy
|
68
|
+
# Lighttpd has supported some variation of the `x-sendfile` header for some
|
69
|
+
# time, although only recent version support `x-sendfile` in a reverse proxy
|
65
70
|
# configuration.
|
66
71
|
#
|
67
72
|
# $HTTP["host"] == "example.com" {
|
@@ -83,7 +88,7 @@ module Rack
|
|
83
88
|
#
|
84
89
|
# === Apache
|
85
90
|
#
|
86
|
-
# x-sendfile is supported under Apache 2.x using a separate module:
|
91
|
+
# `x-sendfile` is supported under Apache 2.x using a separate module:
|
87
92
|
#
|
88
93
|
# https://tn123.org/mod_xsendfile/
|
89
94
|
#
|
@@ -97,16 +102,28 @@ module Rack
|
|
97
102
|
# === Mapping parameter
|
98
103
|
#
|
99
104
|
# The third parameter allows for an overriding extension of the
|
100
|
-
# x-accel-mapping header. Mappings should be provided in tuples of internal to
|
105
|
+
# `x-accel-mapping` header. Mappings should be provided in tuples of internal to
|
101
106
|
# external. The internal values may contain regular expression syntax, they
|
102
107
|
# will be matched with case indifference.
|
108
|
+
#
|
109
|
+
# When `x-accel-redirect` is explicitly enabled via the variation parameter,
|
110
|
+
# and no application-level mappings are provided, the middleware will read
|
111
|
+
# the `x-accel-mapping` header from the proxy. This allows nginx to control
|
112
|
+
# the path mapping without requiring application-level configuration.
|
113
|
+
#
|
114
|
+
# === Security
|
115
|
+
#
|
116
|
+
# For security reasons, the `x-sendfile-type` header from HTTP requests is
|
117
|
+
# ignored. The sendfile variation must be explicitly configured via the
|
118
|
+
# middleware constructor to prevent information disclosure vulnerabilities
|
119
|
+
# where attackers could bypass proxy restrictions.
|
103
120
|
|
104
121
|
class Sendfile
|
105
122
|
def initialize(app, variation = nil, mappings = [])
|
106
123
|
@app = app
|
107
124
|
@variation = variation
|
108
125
|
@mappings = mappings.map do |internal, external|
|
109
|
-
[
|
126
|
+
[/\A#{internal}/i, external]
|
110
127
|
end
|
111
128
|
end
|
112
129
|
|
@@ -145,22 +162,35 @@ module Rack
|
|
145
162
|
end
|
146
163
|
|
147
164
|
private
|
165
|
+
|
148
166
|
def variation(env)
|
149
|
-
|
150
|
-
|
151
|
-
|
167
|
+
# Note: HTTP_X_SENDFILE_TYPE is intentionally NOT read for security reasons.
|
168
|
+
# Attackers could use this header to enable x-accel-redirect and bypass proxy restrictions.
|
169
|
+
@variation || env['sendfile.type']
|
170
|
+
end
|
171
|
+
|
172
|
+
def x_accel_mapping(env)
|
173
|
+
# Only allow header when:
|
174
|
+
# 1. `x-accel-redirect` is explicitly enabled via constructor.
|
175
|
+
# 2. No application-level mappings are configured.
|
176
|
+
return nil unless @variation =~ /x-accel-redirect/i
|
177
|
+
return nil if @mappings.any?
|
178
|
+
|
179
|
+
env['HTTP_X_ACCEL_MAPPING']
|
152
180
|
end
|
153
181
|
|
154
182
|
def map_accel_path(env, path)
|
155
183
|
if mapping = @mappings.find { |internal, _| internal =~ path }
|
156
|
-
path.sub(*mapping)
|
157
|
-
elsif mapping = env
|
184
|
+
return path.sub(*mapping)
|
185
|
+
elsif mapping = x_accel_mapping(env)
|
186
|
+
# Safe to use header: explicit config + no app mappings:
|
158
187
|
mapping.split(',').map(&:strip).each do |m|
|
159
188
|
internal, external = m.split('=', 2).map(&:strip)
|
160
|
-
new_path = path.sub(
|
189
|
+
new_path = path.sub(/\A#{internal}/i, external)
|
161
190
|
return new_path unless path == new_path
|
162
191
|
end
|
163
|
-
|
192
|
+
|
193
|
+
return path
|
164
194
|
end
|
165
195
|
end
|
166
196
|
end
|
data/lib/rack/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leah Neukirchen
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: minitest
|
@@ -76,9 +75,9 @@ email: leah@vuxu.org
|
|
76
75
|
executables: []
|
77
76
|
extensions: []
|
78
77
|
extra_rdoc_files:
|
79
|
-
- README.md
|
80
78
|
- CHANGELOG.md
|
81
79
|
- CONTRIBUTING.md
|
80
|
+
- README.md
|
82
81
|
files:
|
83
82
|
- CHANGELOG.md
|
84
83
|
- CONTRIBUTING.md
|
@@ -143,7 +142,6 @@ metadata:
|
|
143
142
|
changelog_uri: https://github.com/rack/rack/blob/main/CHANGELOG.md
|
144
143
|
documentation_uri: https://rubydoc.info/github/rack/rack
|
145
144
|
source_code_uri: https://github.com/rack/rack
|
146
|
-
post_install_message:
|
147
145
|
rdoc_options: []
|
148
146
|
require_paths:
|
149
147
|
- lib
|
@@ -158,8 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
158
156
|
- !ruby/object:Gem::Version
|
159
157
|
version: '0'
|
160
158
|
requirements: []
|
161
|
-
rubygems_version: 3.
|
162
|
-
signing_key:
|
159
|
+
rubygems_version: 3.6.9
|
163
160
|
specification_version: 4
|
164
161
|
summary: A modular Ruby webserver interface.
|
165
162
|
test_files: []
|