rack 2.0.1 → 2.2.17

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.
Files changed (189) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +795 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +188 -145
  6. data/Rakefile +37 -23
  7. data/{SPEC → SPEC.rdoc} +46 -17
  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 +6 -4
  15. data/lib/rack/auth/digest/md5.rb +13 -11
  16. data/lib/rack/auth/digest/nonce.rb +5 -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 +37 -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 +60 -70
  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 +19 -10
  41. data/lib/rack/handler.rb +7 -2
  42. data/lib/rack/head.rb +1 -1
  43. data/lib/rack/lint.rb +221 -186
  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 +23 -8
  48. data/lib/rack/method_override.rb +13 -4
  49. data/lib/rack/mime.rb +9 -1
  50. data/lib/rack/mock.rb +135 -29
  51. data/lib/rack/multipart/generator.rb +17 -13
  52. data/lib/rack/multipart/parser.rb +85 -68
  53. data/lib/rack/multipart/uploaded_file.rb +15 -7
  54. data/lib/rack/multipart.rb +6 -5
  55. data/lib/rack/null_logger.rb +2 -0
  56. data/lib/rack/query_parser.rb +108 -36
  57. data/lib/rack/recursive.rb +7 -5
  58. data/lib/rack/reloader.rb +8 -4
  59. data/lib/rack/request.rb +232 -60
  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 +14 -10
  64. data/lib/rack/server.rb +97 -25
  65. data/lib/rack/session/abstract/id.rb +113 -25
  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 +24 -10
  69. data/lib/rack/show_exceptions.rb +22 -18
  70. data/lib/rack/show_status.rb +9 -9
  71. data/lib/rack/static.rb +25 -12
  72. data/lib/rack/tempfile_reaper.rb +1 -1
  73. data/lib/rack/urlmap.rb +13 -7
  74. data/lib/rack/utils.rb +135 -123
  75. data/lib/rack/version.rb +29 -0
  76. data/lib/rack.rb +67 -73
  77. data/rack.gemspec +40 -29
  78. metadata +25 -184
  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_percent_escaped_quotes +0 -6
  114. data/test/multipart/filename_with_single_quote +0 -7
  115. data/test/multipart/filename_with_unescaped_percentages +0 -6
  116. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  117. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  118. data/test/multipart/filename_with_unescaped_quotes +0 -6
  119. data/test/multipart/ie +0 -6
  120. data/test/multipart/invalid_character +0 -6
  121. data/test/multipart/mixed_files +0 -21
  122. data/test/multipart/nested +0 -10
  123. data/test/multipart/none +0 -9
  124. data/test/multipart/quoted +0 -15
  125. data/test/multipart/rack-logo.png +0 -0
  126. data/test/multipart/semicolon +0 -6
  127. data/test/multipart/text +0 -15
  128. data/test/multipart/three_files_three_fields +0 -31
  129. data/test/multipart/unity3d_wwwform +0 -11
  130. data/test/multipart/webkit +0 -32
  131. data/test/rackup/config.ru +0 -31
  132. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  133. data/test/spec_auth_basic.rb +0 -89
  134. data/test/spec_auth_digest.rb +0 -260
  135. data/test/spec_body_proxy.rb +0 -85
  136. data/test/spec_builder.rb +0 -233
  137. data/test/spec_cascade.rb +0 -63
  138. data/test/spec_cgi.rb +0 -84
  139. data/test/spec_chunked.rb +0 -103
  140. data/test/spec_common_logger.rb +0 -95
  141. data/test/spec_conditional_get.rb +0 -103
  142. data/test/spec_config.rb +0 -23
  143. data/test/spec_content_length.rb +0 -86
  144. data/test/spec_content_type.rb +0 -46
  145. data/test/spec_deflater.rb +0 -365
  146. data/test/spec_directory.rb +0 -148
  147. data/test/spec_etag.rb +0 -108
  148. data/test/spec_events.rb +0 -133
  149. data/test/spec_fastcgi.rb +0 -85
  150. data/test/spec_file.rb +0 -251
  151. data/test/spec_handler.rb +0 -57
  152. data/test/spec_head.rb +0 -46
  153. data/test/spec_lint.rb +0 -515
  154. data/test/spec_lobster.rb +0 -59
  155. data/test/spec_lock.rb +0 -194
  156. data/test/spec_logger.rb +0 -24
  157. data/test/spec_media_type.rb +0 -42
  158. data/test/spec_method_override.rb +0 -83
  159. data/test/spec_mime.rb +0 -51
  160. data/test/spec_mock.rb +0 -342
  161. data/test/spec_multipart.rb +0 -716
  162. data/test/spec_null_logger.rb +0 -21
  163. data/test/spec_recursive.rb +0 -75
  164. data/test/spec_request.rb +0 -1393
  165. data/test/spec_response.rb +0 -510
  166. data/test/spec_rewindable_input.rb +0 -128
  167. data/test/spec_runtime.rb +0 -50
  168. data/test/spec_sendfile.rb +0 -125
  169. data/test/spec_server.rb +0 -193
  170. data/test/spec_session_abstract_id.rb +0 -31
  171. data/test/spec_session_abstract_session_hash.rb +0 -28
  172. data/test/spec_session_cookie.rb +0 -442
  173. data/test/spec_session_memcache.rb +0 -320
  174. data/test/spec_session_pool.rb +0 -210
  175. data/test/spec_show_exceptions.rb +0 -80
  176. data/test/spec_show_status.rb +0 -104
  177. data/test/spec_static.rb +0 -184
  178. data/test/spec_tempfile_reaper.rb +0 -64
  179. data/test/spec_thin.rb +0 -96
  180. data/test/spec_urlmap.rb +0 -237
  181. data/test/spec_utils.rb +0 -742
  182. data/test/spec_version.rb +0 -11
  183. data/test/spec_webrick.rb +0 -208
  184. data/test/static/another/index.html +0 -1
  185. data/test/static/foo.html +0 -1
  186. data/test/static/index.html +0 -1
  187. data/test/testrequest.rb +0 -78
  188. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  189. 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.
