rack 2.2.9 → 3.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +330 -88
  3. data/CONTRIBUTING.md +63 -55
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +328 -0
  6. data/SPEC.rdoc +204 -131
  7. data/lib/rack/auth/abstract/handler.rb +3 -1
  8. data/lib/rack/auth/abstract/request.rb +3 -1
  9. data/lib/rack/auth/basic.rb +1 -4
  10. data/lib/rack/bad_request.rb +8 -0
  11. data/lib/rack/body_proxy.rb +21 -3
  12. data/lib/rack/builder.rb +102 -69
  13. data/lib/rack/cascade.rb +2 -3
  14. data/lib/rack/common_logger.rb +23 -18
  15. data/lib/rack/conditional_get.rb +18 -15
  16. data/lib/rack/constants.rb +67 -0
  17. data/lib/rack/content_length.rb +12 -16
  18. data/lib/rack/content_type.rb +8 -5
  19. data/lib/rack/deflater.rb +40 -26
  20. data/lib/rack/directory.rb +9 -3
  21. data/lib/rack/etag.rb +14 -23
  22. data/lib/rack/events.rb +4 -0
  23. data/lib/rack/files.rb +15 -17
  24. data/lib/rack/head.rb +9 -8
  25. data/lib/rack/headers.rb +238 -0
  26. data/lib/rack/lint.rb +840 -644
  27. data/lib/rack/lock.rb +2 -5
  28. data/lib/rack/logger.rb +3 -0
  29. data/lib/rack/method_override.rb +5 -1
  30. data/lib/rack/mime.rb +14 -5
  31. data/lib/rack/mock.rb +1 -271
  32. data/lib/rack/mock_request.rb +161 -0
  33. data/lib/rack/mock_response.rb +124 -0
  34. data/lib/rack/multipart/generator.rb +7 -5
  35. data/lib/rack/multipart/parser.rb +213 -95
  36. data/lib/rack/multipart/uploaded_file.rb +4 -0
  37. data/lib/rack/multipart.rb +53 -40
  38. data/lib/rack/null_logger.rb +9 -0
  39. data/lib/rack/query_parser.rb +81 -102
  40. data/lib/rack/recursive.rb +2 -0
  41. data/lib/rack/reloader.rb +0 -2
  42. data/lib/rack/request.rb +260 -123
  43. data/lib/rack/response.rb +151 -66
  44. data/lib/rack/rewindable_input.rb +24 -5
  45. data/lib/rack/runtime.rb +7 -6
  46. data/lib/rack/sendfile.rb +30 -25
  47. data/lib/rack/show_exceptions.rb +21 -4
  48. data/lib/rack/show_status.rb +17 -7
  49. data/lib/rack/static.rb +8 -8
  50. data/lib/rack/tempfile_reaper.rb +15 -4
  51. data/lib/rack/urlmap.rb +3 -1
  52. data/lib/rack/utils.rb +232 -233
  53. data/lib/rack/version.rb +1 -9
  54. data/lib/rack.rb +13 -89
  55. metadata +15 -41
  56. data/README.rdoc +0 -320
  57. data/Rakefile +0 -130
  58. data/bin/rackup +0 -5
  59. data/contrib/rack.png +0 -0
  60. data/contrib/rack.svg +0 -150
  61. data/contrib/rack_logo.svg +0 -164
  62. data/contrib/rdoc.css +0 -412
  63. data/example/lobster.ru +0 -6
  64. data/example/protectedlobster.rb +0 -16
  65. data/example/protectedlobster.ru +0 -10
  66. data/lib/rack/auth/digest/md5.rb +0 -131
  67. data/lib/rack/auth/digest/nonce.rb +0 -54
  68. data/lib/rack/auth/digest/params.rb +0 -54
  69. data/lib/rack/auth/digest/request.rb +0 -43
  70. data/lib/rack/chunked.rb +0 -117
  71. data/lib/rack/core_ext/regexp.rb +0 -14
  72. data/lib/rack/file.rb +0 -7
  73. data/lib/rack/handler/cgi.rb +0 -59
  74. data/lib/rack/handler/fastcgi.rb +0 -100
  75. data/lib/rack/handler/lsws.rb +0 -61
  76. data/lib/rack/handler/scgi.rb +0 -71
  77. data/lib/rack/handler/thin.rb +0 -36
  78. data/lib/rack/handler/webrick.rb +0 -129
  79. data/lib/rack/handler.rb +0 -104
  80. data/lib/rack/lobster.rb +0 -70
  81. data/lib/rack/server.rb +0 -466
  82. data/lib/rack/session/abstract/id.rb +0 -523
  83. data/lib/rack/session/cookie.rb +0 -204
  84. data/lib/rack/session/memcache.rb +0 -10
  85. data/lib/rack/session/pool.rb +0 -85
  86. data/rack.gemspec +0 -46
