rack 2.0.3 → 2.2.4

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.

Files changed (190) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +708 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +152 -150
  6. data/Rakefile +37 -23
  7. data/{SPEC → SPEC.rdoc} +35 -10
  8. data/bin/rackup +1 -0
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +3 -1
  11. data/example/protectedlobster.ru +2 -0
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +1 -1
  14. data/lib/rack/auth/basic.rb +7 -4
  15. data/lib/rack/auth/digest/md5.rb +13 -11
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +4 -2
  18. data/lib/rack/auth/digest/request.rb +5 -3
  19. data/lib/rack/body_proxy.rb +15 -14
  20. data/lib/rack/builder.rb +116 -23
  21. data/lib/rack/cascade.rb +28 -12
  22. data/lib/rack/chunked.rb +68 -20
  23. data/lib/rack/common_logger.rb +36 -25
  24. data/lib/rack/conditional_get.rb +20 -16
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +8 -7
  27. data/lib/rack/content_type.rb +5 -4
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +59 -34
  30. data/lib/rack/directory.rb +84 -64
  31. data/lib/rack/etag.rb +8 -5
  32. data/lib/rack/events.rb +19 -20
  33. data/lib/rack/file.rb +4 -173
  34. data/lib/rack/files.rb +218 -0
  35. data/lib/rack/handler/cgi.rb +2 -3
  36. data/lib/rack/handler/fastcgi.rb +4 -4
  37. data/lib/rack/handler/lsws.rb +3 -3
  38. data/lib/rack/handler/scgi.rb +9 -8
  39. data/lib/rack/handler/thin.rb +3 -3
  40. data/lib/rack/handler/webrick.rb +15 -6
  41. data/lib/rack/handler.rb +7 -2
  42. data/lib/rack/head.rb +1 -1
  43. data/lib/rack/lint.rb +72 -26
  44. data/lib/rack/lobster.rb +10 -10
  45. data/lib/rack/lock.rb +14 -4
  46. data/lib/rack/logger.rb +2 -0
  47. data/lib/rack/media_type.rb +10 -5
  48. data/lib/rack/method_override.rb +9 -3
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +98 -21
  51. data/lib/rack/multipart/generator.rb +17 -13
  52. data/lib/rack/multipart/parser.rb +61 -63
  53. data/lib/rack/multipart/uploaded_file.rb +15 -7
  54. data/lib/rack/multipart.rb +5 -4
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +59 -30
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +8 -4
  59. data/lib/rack/request.rb +228 -56
  60. data/lib/rack/response.rb +127 -44
  61. data/lib/rack/rewindable_input.rb +4 -3
  62. data/lib/rack/runtime.rb +6 -4
  63. data/lib/rack/sendfile.rb +13 -9
  64. data/lib/rack/server.rb +95 -24
  65. data/lib/rack/session/abstract/id.rb +100 -22
  66. data/lib/rack/session/cookie.rb +22 -14
  67. data/lib/rack/session/memcache.rb +4 -87
  68. data/lib/rack/session/pool.rb +18 -9
  69. data/lib/rack/show_exceptions.rb +22 -18
  70. data/lib/rack/show_status.rb +9 -9
  71. data/lib/rack/static.rb +23 -11
  72. data/lib/rack/tempfile_reaper.rb +1 -1
  73. data/lib/rack/urlmap.rb +12 -6
  74. data/lib/rack/utils.rb +107 -111
  75. data/lib/rack/version.rb +29 -0
  76. data/lib/rack.rb +67 -73
  77. data/rack.gemspec +40 -29
  78. metadata +25 -181
  79. data/HISTORY.md +0 -505
  80. data/test/builder/an_underscore_app.rb +0 -5
  81. data/test/builder/anything.rb +0 -5
  82. data/test/builder/comment.ru +0 -4
  83. data/test/builder/end.ru +0 -5
  84. data/test/builder/line.ru +0 -1
  85. data/test/builder/options.ru +0 -2
  86. data/test/cgi/assets/folder/test.js +0 -1
  87. data/test/cgi/assets/fonts/font.eot +0 -1
  88. data/test/cgi/assets/images/image.png +0 -1
  89. data/test/cgi/assets/index.html +0 -1
  90. data/test/cgi/assets/javascripts/app.js +0 -1
  91. data/test/cgi/assets/stylesheets/app.css +0 -1
  92. data/test/cgi/lighttpd.conf +0 -26
  93. data/test/cgi/rackup_stub.rb +0 -6
  94. data/test/cgi/sample_rackup.ru +0 -5
  95. data/test/cgi/test +0 -9
  96. data/test/cgi/test+directory/test+file +0 -1
  97. data/test/cgi/test.fcgi +0 -9
  98. data/test/cgi/test.gz +0 -0
  99. data/test/cgi/test.ru +0 -5
  100. data/test/gemloader.rb +0 -10
  101. data/test/helper.rb +0 -34
  102. data/test/multipart/bad_robots +0 -259
  103. data/test/multipart/binary +0 -0
  104. data/test/multipart/content_type_and_no_filename +0 -6
  105. data/test/multipart/empty +0 -10
  106. data/test/multipart/fail_16384_nofile +0 -814
  107. data/test/multipart/file1.txt +0 -1
  108. data/test/multipart/filename_and_modification_param +0 -7
  109. data/test/multipart/filename_and_no_name +0 -6
  110. data/test/multipart/filename_with_encoded_words +0 -7
  111. data/test/multipart/filename_with_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  113. data/test/multipart/filename_with_null_byte +0 -7
  114. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  115. data/test/multipart/filename_with_single_quote +0 -7
  116. data/test/multipart/filename_with_unescaped_percentages +0 -6
  117. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  119. data/test/multipart/filename_with_unescaped_quotes +0 -6
  120. data/test/multipart/ie +0 -6
  121. data/test/multipart/invalid_character +0 -6
  122. data/test/multipart/mixed_files +0 -21
  123. data/test/multipart/nested +0 -10
  124. data/test/multipart/none +0 -9
  125. data/test/multipart/quoted +0 -15
  126. data/test/multipart/rack-logo.png +0 -0
  127. data/test/multipart/semicolon +0 -6
  128. data/test/multipart/text +0 -15
  129. data/test/multipart/three_files_three_fields +0 -31
  130. data/test/multipart/unity3d_wwwform +0 -11
  131. data/test/multipart/webkit +0 -32
  132. data/test/rackup/config.ru +0 -31
  133. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  134. data/test/spec_auth_basic.rb +0 -89
  135. data/test/spec_auth_digest.rb +0 -260
  136. data/test/spec_body_proxy.rb +0 -85
  137. data/test/spec_builder.rb +0 -233
  138. data/test/spec_cascade.rb +0 -63
  139. data/test/spec_cgi.rb +0 -84
  140. data/test/spec_chunked.rb +0 -103
  141. data/test/spec_common_logger.rb +0 -95
  142. data/test/spec_conditional_get.rb +0 -103
  143. data/test/spec_config.rb +0 -23
  144. data/test/spec_content_length.rb +0 -86
  145. data/test/spec_content_type.rb +0 -46
  146. data/test/spec_deflater.rb +0 -375
  147. data/test/spec_directory.rb +0 -148
  148. data/test/spec_etag.rb +0 -108
  149. data/test/spec_events.rb +0 -133
  150. data/test/spec_fastcgi.rb +0 -85
  151. data/test/spec_file.rb +0 -264
  152. data/test/spec_handler.rb +0 -57
  153. data/test/spec_head.rb +0 -46
  154. data/test/spec_lint.rb +0 -515
  155. data/test/spec_lobster.rb +0 -59
  156. data/test/spec_lock.rb +0 -194
  157. data/test/spec_logger.rb +0 -24
  158. data/test/spec_media_type.rb +0 -42
  159. data/test/spec_method_override.rb +0 -96
  160. data/test/spec_mime.rb +0 -51
  161. data/test/spec_mock.rb +0 -359
  162. data/test/spec_multipart.rb +0 -722
  163. data/test/spec_null_logger.rb +0 -21
  164. data/test/spec_recursive.rb +0 -75
  165. data/test/spec_request.rb +0 -1393
  166. data/test/spec_response.rb +0 -510
  167. data/test/spec_rewindable_input.rb +0 -128
  168. data/test/spec_runtime.rb +0 -50
  169. data/test/spec_sendfile.rb +0 -125
  170. data/test/spec_server.rb +0 -193
  171. data/test/spec_session_abstract_id.rb +0 -31
  172. data/test/spec_session_abstract_session_hash.rb +0 -45
  173. data/test/spec_session_cookie.rb +0 -442
  174. data/test/spec_session_memcache.rb +0 -320
  175. data/test/spec_session_pool.rb +0 -210
  176. data/test/spec_show_exceptions.rb +0 -80
  177. data/test/spec_show_status.rb +0 -104
  178. data/test/spec_static.rb +0 -184
  179. data/test/spec_tempfile_reaper.rb +0 -64
  180. data/test/spec_thin.rb +0 -96
  181. data/test/spec_urlmap.rb +0 -237
  182. data/test/spec_utils.rb +0 -742
  183. data/test/spec_version.rb +0 -11
  184. data/test/spec_webrick.rb +0 -209
  185. data/test/static/another/index.html +0 -1
  186. data/test/static/foo.html +0 -1
  187. data/test/static/index.html +0 -1
  188. data/test/testrequest.rb +0 -78
  189. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  190. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/Rakefile CHANGED