@@ -40,17 +42,18 @@ below.
40
42
  <tt>QUERY_STRING</tt>:: The portion of the request URL that
41
43
  follows the <tt>?</tt>, if any. May be
42
44
  empty, but is always required!
43
- <tt>SERVER_NAME</tt>, <tt>SERVER_PORT</tt>::
44
- When combined with <tt>SCRIPT_NAME</tt> and
45
+ <tt>SERVER_NAME</tt>:: When combined with <tt>SCRIPT_NAME</tt> and
45
46
  <tt>PATH_INFO</tt>, these variables can be
46
47
  used to complete the URL. Note, however,
47
48
  that <tt>HTTP_HOST</tt>, if present,
48
49
  should be used in preference to
49
50
  <tt>SERVER_NAME</tt> for reconstructing
50
51
  the request URL.
51
- <tt>SERVER_NAME</tt> and <tt>SERVER_PORT</tt>
52
- can never be empty strings, and so
53
- are always required.
52
+ <tt>SERVER_NAME</tt> can never be an empty
53
+ string, and so is always required.
54
+ <tt>SERVER_PORT</tt>:: An optional +Integer+ which is the port the
55
+ server is running on. Should be specified if
56
+ the server is running on a non-standard port.
54
57
  <tt>HTTP_</tt> Variables:: Variables corresponding to the
55
58
  client-supplied HTTP request