data/contrib/rdoc.css DELETED
@@ -1,412 +0,0 @@
1
- /* Forked from the Darkfish templates rdoc.css file, much hacked, probably
2
- * imperfect */
3
-
4
- html { max-width: 960px; margin: 0 auto; }
5
- body {
6
- font: 14px "Helvetica Neue", Helvetica, Tahoma, sans-serif;
7
- }
8
- body.file-popup {
9
- font-size: 90%;
10
- margin-left: 0;
11
- }
12
-
13
- h1 {
14
- color: #4183C4;
15
- }
16
-
17
- :link,
18
- :visited {
19
- color: #4183C4;
20
- text-decoration: none;
21
- }
22
- :link:hover,
23
- :visited:hover {
24
- border-bottom: 1px dotted #4183C4;
25
- }
26
-
27
- pre, pre.description {
28
- font: 12px Monaco,"Courier New","DejaVu Sans Mono","Bitstream Vera Sans Mono",monospace;
29
- padding: 1em;
30
- overflow: auto;
31
- line-height: 1.4;
32
- }
33
-
34
- /* @group Generic Classes */
35
-
36
- .initially-hidden {
37
- display: none;
38
- }
39
-
40
- #search-field {
41
- width: 98%;
42
- }
43
-
44
- .missing-docs {
45
- font-size: 120%;
46
- background: white url(images/wrench_orange.png) no-repeat 4px center;
47
- color: #ccc;
48
- line-height: 2em;
49
- border: 1px solid #d00;
50
- opacity: 1;
51
- text-indent: 24px;
52
- letter-spacing: 3px;
53
- font-weight: bold;
54
- -webkit-border-radius: 5px;
55
- -moz-border-radius: 5px;
56
- }
57
-
58
- .target-section {
59
- border: 2px solid #dcce90;
60
- border-left-width: 8px;
61
- background: #fff3c2;
62
- }
63
-
64
- /* @end */
65
-
66
- /* @group Index Page, Standalone file pages */
67
- .indexpage ul {
68
- line-height: 160%;
69
- list-style: none;
70
- }
71
- .indexpage ul :link,
72
- .indexpage ul :visited {
73
- font-size: 16px;
74
- }
75
-
76
- .indexpage li {
77
- padding-left: 20px;
78
- }
79
-
80
- .indexpage ul > li {
81
- background: url(images/bullet_black.png) no-repeat left 4px;
82
- }
83
- .indexpage li.method {
84
- background: url(images/plugin.png) no-repeat left 4px;
85
- }
86
- .indexpage li.module {
87
- background: url(images/package.png) no-repeat left 4px;
88
- }
89
- .indexpage li.class {
90
- background: url(images/ruby.png) no-repeat left 4px;
91
- }
92
- .indexpage li.file {
93
- background: url(images/page_white_text.png) no-repeat left 4px;
94
- }
95
- .indexpage li li {
96
- background: url(images/tag_blue.png) no-repeat left 4px;
97
- }
98
- .indexpage li .toc-toggle {
99
- width: 16px;
100
- height: 16px;
101
- background: url(images/add.png) no-repeat;
102
- }
103
-
104
- .indexpage li .toc-toggle.open {
105
- background: url(images/delete.png) no-repeat;
106
- }
107
-
108
- /* @end */
109
-
110
- /* @group Top-Level Structure */
111
-
112
- .project-section, #file-metadata, #class-metadata {
113
- display: block;
114
- background: #f5f5f5;
115
- margin-bottom: 1em;
116
- padding: 0.5em;
117
- }
118
- .project-section h3, #file-metadata h3, #class-metadata h3 {
119
- margin: 0;
120
- }
121
-
122
- #metadata {
123
- float: left;
124
- width: 280px;
125
- }
126
-
127
- #documentation {
128
- margin: 2em 1em 2em 300px;
129
- }
130
-
131
- #validator-badges {
132
- clear: both;
133
- margin: 1em 1em 2em;
134
- font-size: smaller;
135
- }
136
-
137
- /* @end */
138
-
139
- /* @group Metadata Section */
140
-
141
- #metadata ul,
142
- #metadata dl,
143
- #metadata p {
144
- padding: 0px;
145
- list-style: none;
146
- }
147
-
148
- dl.svninfo {
149
- color: #666;
150
- margin: 0;
151
- }
152
- dl.svninfo dt {
153
- font-weight: bold;
154
- }
155
-
156
- ul.link-list li {
157
- white-space: nowrap;
158
- }
159
- ul.link-list .type {
160
- font-size: 8px;
161
- text-transform: uppercase;
162
- color: white;
163
- background: #969696;
164
- }
165
-
166
- /* @end */
167
-
168
- /* @group Documentation Section */
169
-
170
- .note-list {
171
- margin: 8px 0;
172
- }
173
-
174
- .label-list {
175
- margin: 8px 1.5em;
176
- border: 1px solid #ccc;
177
- }
178
- .description .label-list {
179
- font-size: 14px;
180
- }
181
-
182
- .note-list dt {
183
- font-weight: bold;
184
- }
185
- .note-list dd {
186
- }
187
-
188
- .label-list dt {
189
- font-weight: bold;
190
- background: #ddd;
191
- }
192
- .label-list dd {
193
- }
194
- .label-list dd + dt,
195
- .note-list dd + dt {
196
- margin-top: 0.7em;
197
- }
198
-
199
- #documentation .section {
200
- font-size: 90%;
201
- }
202
-
203
- #documentation h2.section-header {
204
- color: #333;
205
- font-size: 175%;
206
- }
207
-
208
- .documentation-section-title {
209
- position: relative;
210
- }
211
- .documentation-section-title .section-click-top {
212
- position: absolute;
213
- top: 6px;
214
- right: 12px;
215
- font-size: 10px;
216
- visibility: hidden;
217
- }
218
-
219
- .documentation-section-title:hover .section-click-top {
220
- visibility: visible;
221
- }
222
-
223
- #documentation h3.section-header {
224
- color: #333;
225
- font-size: 150%;
226
- }
227
-
228
- #constants-list > dl,
229
- #attributes-list > dl {
230
- margin: 1em 0 2em;
231
- border: 0;
232
- }
233
- #constants-list > dl dt,
234
- #attributes-list > dl dt {
235
- font-weight: bold;
236
- font-family: Monaco, "Andale Mono";
237
- background: inherit;
238
- }
239
- #constants-list > dl dt a,
240
- #attributes-list > dl dt a {
241
- color: inherit;
242
- }
243
- #constants-list > dl dd,
244
- #attributes-list > dl dd {
245
- margin: 0 0 1em 0;
246
- color: #666;
247
- }
248
-
249
- .documentation-section h2 {
250
- position: relative;
251
- }
252
-
253
- .documentation-section h2 a {
254
- position: absolute;
255
- top: 8px;
256
- right: 10px;
257
- font-size: 12px;
258
- color: #9b9877;
259
- visibility: hidden;
260
- }
261
-
262
- .documentation-section h2:hover a {
263
- visibility: visible;
264
- }
265
-
266
- /* @group Method Details */
267
-
268
- #documentation .method-source-code {
269
- display: none;
270
- }
271
-
272
- #documentation .method-detail {
273
- margin: 0.2em 0.2em;
274
- padding: 0.5em;
275
- }
276
- #documentation .method-detail:hover {
277
- background-color: #f5f5f5;
278
- }
279
- #documentation .method-heading {
280
- cursor: pointer;
281
- position: relative;
282
- font-size: 125%;
283
- line-height: 125%;
284
- font-weight: bold;
285
- color: #333;
286
- background: url(images/brick.png) no-repeat left bottom;
287
- padding-left: 20px;
288
- }
289
- #documentation .method-heading :link,
290
- #documentation .method-heading :visited {
291
- color: inherit;
292
- }
293
- #documentation .method-click-advice {
294
- position: absolute;
295
- right: 5px;
296
- font-size: 10px;
297
- color: #aaa;
298
- visibility: hidden;
299
- background: url(images/zoom.png) no-repeat right 5px;
300
- padding-right: 20px;
301
- overflow: show;
302
- }
303
- #documentation .method-heading:hover .method-click-advice {
304
- visibility: visible;
305
- }
306
-
307
- #documentation .method-alias .method-heading {
308
- color: #666;
309
- background: url(images/brick_link.png) no-repeat left bottom;
310
- }
311
-
312
- #documentation .method-description,
313
- #documentation .aliases {
314
- margin: 0 20px;
315
- color: #666;
316
- }
317
-
318
- #documentation .method-description p,
319
- #documentation .aliases p {
320
- line-height: 1.2em;
321
- }
322
-
323
- #documentation .aliases {
324
- font-style: italic;
325
- cursor: default;
326
- }
327
- #documentation .method-description p {
328
- margin-bottom: 0.5em;
329
- }
330
- #documentation .method-description ul {
331
- margin-left: 1.5em;
332
- }
333
-
334
- #documentation .attribute-method-heading {
335
- background: url(images/tag_green.png) no-repeat left bottom;
336
- }
337
- #documentation #attribute-method-details .method-detail:hover {
338
- background-color: transparent;
339
- cursor: default;
340
- }
341
- #documentation .attribute-access-type {
342
- font-size: 60%;
343
- text-transform: uppercase;
344
- vertical-align: super;
345
- }
346
-
347
- .method-section .method-source-code {
348
- background: white;
349
- }
350
-
351
- /* @group Source Code */
352
-
353
- .ruby-constant .ruby-keyword .ruby-ivar .ruby-operator .ruby-identifier
354
- .ruby-node .ruby-comment .ruby-regexp .ruby-value {
355
- background: transparent;
356
- }
357
-
358
- /* Thanks GitHub!!! */
359
- .ruby-constant { color: #458; font-weight: bold; }
360
- .ruby-keyword { color: black; font-weight: bold; }
361
- .ruby-ivar { color: teal; }
362
- .ruby-operator { color: #000; }
363
- .ruby-identifier { color: black; }
364
- .ruby-node { color: red; }
365
- .ruby-comment { color: #998; font-weight: bold; }
366
- .ruby-regexp { color: #009926; }
367
- .ruby-value { color: #099; }
368
- .ruby-string { color: red; }
369
-
370
- /* @group search results */
371
-
372
- #search-section .section-header {
373
- margin: 0;
374
- padding: 0;
375
- }
376
-
377
- #search-results {
378
- width: 100%;
379
- list-style: none;
380
- margin: 0;
381
- padding: 0;
382
- }
383
-
384
- #search-results h1 {
385
- font-size: 1em;
386
- font-weight: normal;
387
- text-shadow: none;
388
- }
389
-
390
- #search-results .current {
391
- background: #eee;
392
- }
393
-
394
- #search-results li {
395
- list-style: none;
396
- line-height: 1em;
397
- padding: 0.5em;
398
- border-bottom: 1px solid black;
399
- }
400
-
401
- #search-results .search-namespace {
402
- font-weight: bold;
403
- }
404
-
405
- #search-results li em {
406
- background: yellow;
407
- font-style: normal;
408
- }
409
-
410
- #search-results pre {
411
- margin: 0.5em;
412
- }
data/example/lobster.ru DELETED
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack/lobster'
4
-
5
- use Rack::ShowExceptions
6
- run Rack::Lobster.new
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack'
4
- require 'rack/lobster'
5
-
6
- lobster = Rack::Lobster.new
7
-
8
- protected_lobster = Rack::Auth::Basic.new(lobster) do |username, password|
9
- Rack::Utils.secure_compare('secret', password)
10
- end
11
-
12
- protected_lobster.realm = 'Lobster 2.0'
13
-
14
- pretty_protected_lobster = Rack::ShowStatus.new(Rack::ShowExceptions.new(protected_lobster))
15
-
16
- Rack::Server.start app: pretty_protected_lobster, Port: 9292
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack/lobster'
4
-
5
- use Rack::ShowExceptions
6
- use Rack::Auth::Basic, "Lobster 2.0" do |username, password|
7
- Rack::Utils.secure_compare('secret', password)
8
- end
9
-
10
- run Rack::Lobster.new
@@ -1,131 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../abstract/handler'
4
- require_relative 'request'
5
- require_relative 'params'
6
- require_relative 'nonce'
7
- require 'digest/md5'
8
-
9
- module Rack
10
- module Auth
11
- module Digest
12
- # Rack::Auth::Digest::MD5 implements the MD5 algorithm version of
13
- # HTTP Digest Authentication, as per RFC 2617.
14
- #
15
- # Initialize with the [Rack] application that you want protecting,
16
- # and a block that looks up a plaintext password for a given username.
17
- #
18
- # +opaque+ needs to be set to a constant base64/hexadecimal string.
19
- #
20
- class MD5 < AbstractHandler
21
-
22
- attr_accessor :opaque
23
-
24
- attr_writer :passwords_hashed
25
-
26
- def initialize(app, realm = nil, opaque = nil, &authenticator)
27
- @passwords_hashed = nil
28
- if opaque.nil? and realm.respond_to? :values_at
29
- realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed
30
- end
31
- super(app, realm, &authenticator)
32
- @opaque = opaque
33
- end
34
-
35
- def passwords_hashed?
36
- !!@passwords_hashed
37
- end
38
-
39
- def call(env)
40
- auth = Request.new(env)
41
-
42
- unless auth.provided?
43
- return unauthorized
44
- end
45
-
46
- if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth)
47
- return bad_request
48
- end
49
-
50
- if valid?(auth)
51
- if auth.nonce.stale?
52
- return unauthorized(challenge(stale: true))
53
- else
54
- env['REMOTE_USER'] = auth.username
55
-
56
- return @app.call(env)
57
- end
58
- end
59
-
60
- unauthorized
61
- end
62
-
63
-
64
- private
65
-
66
- QOP = 'auth'
67
-
68
- def params(hash = {})
69
- Params.new do |params|
70
- params['realm'] = realm
71
- params['nonce'] = Nonce.new.to_s
72
- params['opaque'] = H(opaque)
73
- params['qop'] = QOP
74
-
75
- hash.each { |k, v| params[k] = v }
76
- end
77
- end
78
-
79
- def challenge(hash = {})
80
- "Digest #{params(hash)}"
81
- end
82
-
83
- def valid?(auth)
84
- valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
85
- end
86
-
87
- def valid_qop?(auth)
88
- QOP == auth.qop
89
- end
90
-
91
- def valid_opaque?(auth)
92
- H(opaque) == auth.opaque
93
- end
94
-
95
- def valid_nonce?(auth)
96
- auth.nonce.valid?
97
- end
98
-
99
- def valid_digest?(auth)
100
- pw = @authenticator.call(auth.username)
101
- pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response)
102
- end
103
-
104
- def md5(data)
105
- ::Digest::MD5.hexdigest(data)
106
- end
107
-
108
- alias :H :md5
109
-
110
- def KD(secret, data)
111
- H "#{secret}:#{data}"
112
- end
113
-
114
- def A1(auth, password)
115
- "#{auth.username}:#{auth.realm}:#{password}"
116
- end
117
-
118
- def A2(auth)
119
- "#{auth.method}:#{auth.uri}"
120
- end
121
-
122
- def digest(auth, password)
123
- password_hash = passwords_hashed? ? password : H(A1(auth, password))
124
-
125
- KD password_hash, "#{auth.nonce}:#{auth.nc}:#{auth.cnonce}:#{QOP}:#{H A2(auth)}"
126
- end
127
-
128
- end
129
- end
130
- end
131
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'digest/md5'
4
- require 'base64'
5
-
6
- module Rack
7
- module Auth
8
- module Digest
9
- # Rack::Auth::Digest::Nonce is the default nonce generator for the
10
- # Rack::Auth::Digest::MD5 authentication handler.
11
- #
12
- # +private_key+ needs to set to a constant string.
13
- #
14
- # +time_limit+ can be optionally set to an integer (number of seconds),
15
- # to limit the validity of the generated nonces.
16
-
17
- class Nonce
18
-
19
- class << self
20
- attr_accessor :private_key, :time_limit
21
- end
22
-
23
- def self.parse(string)
24
- new(*Base64.decode64(string).split(' ', 2))
25
- end
26
-
27
- def initialize(timestamp = Time.now, given_digest = nil)
28
- @timestamp, @given_digest = timestamp.to_i, given_digest
29
- end
30
-
31
- def to_s
32
- Base64.encode64("#{@timestamp} #{digest}").strip
33
- end
34
-
35
- def digest
36
- ::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}")
37
- end
38
-
39
- def valid?
40
- digest == @given_digest
41
- end
42
-
43
- def stale?
44
- !self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit
45
- end
46
-
47
- def fresh?
48
- !stale?
49
- end
50
-
51
- end
52
- end
53
- end
54
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Rack
4
- module Auth
5
- module Digest
6
- class Params < Hash
7
-
8
- def self.parse(str)
9
- Params[*split_header_value(str).map do |param|
10
- k, v = param.split('=', 2)
11
- [k, dequote(v)]
12
- end.flatten]
13
- end
14
-
15
- def self.dequote(str) # From WEBrick::HTTPUtils
16
- ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
17
- ret.gsub!(/\\(.)/, "\\1")
18
- ret
19
- end
20
-
21
- def self.split_header_value(str)
22
- str.scan(/\w+\=(?:"[^\"]+"|[^,]+)/n)
23
- end
24
-
25
- def initialize
26
- super()
27
-
28
- yield self if block_given?
29
- end
30
-
31
- def [](k)
32
- super k.to_s
33
- end
34
-
35
- def []=(k, v)
36
- super k.to_s, v.to_s
37
- end
38
-
39
- UNQUOTED = ['nc', 'stale']
40
-
41
- def to_s
42
- map do |k, v|
43
- "#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}"
44
- end.join(', ')
45
- end
46
-
47
- def quote(str) # From WEBrick::HTTPUtils
48
- '"' + str.gsub(/[\\\"]/o, "\\\1") + '"'
49
- end
50
-
51
- end
52
- end
53
- end
54
- end