@@ -1,7 +1,10 @@
1
- # Rakefile for Rack. -*-ruby-*-
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 :default => [:test]
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 :dist => %w[chmod ChangeLog SPEC rdoc] do
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 :officialrelease_really => %w[SPEC dist gem] do
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 :changelog => %w[ChangeLog]
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
- file "SPEC" => 'lib/rack/lint.rb' do
74
- File.open("SPEC", "wb") { |file|
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
- desc "Run all the fast + platform agnostic tests"
84
- task :test => 'SPEC' do
85
- opts = ENV['TEST'] || ''
86
- specopts = ENV['TESTOPTS']
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
- sh "ruby -I./lib:./test -S minitest #{opts} #{specopts} test/gemloader.rb test/spec*.rb"
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 :ci => :test
105
+ task ci: :test
93
106
 
94
- task :gem => ["SPEC"] do
107
+ task gem: :spec do
95
108
  sh "gem build rack.gemspec"
96
109
  end
97
110
 
98
- task :doc => :rdoc
111
+ task doc: :rdoc
112
+
99
113
  desc "Generate RDoc documentation"
100
- task :rdoc => %w[ChangeLog SPEC] do
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 :pushdoc => %w[rdoc] do
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 :pushsite => %w[pushdoc] do
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
- RFC3875 section 4.1.18} for
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 request session data.
102
+ <tt>rack.session</tt>:: A hash like interface for storing
103
+ request session data.
102
104
  The store must implement:
103
- store(key, value) (aliased as []=);
104
- fetch(key, default = nil) (aliased as []);
105
- delete(key);
106
- clear;
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
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "rack"
4
5
  Rack::Server.start
data/example/lobster.ru CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack/lobster'
2
4
 
3
5
  use Rack::ShowExceptions
@@ -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 :app => pretty_protected_lobster, :Port => 9292
16
+ Rack::Server.start app: pretty_protected_lobster, Port: 9292
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack/lobster'
2
4
 
3
5
  use Rack::ShowExceptions
@@ -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
 
@@ -1,4 +1,4 @@
1
- require 'rack/request'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Rack
4
4
  module Auth
@@ -1,5 +1,8 @@
1
- require 'rack/auth/abstract/handler'
2
- require 'rack/auth/abstract/request'
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 ||= params.unpack("m*").first.split(/:/, 2)
51
+ @credentials ||= Base64.decode64(params).split(':', 2)
49
52
  end
50
53
 
51
54
  def username
@@ -1,7 +1,9 @@
1
- require 'rack/auth/abstract/handler'
2
- require 'rack/auth/digest/request'
3
- require 'rack/auth/digest/params'
4
- require 'rack/auth/digest/nonce'
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(:stale => true))
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'.freeze
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([secret, data] * ':')
111
+ H "#{secret}:#{data}"
110
112
  end
111
113
 
112
114
  def A1(auth, password)
113
- [ auth.username, auth.realm, password ] * ':'
115
+ "#{auth.username}:#{auth.realm}:#{password}"
114
116
  end
115
117
 
116
118
  def A2(auth)
117
- [ auth.method, auth.uri ] * ':'
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(password_hash, [ auth.nonce, auth.nc, auth.cnonce, QOP, H(A2(auth)) ] * ':')
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(*string.unpack("m*").first.split(' ', 2))
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
- [([ @timestamp, digest ] * ' ')].pack("m*").strip
32
+ Base64.encode64("#{@timestamp} #{digest}").strip
30
33
  end
31
34
 
32
35
  def digest
33
- ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':')
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}=" << (UNQUOTED.include?(k) ? v.to_s : quote(v))
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
- '"' << str.gsub(/[\\\"]/o, "\\\1") << '"'
48
+ '"' + str.gsub(/[\\\"]/o, "\\\1") + '"'
47
49
  end
48
50
 
49
51
  end
@@ -1,6 +1,8 @@
1
- require 'rack/auth/abstract/request'
2
- require 'rack/auth/digest/params'
3
- require 'rack/auth/digest/nonce'
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
@@ -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
- def respond_to?(method_name, include_all=false)
10
- case method_name
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
- # N.B. This method is a special case to address the bug described by #434.
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