56
59
  headers (i.e., variables whose
@@ -60,9 +63,8 @@ below.
60
63
  the presence or absence of the
61
64
  appropriate HTTP header in the
62
65
  request. See
63
- {https://tools.ietf.org/html/rfc3875#section-4.1.18
64
- RFC3875 section 4.1.18} for
65
- specific behavior.
66
+ {RFC3875 section 4.1.18}[https://tools.ietf.org/html/rfc3875#section-4.1.18]
67
+ for specific behavior.
66
68
  In addition to this, the Rack environment must include these
67
69
  Rack-specific variables:
68
70
  <tt>rack.version</tt>:: The Array representing this version of Rack
@@ -98,12 +100,14 @@ Rack-specific variables:
98
100
  Additional environment specifications have approved to
99
101
  standardized middleware APIs. None of these are required to
100
102
  be implemented by the server.
101
- <tt>rack.session</tt>:: A hash like interface for storing request session data.
103
+ <tt>rack.session</tt>:: A hash like interface for storing
104
+ request session data.
102
105
  The store must implement:
103
- store(key, value) (aliased as []=);
104
- fetch(key, default = nil) (aliased as []);
105
- delete(key);
106
- clear;
106
+ store(key, value) (aliased as []=);
107
+ fetch(key, default = nil) (aliased as []);
108
+ delete(key);
109
+ clear;
110
+ to_hash (returning unfrozen Hash instance);
107
111
  <tt>rack.logger</tt>:: A common object interface for logging messages.
108
112
  The object must implement:
109
113
  info(message, &block)
@@ -118,10 +122,16 @@ environment, too. The keys must contain at least one dot,
118
122
  and should be prefixed uniquely. The prefix <tt>rack.</tt>
119
123
  is reserved for use with the Rack core distribution and other
120
124
  accepted specifications and must not be used otherwise.
125
+
126
+ The <tt>SERVER_PORT</tt> must be an Integer if set.
127
+ The <tt>SERVER_NAME</tt> must be a valid authority as defined by RFC7540.
128
+ The <tt>HTTP_HOST</tt> must be a valid authority as defined by RFC7540.
121
129
  The environment must not contain the keys
122
130
  <tt>HTTP_CONTENT_TYPE</tt> or <tt>HTTP_CONTENT_LENGTH</tt>
123
131
  (use the versions without <tt>HTTP_</tt>).
124
132
  The CGI keys (named without a period) must have String values.
133
+ If the string values for CGI keys contain non-ASCII characters,
134
+ they should use ASCII-8BIT encoding.
125
135
  There are the following restrictions:
126
136
  * <tt>rack.version</tt> must be an array of Integers.
127
137
  * <tt>rack.url_scheme</tt> must either be +http+ or +https+.
@@ -137,6 +147,7 @@ There are the following restrictions:
137
147
  <tt>SCRIPT_NAME</tt> is empty.
138
148
  <tt>SCRIPT_NAME</tt> never should be <tt>/</tt>, but instead be empty.
139
149
  === The Input Stream
150
+
140
151
  The input stream is an IO-like object which contains the raw HTTP
141
152
  POST data.
142
153
  When applicable, its external encoding must be "ASCII-8BIT" and it
@@ -146,14 +157,19 @@ The input stream must respond to +gets+, +each+, +read+ and +rewind+.
146
157
  or +nil+ on EOF.
147
158
  * +read+ behaves like IO#read.
148
159
  Its signature is <tt>read([length, [buffer]])</tt>.
160
+
149
161
  If given, +length+ must be a non-negative Integer (>= 0) or +nil+,
150
162
  and +buffer+ must be a String and may not be nil.
163
+
151
164
  If +length+ is given and not nil, then this method reads at most
152
165
  +length+ bytes from the input stream.
166
+
153
167
  If +length+ is not given or nil, then this method reads
154
168
  all data until EOF.
169
+
155
170
  When EOF is reached, this method returns nil if +length+ is given
156
171
  and not nil, or "" if +length+ is not given or is nil.
172
+
157
173
  If +buffer+ is given, then the read data will be placed
158
174
  into +buffer+ instead of a newly created String object.
159
175
  * +each+ must be called without arguments and only yield Strings.
@@ -175,16 +191,20 @@ The error stream must respond to +puts+, +write+ and +flush+.
175
191
  If rack.hijack? is true then rack.hijack must respond to #call.
176
192
  rack.hijack must return the io that will also be assigned (or is
177
193
  already present, in rack.hijack_io.
194
+
178
195
  rack.hijack_io must respond to:
179
196
  <tt>read, write, read_nonblock, write_nonblock, flush, close,
180
197
  close_read, close_write, closed?</tt>
198
+
181
199
  The semantics of these IO methods must be a best effort match to
182
200
  those of a normal ruby IO or Socket object, using standard
183
201
  arguments and raising standard exceptions. Servers are encouraged
184
202
  to simply pass on real IO objects, although it is recognized that
185
203
  this approach is not directly compatible with SPDY and HTTP 2.0.
204
+
186
205
  IO provided in rack.hijack_io should preference the
187
206
  IO::WaitReadable and IO::WaitWritable APIs wherever supported.
207
+
188
208
  There is a deliberate lack of full specification around
189
209
  rack.hijack_io, as semantics will change from server to server.
190
210
  Users are encouraged to utilize this API with a knowledge of their
@@ -192,7 +212,9 @@ server choice, and servers may extend the functionality of
192
212
  hijack_io to provide additional features to users. The purpose of
193
213
  rack.hijack is for Rack to "get out of the way", as such, Rack only
194
214
  provides the minimum of specification and support.
215
+
195
216
  If rack.hijack? is false, then rack.hijack should not be set.
217
+
196
218
  If rack.hijack? is false, then rack.hijack_io should not be set.
197
219
  ==== Response (after headers)
198
220
  It is also possible to hijack a response after the status and headers
@@ -201,6 +223,7 @@ In order to do this, an application may set the special header
201
223
  <tt>rack.hijack</tt> to an object that responds to <tt>call</tt>
202
224
  accepting an argument that conforms to the <tt>rack.hijack_io</tt>
203
225
  protocol.
226
+
204
227
  After the headers have been sent, and this hijack callback has been
205
228
  called, the application is now responsible for the remaining lifecycle
206
229
  of the IO. The application is also responsible for maintaining HTTP
@@ -209,8 +232,10 @@ applications will have wanted to specify the header Connection:close in
209
232
  HTTP/1.1, and not Connection:keep-alive, as there is no protocol for
210
233
  returning hijacked sockets to the web server. For that purpose, use the
211
234
  body streaming API instead (progressively yielding strings via each).
235
+
212
236
  Servers must ignore the <tt>body</tt> part of the response tuple when
213
237
  the <tt>rack.hijack</tt> response API is in use.
238
+
214
239
  The special response header <tt>rack.hijack</tt> must only be set
215
240
  if the request env has <tt>rack.hijack?</tt> <tt>true</tt>.
216
241
  ==== Conventions
@@ -225,9 +250,9 @@ This is an HTTP status. When parsed as integer (+to_i+), it must be
225
250
  greater than or equal to 100.
226
251
  === The Headers
227
252
  The header must respond to +each+, and yield values of key and value.
253
+ The header keys must be Strings.
228
254
  Special headers starting "rack." are for communicating with the
229
255
  server, and must not be sent back to the client.
230
- The header keys must be Strings.
231
256
  The header must not contain a +Status+ key.
232
257
  The header must conform to RFC7230 token specification, i.e. cannot
233
258
  contain non-printable ASCII, DQUOTE or "(),/:;<=>?@[\]{}".
@@ -237,23 +262,27 @@ consisting of lines (for multiple header values, e.g. multiple
237
262
  The lines must not contain characters below 037.
238
263
  === The Content-Type
239
264
  There must not be a <tt>Content-Type</tt>, when the +Status+ is 1xx,
240
- 204, 205 or 304.
265
+ 204 or 304.
241
266
  === The Content-Length
242
267
  There must not be a <tt>Content-Length</tt> header when the
243
- +Status+ is 1xx, 204, 205 or 304.
268
+ +Status+ is 1xx, 204 or 304.
244
269
  === The Body
245
270
  The Body must respond to +each+
246
271
  and must only yield String values.
272
+
247
273
  The Body itself should not be an instance of String, as this will
248
274
  break in Ruby 1.9.
275
+
249
276
  If the Body responds to +close+, it will be called after iteration. If
250
277
  the body is replaced by a middleware after action, the original body
251
278
  must be closed first, if it responds to close.
279
+
252
280
  If the Body responds to +to_path+, it must return a String
253
281
  identifying the location of a file whose contents are identical
254
282
  to that produced by calling +each+; this may be used by the
255
283
  server as an alternative, possibly more efficient way to
256
284
  transport the response.
285
+
257
286
  The Body commonly is an Array of Strings, the application
258
287
  instance itself, or a File-like object.
259
288
  == 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,7 @@
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'
3
5
 
4
6
  module Rack
5
7
  module Auth
@@ -41,11 +43,11 @@ module Rack
41
43
 
42
44
  class Request < Auth::AbstractRequest
43
45
  def basic?
44
- "basic" == scheme
46
+ "basic" == scheme && credentials.length == 2
45
47
  end
46
48
 
47
49
  def credentials
48
- @credentials ||= params.unpack("m*").first.split(/:/, 2)
50
+ @credentials ||= params.unpack("m").first.split(':', 2)
49
51
  end
50
52
 
51
53
  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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'digest/md5'
2
4
 
3
5
  module Rack
@@ -18,7 +20,7 @@ module Rack
18
20
  end
19
21
 
20
22
  def self.parse(string)
21
- new(*string.unpack("m*").first.split(' ', 2))
23
+ new(*string.unpack("m").first.split(' ', 2))
22
24
  end
23
25
 
24
26
  def initialize(timestamp = Time.now, given_digest = nil)
@@ -26,11 +28,11 @@ module Rack
26
28
  end
27
29
 
28
30
  def to_s
29
- [([ @timestamp, digest ] * ' ')].pack("m*").strip
31
+ ["#{@timestamp} #{digest}"].pack("m").strip
30
32
  end
31
33
 
32
34
  def digest
33
- ::Digest::MD5.hexdigest([ @timestamp, self.class.private_key ] * ':')
35
+ ::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}")
34
36
  end
35
37
 
36
38
  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