rack 2.0.9.3 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +681 -0
- data/CONTRIBUTING.md +136 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +152 -162
- data/Rakefile +37 -23
- data/{SPEC → SPEC.rdoc} +35 -10
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +1 -1
- data/lib/rack/auth/basic.rb +7 -4
- data/lib/rack/auth/digest/md5.rb +13 -11
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +5 -3
- data/lib/rack/body_proxy.rb +15 -14
- data/lib/rack/builder.rb +116 -23
- data/lib/rack/cascade.rb +28 -12
- data/lib/rack/chunked.rb +68 -20
- data/lib/rack/common_logger.rb +33 -28
- data/lib/rack/conditional_get.rb +20 -16
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +8 -7
- data/lib/rack/content_type.rb +5 -4
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +59 -34
- data/lib/rack/directory.rb +84 -64
- data/lib/rack/etag.rb +5 -4
- data/lib/rack/events.rb +19 -20
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +218 -0
- data/lib/rack/handler/cgi.rb +2 -3
- data/lib/rack/handler/fastcgi.rb +4 -4
- data/lib/rack/handler/lsws.rb +3 -3
- data/lib/rack/handler/scgi.rb +9 -8
- data/lib/rack/handler/thin.rb +17 -11
- data/lib/rack/handler/webrick.rb +15 -6
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/head.rb +1 -1
- data/lib/rack/lint.rb +72 -26
- data/lib/rack/lobster.rb +10 -10
- data/lib/rack/lock.rb +2 -1
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +4 -2
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +97 -20
- data/lib/rack/multipart/generator.rb +17 -13
- data/lib/rack/multipart/parser.rb +58 -73
- data/lib/rack/multipart/uploaded_file.rb +15 -7
- data/lib/rack/multipart.rb +7 -4
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +53 -28
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +8 -4
- data/lib/rack/request.rb +220 -61
- data/lib/rack/response.rb +127 -44
- data/lib/rack/rewindable_input.rb +4 -3
- data/lib/rack/runtime.rb +6 -4
- data/lib/rack/sendfile.rb +13 -9
- data/lib/rack/server.rb +95 -24
- data/lib/rack/session/abstract/id.rb +33 -21
- data/lib/rack/session/cookie.rb +12 -12
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +5 -3
- data/lib/rack/show_exceptions.rb +17 -13
- data/lib/rack/show_status.rb +5 -5
- data/lib/rack/static.rb +23 -11
- data/lib/rack/tempfile_reaper.rb +1 -1
- data/lib/rack/urlmap.rb +12 -6
- data/lib/rack/utils.rb +105 -130
- data/lib/rack/version.rb +29 -0
- data/lib/rack.rb +67 -73
- data/rack.gemspec +40 -28
- metadata +39 -182
- data/HISTORY.md +0 -520
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -107
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -520
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -110
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -721
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1423
- data/test/spec_response.rb +0 -528
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -357
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -247
- data/test/spec_show_exceptions.rb +0 -93
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/Rakefile
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
2
5
|
|
3
6
|
desc "Run all the tests"
|
4
|
-
task :
|
7
|
+
task default: :test
|
5
8
|
|
6
9
|
desc "Install gem dependencies"
|
7
10
|
task :deps do
|
@@ -16,9 +19,9 @@ task :deps do
|
|
16
19
|
end
|
17
20
|
|
18
21
|
desc "Make an archive as .tar.gz"
|
19
|
-
task :
|
22
|
+
task dist: %w[chmod changelog spec rdoc] do
|
20
23
|
sh "git archive --format=tar --prefix=#{release}/ HEAD^{tree} >#{release}.tar"
|
21
|
-
sh "pax -waf #{release}.tar -s ':^:#{release}/:' SPEC ChangeLog doc rack.gemspec"
|
24
|
+
sh "pax -waf #{release}.tar -s ':^:#{release}/:' SPEC.rdoc ChangeLog doc rack.gemspec"
|
22
25
|
sh "gzip -f -9 #{release}.tar"
|
23
26
|
end
|
24
27
|
|
@@ -31,12 +34,12 @@ task :officialrelease do
|
|
31
34
|
sh "mv stage/#{release}.tar.gz stage/#{release}.gem ."
|
32
35
|
end
|
33
36
|
|
34
|
-
task :
|
37
|
+
task officialrelease_really: %w[spec dist gem] do
|
35
38
|
sh "shasum #{release}.tar.gz #{release}.gem"
|
36
39
|
end
|
37
40
|
|
38
41
|
def release
|
39
|
-
"rack-" + File.read('lib/rack.rb')[/RELEASE += +([\"\'])([\d][\w\.]+)\1/, 2]
|
42
|
+
"rack-" + File.read('lib/rack/version.rb')[/RELEASE += +([\"\'])([\d][\w\.]+)\1/, 2]
|
40
43
|
end
|
41
44
|
|
42
45
|
desc "Make binaries executable"
|
@@ -46,7 +49,7 @@ task :chmod do
|
|
46
49
|
end
|
47
50
|
|
48
51
|
desc "Generate a ChangeLog"
|
49
|
-
task :
|
52
|
+
task changelog: "ChangeLog"
|
50
53
|
|
51
54
|
file '.git/index'
|
52
55
|
file "ChangeLog" => '.git/index' do
|
@@ -68,48 +71,59 @@ file "ChangeLog" => '.git/index' do
|
|
68
71
|
}
|
69
72
|
end
|
70
73
|
|
71
|
-
file 'lib/rack/lint.rb'
|
72
74
|
desc "Generate Rack Specification"
|
73
|
-
|
74
|
-
|
75
|
+
task spec: "SPEC.rdoc"
|
76
|
+
|
77
|
+
file 'lib/rack/lint.rb'
|
78
|
+
file "SPEC.rdoc" => 'lib/rack/lint.rb' do
|
79
|
+
File.open("SPEC.rdoc", "wb") { |file|
|
75
80
|
IO.foreach("lib/rack/lint.rb") { |line|
|
76
|
-
if line =~
|
81
|
+
if line =~ /^\s*## ?(.*)/
|
77
82
|
file.puts $1
|
78
83
|
end
|
79
84
|
}
|
80
85
|
}
|
81
86
|
end
|
82
87
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
88
|
+
Rake::TestTask.new("test:regular") do |t|
|
89
|
+
t.libs << "test"
|
90
|
+
t.test_files = FileList["test/**/*_test.rb", "test/**/spec_*.rb", "test/gemloader.rb"]
|
91
|
+
t.warning = false
|
92
|
+
t.verbose = true
|
93
|
+
end
|
87
94
|
|
88
|
-
|
95
|
+
desc "Run tests with coverage"
|
96
|
+
task "test_cov" do
|
97
|
+
ENV['COVERAGE'] = '1'
|
98
|
+
Rake::Task['test:regular'].invoke
|
89
99
|
end
|
90
100
|
|
101
|
+
desc "Run all the fast + platform agnostic tests"
|
102
|
+
task test: %w[spec test:regular]
|
103
|
+
|
91
104
|
desc "Run all the tests we run on CI"
|
92
|
-
task :
|
105
|
+
task ci: :test
|
93
106
|
|
94
|
-
task :
|
107
|
+
task gem: :spec do
|
95
108
|
sh "gem build rack.gemspec"
|
96
109
|
end
|
97
110
|
|
98
|
-
task :
|
111
|
+
task doc: :rdoc
|
112
|
+
|
99
113
|
desc "Generate RDoc documentation"
|
100
|
-
task :
|
114
|
+
task rdoc: %w[changelog spec] do
|
101
115
|
sh(*%w{rdoc --line-numbers --main README.rdoc
|
102
116
|
--title 'Rack\ Documentation' --charset utf-8 -U -o doc} +
|
103
|
-
%w{README.rdoc KNOWN-ISSUES SPEC ChangeLog} +
|
117
|
+
%w{README.rdoc KNOWN-ISSUES SPEC.rdoc ChangeLog} +
|
104
118
|
`git ls-files lib/\*\*/\*.rb`.strip.split)
|
105
119
|
cp "contrib/rdoc.css", "doc/rdoc.css"
|
106
120
|
end
|
107
121
|
|
108
|
-
task :
|
122
|
+
task pushdoc: :rdoc do
|
109
123
|
sh "rsync -avz doc/ rack.rubyforge.org:/var/www/gforge-projects/rack/doc/"
|
110
124
|
end
|
111
125
|
|
112
|
-
task :
|
126
|
+
task pushsite: :pushdoc do
|
113
127
|
sh "cd site && git gc"
|
114
128
|
sh "rsync -avz site/ rack.rubyforge.org:/var/www/gforge-projects/rack/"
|
115
129
|
sh "cd site && git push"
|
data/{SPEC → SPEC.rdoc}
RENAMED
@@ -1,5 +1,6 @@
|
|
1
1
|
This specification aims to formalize the Rack protocol. You
|
2
2
|
can (and should) use Rack::Lint to enforce it.
|
3
|
+
|
3
4
|
When you develop middleware, be sure to add a Lint before and
|
4
5
|
after to catch all mistakes.
|
5
6
|
= Rack applications
|
@@ -11,9 +12,10 @@ The *status*,
|
|
11
12
|
the *headers*,
|
12
13
|
and the *body*.
|
13
14
|
== The Environment
|
14
|
-
The environment must be an instance of Hash that includes
|
15
|
+
The environment must be an unfrozen instance of Hash that includes
|
15
16
|
CGI-like headers. The application is free to modify the
|
16
17
|
environment.
|
18
|
+
|
17
19
|
The environment is required to include these variables
|
18
20
|
(adopted from PEP333), except when they'd be empty, but see
|
19
21
|
below.
|
@@ -60,9 +62,8 @@ below.
|
|
60
62
|
the presence or absence of the
|
61
63
|
appropriate HTTP header in the
|
62
64
|
request. See
|
63
|
-
{https://tools.ietf.org/html/rfc3875#section-4.1.18
|
64
|
-
|
65
|
-
specific behavior.
|
65
|
+
{RFC3875 section 4.1.18}[https://tools.ietf.org/html/rfc3875#section-4.1.18]
|
66
|
+
for specific behavior.
|
66
67
|
In addition to this, the Rack environment must include these
|
67
68
|
Rack-specific variables:
|
68
69
|
<tt>rack.version</tt>:: The Array representing this version of Rack
|
@@ -98,12 +99,14 @@ Rack-specific variables:
|
|
98
99
|
Additional environment specifications have approved to
|
99
100
|
standardized middleware APIs. None of these are required to
|
100
101
|
be implemented by the server.
|
101
|
-
<tt>rack.session</tt>:: A hash like interface for storing
|
102
|
+
<tt>rack.session</tt>:: A hash like interface for storing
|
103
|
+
request session data.
|
102
104
|
The store must implement:
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
store(key, value) (aliased as []=);
|
106
|
+
fetch(key, default = nil) (aliased as []);
|
107
|
+
delete(key);
|
108
|
+
clear;
|
109
|
+
to_hash (returning unfrozen Hash instance);
|
107
110
|
<tt>rack.logger</tt>:: A common object interface for logging messages.
|
108
111
|
The object must implement:
|
109
112
|
info(message, &block)
|
@@ -118,10 +121,13 @@ environment, too. The keys must contain at least one dot,
|
|
118
121
|
and should be prefixed uniquely. The prefix <tt>rack.</tt>
|
119
122
|
is reserved for use with the Rack core distribution and other
|
120
123
|
accepted specifications and must not be used otherwise.
|
124
|
+
|
121
125
|
The environment must not contain the keys
|
122
126
|
<tt>HTTP_CONTENT_TYPE</tt> or <tt>HTTP_CONTENT_LENGTH</tt>
|
123
127
|
(use the versions without <tt>HTTP_</tt>).
|
124
128
|
The CGI keys (named without a period) must have String values.
|
129
|
+
If the string values for CGI keys contain non-ASCII characters,
|
130
|
+
they should use ASCII-8BIT encoding.
|
125
131
|
There are the following restrictions:
|
126
132
|
* <tt>rack.version</tt> must be an array of Integers.
|
127
133
|
* <tt>rack.url_scheme</tt> must either be +http+ or +https+.
|
@@ -137,6 +143,7 @@ There are the following restrictions:
|
|
137
143
|
<tt>SCRIPT_NAME</tt> is empty.
|
138
144
|
<tt>SCRIPT_NAME</tt> never should be <tt>/</tt>, but instead be empty.
|
139
145
|
=== The Input Stream
|
146
|
+
|
140
147
|
The input stream is an IO-like object which contains the raw HTTP
|
141
148
|
POST data.
|
142
149
|
When applicable, its external encoding must be "ASCII-8BIT" and it
|
@@ -146,14 +153,19 @@ The input stream must respond to +gets+, +each+, +read+ and +rewind+.
|
|
146
153
|
or +nil+ on EOF.
|
147
154
|
* +read+ behaves like IO#read.
|
148
155
|
Its signature is <tt>read([length, [buffer]])</tt>.
|
156
|
+
|
149
157
|
If given, +length+ must be a non-negative Integer (>= 0) or +nil+,
|
150
158
|
and +buffer+ must be a String and may not be nil.
|
159
|
+
|
151
160
|
If +length+ is given and not nil, then this method reads at most
|
152
161
|
+length+ bytes from the input stream.
|
162
|
+
|
153
163
|
If +length+ is not given or nil, then this method reads
|
154
164
|
all data until EOF.
|
165
|
+
|
155
166
|
When EOF is reached, this method returns nil if +length+ is given
|
156
167
|
and not nil, or "" if +length+ is not given or is nil.
|
168
|
+
|
157
169
|
If +buffer+ is given, then the read data will be placed
|
158
170
|
into +buffer+ instead of a newly created String object.
|
159
171
|
* +each+ must be called without arguments and only yield Strings.
|
@@ -175,16 +187,20 @@ The error stream must respond to +puts+, +write+ and +flush+.
|
|
175
187
|
If rack.hijack? is true then rack.hijack must respond to #call.
|
176
188
|
rack.hijack must return the io that will also be assigned (or is
|
177
189
|
already present, in rack.hijack_io.
|
190
|
+
|
178
191
|
rack.hijack_io must respond to:
|
179
192
|
<tt>read, write, read_nonblock, write_nonblock, flush, close,
|
180
193
|
close_read, close_write, closed?</tt>
|
194
|
+
|
181
195
|
The semantics of these IO methods must be a best effort match to
|
182
196
|
those of a normal ruby IO or Socket object, using standard
|
183
197
|
arguments and raising standard exceptions. Servers are encouraged
|
184
198
|
to simply pass on real IO objects, although it is recognized that
|
185
199
|
this approach is not directly compatible with SPDY and HTTP 2.0.
|
200
|
+
|
186
201
|
IO provided in rack.hijack_io should preference the
|
187
202
|
IO::WaitReadable and IO::WaitWritable APIs wherever supported.
|
203
|
+
|
188
204
|
There is a deliberate lack of full specification around
|
189
205
|
rack.hijack_io, as semantics will change from server to server.
|
190
206
|
Users are encouraged to utilize this API with a knowledge of their
|
@@ -192,7 +208,9 @@ server choice, and servers may extend the functionality of
|
|
192
208
|
hijack_io to provide additional features to users. The purpose of
|
193
209
|
rack.hijack is for Rack to "get out of the way", as such, Rack only
|
194
210
|
provides the minimum of specification and support.
|
211
|
+
|
195
212
|
If rack.hijack? is false, then rack.hijack should not be set.
|
213
|
+
|
196
214
|
If rack.hijack? is false, then rack.hijack_io should not be set.
|
197
215
|
==== Response (after headers)
|
198
216
|
It is also possible to hijack a response after the status and headers
|
@@ -201,6 +219,7 @@ In order to do this, an application may set the special header
|
|
201
219
|
<tt>rack.hijack</tt> to an object that responds to <tt>call</tt>
|
202
220
|
accepting an argument that conforms to the <tt>rack.hijack_io</tt>
|
203
221
|
protocol.
|
222
|
+
|
204
223
|
After the headers have been sent, and this hijack callback has been
|
205
224
|
called, the application is now responsible for the remaining lifecycle
|
206
225
|
of the IO. The application is also responsible for maintaining HTTP
|
@@ -209,8 +228,10 @@ applications will have wanted to specify the header Connection:close in
|
|
209
228
|
HTTP/1.1, and not Connection:keep-alive, as there is no protocol for
|
210
229
|
returning hijacked sockets to the web server. For that purpose, use the
|
211
230
|
body streaming API instead (progressively yielding strings via each).
|
231
|
+
|
212
232
|
Servers must ignore the <tt>body</tt> part of the response tuple when
|
213
233
|
the <tt>rack.hijack</tt> response API is in use.
|
234
|
+
|
214
235
|
The special response header <tt>rack.hijack</tt> must only be set
|
215
236
|
if the request env has <tt>rack.hijack?</tt> <tt>true</tt>.
|
216
237
|
==== Conventions
|
@@ -225,9 +246,9 @@ This is an HTTP status. When parsed as integer (+to_i+), it must be
|
|
225
246
|
greater than or equal to 100.
|
226
247
|
=== The Headers
|
227
248
|
The header must respond to +each+, and yield values of key and value.
|
249
|
+
The header keys must be Strings.
|
228
250
|
Special headers starting "rack." are for communicating with the
|
229
251
|
server, and must not be sent back to the client.
|
230
|
-
The header keys must be Strings.
|
231
252
|
The header must not contain a +Status+ key.
|
232
253
|
The header must conform to RFC7230 token specification, i.e. cannot
|
233
254
|
contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}".
|
@@ -244,16 +265,20 @@ There must not be a <tt>Content-Length</tt> header when the
|
|
244
265
|
=== The Body
|
245
266
|
The Body must respond to +each+
|
246
267
|
and must only yield String values.
|
268
|
+
|
247
269
|
The Body itself should not be an instance of String, as this will
|
248
270
|
break in Ruby 1.9.
|
271
|
+
|
249
272
|
If the Body responds to +close+, it will be called after iteration. If
|
250
273
|
the body is replaced by a middleware after action, the original body
|
251
274
|
must be closed first, if it responds to close.
|
275
|
+
|
252
276
|
If the Body responds to +to_path+, it must return a String
|
253
277
|
identifying the location of a file whose contents are identical
|
254
278
|
to that produced by calling +each+; this may be used by the
|
255
279
|
server as an alternative, possibly more efficient way to
|
256
280
|
transport the response.
|
281
|
+
|
257
282
|
The Body commonly is an Array of Strings, the application
|
258
283
|
instance itself, or a File-like object.
|
259
284
|
== Thanks
|
data/bin/rackup
CHANGED
data/example/lobster.ru
CHANGED
data/example/protectedlobster.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack'
|
2
4
|
require 'rack/lobster'
|
3
5
|
|
@@ -11,4 +13,4 @@ protected_lobster.realm = 'Lobster 2.0'
|
|
11
13
|
|
12
14
|
pretty_protected_lobster = Rack::ShowStatus.new(Rack::ShowExceptions.new(protected_lobster))
|
13
15
|
|
14
|
-
Rack::Server.start :
|
16
|
+
Rack::Server.start app: pretty_protected_lobster, Port: 9292
|
data/example/protectedlobster.ru
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
module Auth
|
3
5
|
# Rack::Auth::AbstractHandler implements common authentication functionality.
|
@@ -8,7 +10,7 @@ module Rack
|
|
8
10
|
|
9
11
|
attr_accessor :realm
|
10
12
|
|
11
|
-
def initialize(app, realm=nil, &authenticator)
|
13
|
+
def initialize(app, realm = nil, &authenticator)
|
12
14
|
@app, @realm, @authenticator = app, realm, authenticator
|
13
15
|
end
|
14
16
|
|
data/lib/rack/auth/basic.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'abstract/handler'
|
4
|
+
require_relative 'abstract/request'
|
5
|
+
require 'base64'
|
3
6
|
|
4
7
|
module Rack
|
5
8
|
module Auth
|
@@ -41,11 +44,11 @@ module Rack
|
|
41
44
|
|
42
45
|
class Request < Auth::AbstractRequest
|
43
46
|
def basic?
|
44
|
-
"basic" == scheme
|
47
|
+
"basic" == scheme && credentials.length == 2
|
45
48
|
end
|
46
49
|
|
47
50
|
def credentials
|
48
|
-
@credentials ||=
|
51
|
+
@credentials ||= Base64.decode64(params).split(':', 2)
|
49
52
|
end
|
50
53
|
|
51
54
|
def username
|
data/lib/rack/auth/digest/md5.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../abstract/handler'
|
4
|
+
require_relative 'request'
|
5
|
+
require_relative 'params'
|
6
|
+
require_relative 'nonce'
|
5
7
|
require 'digest/md5'
|
6
8
|
|
7
9
|
module Rack
|
@@ -21,7 +23,7 @@ module Rack
|
|
21
23
|
|
22
24
|
attr_writer :passwords_hashed
|
23
25
|
|
24
|
-
def initialize(app, realm=nil, opaque=nil, &authenticator)
|
26
|
+
def initialize(app, realm = nil, opaque = nil, &authenticator)
|
25
27
|
@passwords_hashed = nil
|
26
28
|
if opaque.nil? and realm.respond_to? :values_at
|
27
29
|
realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed
|
@@ -47,7 +49,7 @@ module Rack
|
|
47
49
|
|
48
50
|
if valid?(auth)
|
49
51
|
if auth.nonce.stale?
|
50
|
-
return unauthorized(challenge(:
|
52
|
+
return unauthorized(challenge(stale: true))
|
51
53
|
else
|
52
54
|
env['REMOTE_USER'] = auth.username
|
53
55
|
|
@@ -61,7 +63,7 @@ module Rack
|
|
61
63
|
|
62
64
|
private
|
63
65
|
|
64
|
-
QOP = 'auth'
|
66
|
+
QOP = 'auth'
|
65
67
|
|
66
68
|
def params(hash = {})
|
67
69
|
Params.new do |params|
|
@@ -106,21 +108,21 @@ module Rack
|
|
106
108
|
alias :H :md5
|
107
109
|
|
108
110
|
def KD(secret, data)
|
109
|
-
H
|
111
|
+
H "#{secret}:#{data}"
|
110
112
|
end
|
111
113
|
|
112
114
|
def A1(auth, password)
|
113
|
-
|
115
|
+
"#{auth.username}:#{auth.realm}:#{password}"
|
114
116
|
end
|
115
117
|
|
116
118
|
def A2(auth)
|
117
|
-
|
119
|
+
"#{auth.method}:#{auth.uri}"
|
118
120
|
end
|
119
121
|
|
120
122
|
def digest(auth, password)
|
121
123
|
password_hash = passwords_hashed? ? password : H(A1(auth, password))
|
122
124
|
|
123
|
-
KD
|
125
|
+
KD password_hash, "#{auth.nonce}:#{auth.nc}:#{auth.cnonce}:#{QOP}:#{H A2(auth)}"
|
124
126
|
end
|
125
127
|
|
126
128
|
end
|
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'digest/md5'
|
4
|
+
require 'base64'
|
2
5
|
|
3
6
|
module Rack
|
4
7
|
module Auth
|
@@ -18,7 +21,7 @@ module Rack
|
|
18
21
|
end
|
19
22
|
|
20
23
|
def self.parse(string)
|
21
|
-
new(*
|
24
|
+
new(*Base64.decode64(string).split(' ', 2))
|
22
25
|
end
|
23
26
|
|
24
27
|
def initialize(timestamp = Time.now, given_digest = nil)
|
@@ -26,11 +29,11 @@ module Rack
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def to_s
|
29
|
-
|
32
|
+
Base64.encode64("#{@timestamp} #{digest}").strip
|
30
33
|
end
|
31
34
|
|
32
35
|
def digest
|
33
|
-
::Digest::MD5.hexdigest(
|
36
|
+
::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}")
|
34
37
|
end
|
35
38
|
|
36
39
|
def valid?
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
module Auth
|
3
5
|
module Digest
|
@@ -38,12 +40,12 @@ module Rack
|
|
38
40
|
|
39
41
|
def to_s
|
40
42
|
map do |k, v|
|
41
|
-
"#{k}
|
43
|
+
"#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}"
|
42
44
|
end.join(', ')
|
43
45
|
end
|
44
46
|
|
45
47
|
def quote(str) # From WEBrick::HTTPUtils
|
46
|
-
'"'
|
48
|
+
'"' + str.gsub(/[\\\"]/o, "\\\1") + '"'
|
47
49
|
end
|
48
50
|
|
49
51
|
end
|
@@ -1,6 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../abstract/request'
|
4
|
+
require_relative 'params'
|
5
|
+
require_relative 'nonce'
|
4
6
|
|
5
7
|
module Rack
|
6
8
|
module Auth
|
data/lib/rack/body_proxy.rb
CHANGED
@@ -1,19 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
4
|
+
# Proxy for response bodies allowing calling a block when
|
5
|
+
# the response body is closed (after the response has been fully
|
6
|
+
# sent to the client).
|
2
7
|
class BodyProxy
|
8
|
+
# Set the response body to wrap, and the block to call when the
|
9
|
+
# response has been fully sent.
|
3
10
|
def initialize(body, &block)
|
4
11
|
@body = body
|
5
12
|
@block = block
|
6
13
|
@closed = false
|
7
14
|
end
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
when :to_ary, 'to_ary'
|
12
|
-
return false
|
13
|
-
end
|
16
|
+
# Return whether the wrapped body responds to the method.
|
17
|
+
def respond_to_missing?(method_name, include_all = false)
|
14
18
|
super or @body.respond_to?(method_name, include_all)
|
15
19
|
end
|
16
20
|
|
21
|
+
# If not already closed, close the wrapped body and
|
22
|
+
# then call the block the proxy was initialized with.
|
17
23
|
def close
|
18
24
|
return if @closed
|
19
25
|
@closed = true
|
@@ -24,21 +30,16 @@ module Rack
|
|
24
30
|
end
|
25
31
|
end
|
26
32
|
|
33
|
+
# Whether the proxy is closed. The proxy starts as not closed,
|
34
|
+
# and becomes closed on the first call to close.
|
27
35
|
def closed?
|
28
36
|
@closed
|
29
37
|
end
|
30
38
|
|
31
|
-
#
|
32
|
-
# We are applying this special case for #each only. Future bugs of this
|
33
|
-
# class will be handled by requesting users to patch their ruby
|
34
|
-
# implementation, to save adding too many methods in this class.
|
35
|
-
def each
|
36
|
-
@body.each { |body| yield body }
|
37
|
-
end
|
38
|
-
|
39
|
+
# Delegate missing methods to the wrapped body.
|
39
40
|
def method_missing(method_name, *args, &block)
|
40
|
-
super if :to_ary == method_name
|
41
41
|
@body.__send__(method_name, *args, &block)
|
42
42
|
end
|
43
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
43
44
|
end
|
44
45
|
end
|