rack 2.0.9.3 → 3.0.0

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 (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +808 -0
  3. data/CONTRIBUTING.md +142 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.md +293 -0
  6. data/SPEC.rdoc +340 -0
  7. data/lib/rack/auth/abstract/handler.rb +6 -2
  8. data/lib/rack/auth/abstract/request.rb +4 -2
  9. data/lib/rack/auth/basic.rb +7 -4
  10. data/lib/rack/auth/digest/md5.rb +1 -129
  11. data/lib/rack/auth/digest/nonce.rb +1 -51
  12. data/lib/rack/auth/digest/params.rb +1 -52
  13. data/lib/rack/auth/digest/request.rb +1 -41
  14. data/lib/rack/auth/digest.rb +256 -0
  15. data/lib/rack/body_proxy.rb +18 -15
  16. data/lib/rack/builder.rb +151 -40
  17. data/lib/rack/cascade.rb +30 -12
  18. data/lib/rack/chunked.rb +74 -23
  19. data/lib/rack/common_logger.rb +49 -36
  20. data/lib/rack/conditional_get.rb +33 -26
  21. data/lib/rack/config.rb +2 -0
  22. data/lib/rack/constants.rb +63 -0
  23. data/lib/rack/content_length.rb +13 -16
  24. data/lib/rack/content_type.rb +12 -8
  25. data/lib/rack/deflater.rb +84 -45
  26. data/lib/rack/directory.rb +90 -64
  27. data/lib/rack/etag.rb +17 -23
  28. data/lib/rack/events.rb +23 -20
  29. data/lib/rack/file.rb +5 -172
  30. data/lib/rack/files.rb +216 -0
  31. data/lib/rack/head.rb +10 -9
  32. data/lib/rack/headers.rb +154 -0
  33. data/lib/rack/lint.rb +786 -645
  34. data/lib/rack/lock.rb +4 -6
  35. data/lib/rack/logger.rb +4 -0
  36. data/lib/rack/media_type.rb +10 -5
  37. data/lib/rack/method_override.rb +8 -2
  38. data/lib/rack/mime.rb +17 -1
  39. data/lib/rack/mock.rb +2 -195
  40. data/lib/rack/mock_request.rb +166 -0
  41. data/lib/rack/mock_response.rb +126 -0
  42. data/lib/rack/multipart/generator.rb +21 -15
  43. data/lib/rack/multipart/parser.rb +161 -118
  44. data/lib/rack/multipart/uploaded_file.rb +19 -7
  45. data/lib/rack/multipart.rb +23 -41
  46. data/lib/rack/null_logger.rb +11 -0
  47. data/lib/rack/query_parser.rb +126 -65
  48. data/lib/rack/recursive.rb +9 -5
  49. data/lib/rack/reloader.rb +6 -4
  50. data/lib/rack/request.rb +331 -74
  51. data/lib/rack/response.rb +223 -70
  52. data/lib/rack/rewindable_input.rb +28 -8
  53. data/lib/rack/runtime.rb +11 -8
  54. data/lib/rack/sendfile.rb +42 -33
  55. data/lib/rack/show_exceptions.rb +35 -18
  56. data/lib/rack/show_status.rb +25 -15
  57. data/lib/rack/static.rb +30 -18
  58. data/lib/rack/tempfile_reaper.rb +16 -5
  59. data/lib/rack/urlmap.rb +14 -6
  60. data/lib/rack/utils.rb +268 -260
  61. data/lib/rack/version.rb +34 -0
  62. data/lib/rack.rb +15 -92
  63. metadata +44 -207
  64. data/HISTORY.md +0 -520
  65. data/README.rdoc +0 -316
  66. data/Rakefile +0 -116
  67. data/SPEC +0 -263
  68. data/bin/rackup +0 -4
  69. data/contrib/rack.png +0 -0
  70. data/contrib/rack.svg +0 -150
  71. data/contrib/rack_logo.svg +0 -164
  72. data/contrib/rdoc.css +0 -412
  73. data/example/lobster.ru +0 -4
  74. data/example/protectedlobster.rb +0 -14
  75. data/example/protectedlobster.ru +0 -8
  76. data/lib/rack/handler/cgi.rb +0 -60
  77. data/lib/rack/handler/fastcgi.rb +0 -100
  78. data/lib/rack/handler/lsws.rb +0 -61
  79. data/lib/rack/handler/scgi.rb +0 -70
  80. data/lib/rack/handler/thin.rb +0 -36
  81. data/lib/rack/handler/webrick.rb +0 -120
  82. data/lib/rack/handler.rb +0 -99
  83. data/lib/rack/lobster.rb +0 -70
  84. data/lib/rack/server.rb +0 -395
  85. data/lib/rack/session/abstract/id.rb +0 -510
  86. data/lib/rack/session/cookie.rb +0 -204
  87. data/lib/rack/session/memcache.rb +0 -99
  88. data/lib/rack/session/pool.rb +0 -83
  89. data/rack.gemspec +0 -34
  90. data/test/builder/an_underscore_app.rb +0 -5
  91. data/test/builder/anything.rb +0 -5
  92. data/test/builder/comment.ru +0 -4
  93. data/test/builder/end.ru +0 -5
  94. data/test/builder/line.ru +0 -1
  95. data/test/builder/options.ru +0 -2
  96. data/test/cgi/assets/folder/test.js +0 -1
  97. data/test/cgi/assets/fonts/font.eot +0 -1
  98. data/test/cgi/assets/images/image.png +0 -1
  99. data/test/cgi/assets/index.html +0 -1
  100. data/test/cgi/assets/javascripts/app.js +0 -1
  101. data/test/cgi/assets/stylesheets/app.css +0 -1
  102. data/test/cgi/lighttpd.conf +0 -26
  103. data/test/cgi/rackup_stub.rb +0 -6
  104. data/test/cgi/sample_rackup.ru +0 -5
  105. data/test/cgi/test +0 -9
  106. data/test/cgi/test+directory/test+file +0 -1
  107. data/test/cgi/test.fcgi +0 -9
  108. data/test/cgi/test.gz +0 -0
  109. data/test/cgi/test.ru +0 -5
  110. data/test/gemloader.rb +0 -10
  111. data/test/helper.rb +0 -34
  112. data/test/multipart/bad_robots +0 -259
  113. data/test/multipart/binary +0 -0
  114. data/test/multipart/content_type_and_no_filename +0 -6
  115. data/test/multipart/empty +0 -10
  116. data/test/multipart/fail_16384_nofile +0 -814
  117. data/test/multipart/file1.txt +0 -1
  118. data/test/multipart/filename_and_modification_param +0 -7
  119. data/test/multipart/filename_and_no_name +0 -6
  120. data/test/multipart/filename_with_encoded_words +0 -7
  121. data/test/multipart/filename_with_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  123. data/test/multipart/filename_with_null_byte +0 -7
  124. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  125. data/test/multipart/filename_with_single_quote +0 -7
  126. data/test/multipart/filename_with_unescaped_percentages +0 -6
  127. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  128. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  129. data/test/multipart/filename_with_unescaped_quotes +0 -6
  130. data/test/multipart/ie +0 -6
  131. data/test/multipart/invalid_character +0 -6
  132. data/test/multipart/mixed_files +0 -21
  133. data/test/multipart/nested +0 -10
  134. data/test/multipart/none +0 -9
  135. data/test/multipart/quoted +0 -15
  136. data/test/multipart/rack-logo.png +0 -0
  137. data/test/multipart/semicolon +0 -6
  138. data/test/multipart/text +0 -15
  139. data/test/multipart/three_files_three_fields +0 -31
  140. data/test/multipart/unity3d_wwwform +0 -11
  141. data/test/multipart/webkit +0 -32
  142. data/test/rackup/config.ru +0 -31
  143. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  144. data/test/spec_auth_basic.rb +0 -89
  145. data/test/spec_auth_digest.rb +0 -260
  146. data/test/spec_body_proxy.rb +0 -85
  147. data/test/spec_builder.rb +0 -233
  148. data/test/spec_cascade.rb +0 -63
  149. data/test/spec_cgi.rb +0 -84
  150. data/test/spec_chunked.rb +0 -103
  151. data/test/spec_common_logger.rb +0 -107
  152. data/test/spec_conditional_get.rb +0 -103
  153. data/test/spec_config.rb +0 -23
  154. data/test/spec_content_length.rb +0 -86
  155. data/test/spec_content_type.rb +0 -46
  156. data/test/spec_deflater.rb +0 -375
  157. data/test/spec_directory.rb +0 -148
  158. data/test/spec_etag.rb +0 -108
  159. data/test/spec_events.rb +0 -133
  160. data/test/spec_fastcgi.rb +0 -85
  161. data/test/spec_file.rb +0 -264
  162. data/test/spec_handler.rb +0 -57
  163. data/test/spec_head.rb +0 -46
  164. data/test/spec_lint.rb +0 -520
  165. data/test/spec_lobster.rb +0 -59
  166. data/test/spec_lock.rb +0 -204
  167. data/test/spec_logger.rb +0 -24
  168. data/test/spec_media_type.rb +0 -42
  169. data/test/spec_method_override.rb +0 -110
  170. data/test/spec_mime.rb +0 -51
  171. data/test/spec_mock.rb +0 -359
  172. data/test/spec_multipart.rb +0 -721
  173. data/test/spec_null_logger.rb +0 -21
  174. data/test/spec_recursive.rb +0 -75
  175. data/test/spec_request.rb +0 -1423
  176. data/test/spec_response.rb +0 -528
  177. data/test/spec_rewindable_input.rb +0 -128
  178. data/test/spec_runtime.rb +0 -50
  179. data/test/spec_sendfile.rb +0 -125
  180. data/test/spec_server.rb +0 -193
  181. data/test/spec_session_abstract_id.rb +0 -31
  182. data/test/spec_session_abstract_session_hash.rb +0 -45
  183. data/test/spec_session_cookie.rb +0 -442
  184. data/test/spec_session_memcache.rb +0 -357
  185. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  186. data/test/spec_session_pool.rb +0 -247
  187. data/test/spec_show_exceptions.rb +0 -93
  188. data/test/spec_show_status.rb +0 -104
  189. data/test/spec_static.rb +0 -184
  190. data/test/spec_tempfile_reaper.rb +0 -64
  191. data/test/spec_thin.rb +0 -96
  192. data/test/spec_urlmap.rb +0 -237
  193. data/test/spec_utils.rb +0 -742
  194. data/test/spec_version.rb +0 -11
  195. data/test/spec_webrick.rb +0 -206
  196. data/test/static/another/index.html +0 -1
  197. data/test/static/foo.html +0 -1
  198. data/test/static/index.html +0 -1
  199. data/test/testrequest.rb +0 -78
  200. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  201. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/sendfile.rb CHANGED
@@ -1,33 +1,36 @@
1
- require 'rack/file'
2
- require 'rack/body_proxy'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'constants'
4
+ require_relative 'utils'
5
+ require_relative 'body_proxy'
3
6
 
4
7
  module Rack
5
8
 
6
9
  # = Sendfile
7
10
  #
8
11
  # The Sendfile middleware intercepts responses whose body is being
9
- # served from a file and replaces it with a server specific X-Sendfile
12
+ # served from a file and replaces it with a server specific x-sendfile
10
13
  # header. The web server is then responsible for writing the file contents
11
14
  # to the client. This can dramatically reduce the amount of work required
12
15
  # by the Ruby backend and takes advantage of the web server's optimized file
13
16
  # delivery code.
14
17
  #
15
18
  # In order to take advantage of this middleware, the response body must
16
- # respond to +to_path+ and the request must include an X-Sendfile-Type
17
- # header. Rack::File and other components implement +to_path+ so there's
18
- # rarely anything you need to do in your application. The X-Sendfile-Type
19
+ # respond to +to_path+ and the request must include an x-sendfile-type
20
+ # header. Rack::Files and other components implement +to_path+ so there's
21
+ # rarely anything you need to do in your application. The x-sendfile-type
19
22
  # header is typically set in your web servers configuration. The following
20
23
  # sections attempt to document
21
24
  #
22
25
  # === Nginx
23
26
  #
24
- # Nginx supports the X-Accel-Redirect header. This is similar to X-Sendfile
27
+ # Nginx supports the x-accel-redirect header. This is similar to x-sendfile
25
28
  # but requires parts of the filesystem to be mapped into a private URL
26
29
  # hierarchy.
27
30
  #
28
31
  # The following example shows the Nginx configuration required to create
29
- # a private "/files/" area, enable X-Accel-Redirect, and pass the special
30
- # X-Sendfile-Type and X-Accel-Mapping headers to the backend:
32
+ # a private "/files/" area, enable x-accel-redirect, and pass the special
33
+ # x-sendfile-type and x-accel-mapping headers to the backend:
31
34
  #
32
35
  # location ~ /files/(.*) {
33
36
  # internal;
@@ -41,24 +44,24 @@ module Rack
41
44
  # proxy_set_header X-Real-IP $remote_addr;
42
45
  # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
43
46
  #
44
- # proxy_set_header X-Sendfile-Type X-Accel-Redirect;
45
- # proxy_set_header X-Accel-Mapping /var/www/=/files/;
47
+ # proxy_set_header x-sendfile-type x-accel-redirect;
48
+ # proxy_set_header x-accel-mapping /var/www/=/files/;
46
49
  #
47
50
  # proxy_pass http://127.0.0.1:8080/;
48
51
  # }
49
52
  #
50
- # Note that the X-Sendfile-Type header must be set exactly as shown above.
51
- # The X-Accel-Mapping header should specify the location on the file system,
53
+ # Note that the x-sendfile-type header must be set exactly as shown above.
54
+ # The x-accel-mapping header should specify the location on the file system,
52
55
  # followed by an equals sign (=), followed name of the private URL pattern
53
56
  # that it maps to. The middleware performs a simple substitution on the
54
57
  # resulting path.
55
58
  #
56
- # See Also: http://wiki.codemongers.com/NginxXSendfile
59
+ # See Also: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile
57
60
  #
58
61
  # === lighttpd
59
62
  #
60
- # Lighttpd has supported some variation of the X-Sendfile header for some
61
- # time, although only recent version support X-Sendfile in a reverse proxy
63
+ # Lighttpd has supported some variation of the x-sendfile header for some
64
+ # time, although only recent version support x-sendfile in a reverse proxy
62
65
  # configuration.
63
66
  #
64
67
  # $HTTP["host"] == "example.com" {
@@ -72,7 +75,7 @@ module Rack
72
75
  #
73
76
  # proxy-core.allow-x-sendfile = "enable"
74
77
  # proxy-core.rewrite-request = (
75
- # "X-Sendfile-Type" => (".*" => "X-Sendfile")
78
+ # "x-sendfile-type" => (".*" => "x-sendfile")
76
79
  # )
77
80
  # }
78
81
  #
@@ -80,26 +83,26 @@ module Rack
80
83
  #
81
84
  # === Apache
82
85
  #
83
- # X-Sendfile is supported under Apache 2.x using a separate module:
86
+ # x-sendfile is supported under Apache 2.x using a separate module:
84
87
  #
85
88
  # https://tn123.org/mod_xsendfile/
86
89
  #
87
90
  # Once the module is compiled and installed, you can enable it using
88
91
  # XSendFile config directive:
89
92
  #
90
- # RequestHeader Set X-Sendfile-Type X-Sendfile
93
+ # RequestHeader Set x-sendfile-type x-sendfile
91
94
  # ProxyPassReverse / http://localhost:8001/
92
95
  # XSendFile on
93
96
  #
94
97
  # === Mapping parameter
95
98
  #
96
99
  # The third parameter allows for an overriding extension of the
97
- # X-Accel-Mapping header. Mappings should be provided in tuples of internal to
100
+ # x-accel-mapping header. Mappings should be provided in tuples of internal to
98
101
  # external. The internal values may contain regular expression syntax, they
99
102
  # will be matched with case indifference.
100
103
 
101
104
  class Sendfile
102
- def initialize(app, variation=nil, mappings=[])
105
+ def initialize(app, variation = nil, mappings = [])
103
106
  @app = app
104
107
  @variation = variation
105
108
  @mappings = mappings.map do |internal, external|
@@ -108,27 +111,29 @@ module Rack
108
111
  end
109
112
 
110
113
  def call(env)
111
- status, headers, body = @app.call(env)
114
+ status, headers, body = response = @app.call(env)
115
+
112
116
  if body.respond_to?(:to_path)
113
117
  case type = variation(env)
114
- when 'X-Accel-Redirect'
118
+ when /x-accel-redirect/i
115
119
  path = ::File.expand_path(body.to_path)
116
120
  if url = map_accel_path(env, path)
117
121
  headers[CONTENT_LENGTH] = '0'
118
- headers[type] = url
122
+ # '?' must be percent-encoded because it is not query string but a part of path
123
+ headers[type.downcase] = ::Rack::Utils.escape_path(url).gsub('?', '%3F')
119
124
  obody = body
120
- body = Rack::BodyProxy.new([]) do
125
+ response[2] = Rack::BodyProxy.new([]) do
121
126
  obody.close if obody.respond_to?(:close)
122
127
  end
123
128
  else
124
- env[RACK_ERRORS].puts "X-Accel-Mapping header missing"
129
+ env[RACK_ERRORS].puts "x-accel-mapping header missing"
125
130
  end
126
- when 'X-Sendfile', 'X-Lighttpd-Send-File'
131
+ when /x-sendfile|x-lighttpd-send-file/i
127
132
  path = ::File.expand_path(body.to_path)
128
133
  headers[CONTENT_LENGTH] = '0'
129
- headers[type] = path
134
+ headers[type.downcase] = path
130
135
  obody = body
131
- body = Rack::BodyProxy.new([]) do
136
+ response[2] = Rack::BodyProxy.new([]) do
132
137
  obody.close if obody.respond_to?(:close)
133
138
  end
134
139
  when '', nil
@@ -136,7 +141,7 @@ module Rack
136
141
  env[RACK_ERRORS].puts "Unknown x-sendfile variation: '#{type}'.\n"
137
142
  end
138
143
  end
139
- [status, headers, body]
144
+ response
140
145
  end
141
146
 
142
147
  private
@@ -147,11 +152,15 @@ module Rack
147
152
  end
148
153
 
149
154
  def map_accel_path(env, path)
150
- if mapping = @mappings.find { |internal,_| internal =~ path }
155
+ if mapping = @mappings.find { |internal, _| internal =~ path }
151
156
  path.sub(*mapping)
152
157
  elsif mapping = env['HTTP_X_ACCEL_MAPPING']
153
- internal, external = mapping.split('=', 2).map(&:strip)
154
- path.sub(/^#{internal}/i, external)
158
+ mapping.split(',').map(&:strip).each do |m|
159
+ internal, external = m.split('=', 2).map(&:strip)
160
+ new_path = path.sub(/^#{internal}/i, external)
161
+ return new_path unless path == new_path
162
+ end
163
+ path
155
164
  end
156
165
  end
157
166
  end
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ostruct'
2
4
  require 'erb'
3
- require 'rack/request'
4
- require 'rack/utils'
5
+
6
+ require_relative 'constants'
7
+ require_relative 'utils'
8
+ require_relative 'request'
5
9
 
6
10
  module Rack
7
11
  # Rack::ShowExceptions catches all exceptions raised from the app it
@@ -55,7 +59,12 @@ module Rack
55
59
  private :accepts_html?
56
60
 
57
61
  def dump_exception(exception)
58
- string = "#{exception.class}: #{exception.message}\n"
62
+ if exception.respond_to?(:detailed_message)
63
+ message = exception.detailed_message(highlight: false)
64
+ else
65
+ message = exception.message
66
+ end
67
+ string = "#{exception.class}: #{message}\n".dup
59
68
  string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
60
69
  string
61
70
  end
@@ -63,12 +72,12 @@ module Rack
63
72
  def pretty(env, exception)
64
73
  req = Rack::Request.new(env)
65
74
 
66
- # This double assignment is to prevent an "unused variable" warning on
67
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
75
+ # This double assignment is to prevent an "unused variable" warning.
76
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
68
77
  path = path = (req.script_name + req.path_info).squeeze("/")
69
78
 
70
- # This double assignment is to prevent an "unused variable" warning on
71
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
79
+ # This double assignment is to prevent an "unused variable" warning.
80
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
72
81
  frames = frames = exception.backtrace.map { |line|
73
82
  frame = OpenStruct.new
74
83
  if line =~ /(.*?):(\d+)(:in `(.*)')?/
@@ -77,13 +86,13 @@ module Rack
77
86
  frame.function = $4
78
87
 
79
88
  begin
80
- lineno = frame.lineno-1
89
+ lineno = frame.lineno - 1
81
90
  lines = ::File.readlines(frame.filename)
82
- frame.pre_context_lineno = [lineno-CONTEXT, 0].max
91
+ frame.pre_context_lineno = [lineno - CONTEXT, 0].max
83
92
  frame.pre_context = lines[frame.pre_context_lineno...lineno]
84
93
  frame.context_line = lines[lineno].chomp
85
- frame.post_context_lineno = [lineno+CONTEXT, lines.size].min
86
- frame.post_context = lines[lineno+1..frame.post_context_lineno]
94
+ frame.post_context_lineno = [lineno + CONTEXT, lines.size].min
95
+ frame.post_context = lines[lineno + 1..frame.post_context_lineno]
87
96
  rescue
88
97
  end
89
98
 
@@ -93,7 +102,11 @@ module Rack
93
102
  end
94
103
  }.compact
95
104
 
96
- TEMPLATE.result(binding)
105
+ template.result(binding)
106
+ end
107
+
108
+ def template
109
+ TEMPLATE
97
110
  end
98
111
 
99
112
  def h(obj) # :nodoc:
@@ -107,8 +120,8 @@ module Rack
107
120
 
108
121
  # :stopdoc:
109
122
 
110
- # adapted from Django <djangoproject.com>
111
- # Copyright (c) 2005, the Lawrence Journal-World
123
+ # adapted from Django <www.djangoproject.com>
124
+ # Copyright (c) Django Software Foundation and individual contributors.
112
125
  # Used under the modified BSD license:
113
126
  # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
114
127
  TEMPLATE = ERB.new(<<-'HTML'.gsub(/^ /, ''))
@@ -155,7 +168,7 @@ module Rack
155
168
  div.commands { margin-left: 40px; }
156
169
  div.commands a { color:black; text-decoration:none; }
157
170
  #summary { background: #ffc; }
158
- #summary h2 { font-weight: normal; color: #666; }
171
+ #summary h2 { font-family: monospace; font-weight: normal; color: #666; white-space: pre-wrap; }
159
172
  #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
160
173
  #summary ul#quicklinks li { float: left; padding: 0 1em; }
161
174
  #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
@@ -223,7 +236,11 @@ module Rack
223
236
 
224
237
  <div id="summary">
225
238
  <h1><%=h exception.class %> at <%=h path %></h1>
239
+ <% if exception.respond_to?(:detailed_message) %>
240
+ <h2><%=h exception.detailed_message(highlight: false) %></h2>
241
+ <% else %>
226
242
  <h2><%=h exception.message %></h2>
243
+ <% end %>
227
244
  <table><tr>
228
245
  <th>Ruby</th>
229
246
  <td>
@@ -307,7 +324,7 @@ module Rack
307
324
  <% end %>
308
325
 
309
326
  <h3 id="post-info">POST</h3>
310
- <% if req.POST and not req.POST.empty? %>
327
+ <% if ((req.POST and not req.POST.empty?) rescue (no_post_data = "Invalid POST data"; nil)) %>
311
328
  <table class="req">
312
329
  <thead>
313
330
  <tr>
@@ -325,7 +342,7 @@ module Rack
325
342
  </tbody>
326
343
  </table>
327
344
  <% else %>
328
- <p>No POST data.</p>
345
+ <p><%= no_post_data || "No POST data" %>.</p>
329
346
  <% end %>
330
347
 
331
348
 
@@ -363,7 +380,7 @@ module Rack
363
380
  <% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
364
381
  <tr>
365
382
  <td><%=h key %></td>
366
- <td class="code"><div><%=h val %></div></td>
383
+ <td class="code"><div><%=h val.inspect %></div></td>
367
384
  </tr>
368
385
  <% } %>
369
386
  </tbody>
@@ -1,6 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'erb'
2
- require 'rack/request'
3
- require 'rack/utils'
4
+
5
+ require_relative 'constants'
6
+ require_relative 'utils'
7
+ require_relative 'request'
8
+ require_relative 'body_proxy'
4
9
 
5
10
  module Rack
6
11
  # Rack::ShowStatus catches all empty responses and replaces them
@@ -17,28 +22,33 @@ module Rack
17
22
  end
18
23
 
19
24
  def call(env)
20
- status, headers, body = @app.call(env)
21
- headers = Utils::HeaderHash.new(headers)
25
+ status, headers, body = response = @app.call(env)
22
26
  empty = headers[CONTENT_LENGTH].to_i <= 0
23
27
 
24
28
  # client or server error, or explicit message
25
29
  if (status.to_i >= 400 && empty) || env[RACK_SHOWSTATUS_DETAIL]
26
- # This double assignment is to prevent an "unused variable" warning on
27
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
30
+ # This double assignment is to prevent an "unused variable" warning.
31
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
28
32
  req = req = Rack::Request.new(env)
29
33
 
30
34
  message = Rack::Utils::HTTP_STATUS_CODES[status.to_i] || status.to_s
31
35
 
32
- # This double assignment is to prevent an "unused variable" warning on
33
- # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
36
+ # This double assignment is to prevent an "unused variable" warning.
37
+ # Yes, it is dumb, but I don't like Ruby yelling at me.
34
38
  detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message
35
39
 
36
- body = @template.result(binding)
37
- size = body.bytesize
38
- [status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), [body]]
39
- else
40
- [status, headers, body]
40
+ html = @template.result(binding)
41
+ size = html.bytesize
42
+
43
+ response[2] = Rack::BodyProxy.new([html]) do
44
+ body.close if body.respond_to?(:close)
45
+ end
46
+
47
+ headers[CONTENT_TYPE] = "text/html"
48
+ headers[CONTENT_LENGTH] = size.to_s
41
49
  end
50
+
51
+ response
42
52
  end
43
53
 
44
54
  def h(obj) # :nodoc:
@@ -52,8 +62,8 @@ module Rack
52
62
 
53
63
  # :stopdoc:
54
64
 
55
- # adapted from Django <djangoproject.com>
56
- # Copyright (c) 2005, the Lawrence Journal-World
65
+ # adapted from Django <www.djangoproject.com>
66
+ # Copyright (c) Django Software Foundation and individual contributors.
57
67
  # Used under the modified BSD license:
58
68
  # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
59
69
  TEMPLATE = <<'HTML'
data/lib/rack/static.rb CHANGED
@@ -1,11 +1,14 @@
1
- require "rack/file"
2
- require "rack/utils"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'constants'
4
+ require_relative 'files'
5
+ require_relative 'mime'
3
6
 
4
7
  module Rack
5
8
 
6
9
  # The Rack::Static middleware intercepts requests for static files
7
10
  # (javascript files, images, stylesheets, etc) based on the url prefixes or
8
- # route mappings passed in the options, and serves them using a Rack::File
11
+ # route mappings passed in the options, and serves them using a Rack::Files
9
12
  # object. This allows a Rack stack to serve both static and dynamic content.
10
13
  #
11
14
  # Examples:
@@ -15,6 +18,11 @@ module Rack
15
18
  #
16
19
  # use Rack::Static, :urls => ["/media"]
17
20
  #
21
+ # Same as previous, but instead of returning 404 for missing files under
22
+ # /media, call the next middleware:
23
+ #
24
+ # use Rack::Static, :urls => ["/media"], :cascade => true
25
+ #
18
26
  # Serve all requests beginning with /css or /images from the folder "public"
19
27
  # in the current directory (ie public/css/* and public/images/*):
20
28
  #
@@ -74,32 +82,32 @@ module Rack
74
82
  # :header_rules => [
75
83
  # # Cache all static files in public caches (e.g. Rack::Cache)
76
84
  # # as well as in the browser
77
- # [:all, {'Cache-Control' => 'public, max-age=31536000'}],
85
+ # [:all, {'cache-control' => 'public, max-age=31536000'}],
78
86
  #
79
87
  # # Provide web fonts with cross-origin access-control-headers
80
88
  # # Firefox requires this when serving assets using a Content Delivery Network
81
- # [:fonts, {'Access-Control-Allow-Origin' => '*'}]
89
+ # [:fonts, {'access-control-allow-origin' => '*'}]
82
90
  # ]
83
91
  #
84
92
  class Static
85
-
86
- def initialize(app, options={})
93
+ def initialize(app, options = {})
87
94
  @app = app
88
95
  @urls = options[:urls] || ["/favicon.ico"]
89
96
  @index = options[:index]
90
97
  @gzip = options[:gzip]
98
+ @cascade = options[:cascade]
91
99
  root = options[:root] || Dir.pwd
92
100
 
93
101
  # HTTP Headers
94
102
  @header_rules = options[:header_rules] || []
95
103
  # Allow for legacy :cache_control option while prioritizing global header_rules setting
96
- @header_rules.unshift([:all, {CACHE_CONTROL => options[:cache_control]}]) if options[:cache_control]
104
+ @header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control]
97
105
 
98
- @file_server = Rack::File.new(root)
106
+ @file_server = Rack::Files.new(root)
99
107
  end
100
108
 
101
109
  def add_index_root?(path)
102
- @index && path =~ /\/$/
110
+ @index && route_file(path) && path.end_with?('/')
103
111
  end
104
112
 
105
113
  def overwrite_file_path(path)
@@ -120,7 +128,7 @@ module Rack
120
128
  if can_serve(path)
121
129
  if overwrite_file_path(path)
122
130
  env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path])
123
- elsif @gzip && env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/
131
+ elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING'])
124
132
  path = env[PATH_INFO]
125
133
  env[PATH_INFO] += '.gz'
126
134
  response = @file_server.call(env)
@@ -128,17 +136,21 @@ module Rack
128
136
 
129
137
  if response[0] == 404
130
138
  response = nil
139
+ elsif response[0] == 304
140
+ # Do nothing, leave headers as is
131
141
  else
132
- if mime_type = Mime.mime_type(::File.extname(path), 'text/plain')
133
- response[1][CONTENT_TYPE] = mime_type
134
- end
135
- response[1]['Content-Encoding'] = 'gzip'
142
+ response[1][CONTENT_TYPE] = Mime.mime_type(::File.extname(path), 'text/plain')
143
+ response[1]['content-encoding'] = 'gzip'
136
144
  end
137
145
  end
138
146
 
139
147
  path = env[PATH_INFO]
140
148
  response ||= @file_server.call(env)
141
149
 
150
+ if @cascade && response[0] == 404
151
+ return @app.call(env)
152
+ end
153
+
142
154
  headers = response[1]
143
155
  applicable_rules(path).each do |rule, new_headers|
144
156
  new_headers.each { |field, content| headers[field] = content }
@@ -157,14 +169,14 @@ module Rack
157
169
  when :all
158
170
  true
159
171
  when :fonts
160
- path =~ /\.(?:ttf|otf|eot|woff2|woff|svg)\z/
172
+ /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
161
173
  when String
162
174
  path = ::Rack::Utils.unescape(path)
163
175
  path.start_with?(rule) || path.start_with?('/' + rule)
164
176
  when Array
165
- path =~ /\.(#{rule.join('|')})\z/
177
+ /\.(#{rule.join('|')})\z/.match?(path)
166
178
  when Regexp
167
- path =~ rule
179
+ rule.match?(path)
168
180
  else
169
181
  false
170
182
  end
@@ -1,4 +1,7 @@
1
- require 'rack/body_proxy'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'constants'
4
+ require_relative 'body_proxy'
2
5
 
3
6
  module Rack
4
7
 
@@ -12,11 +15,19 @@ module Rack
12
15
 
13
16
  def call(env)
14
17
  env[RACK_TEMPFILES] ||= []
15
- status, headers, body = @app.call(env)
16
- body_proxy = BodyProxy.new(body) do
17
- env[RACK_TEMPFILES].each(&:close!) unless env[RACK_TEMPFILES].nil?
18
+
19
+ begin
20
+ _, _, body = response = @app.call(env)
21
+ rescue Exception
22
+ env[RACK_TEMPFILES]&.each(&:close!)
23
+ raise
18
24
  end
19
- [status, headers, body_proxy]
25
+
26
+ response[2] = BodyProxy.new(body) do
27
+ env[RACK_TEMPFILES]&.each(&:close!)
28
+ end
29
+
30
+ response
20
31
  end
21
32
  end
22
33
  end
data/lib/rack/urlmap.rb CHANGED
@@ -1,3 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ require_relative 'constants'
6
+
1
7
  module Rack
2
8
  # Rack::URLMap takes a hash mapping urls or paths to apps, and
3
9
  # dispatches accordingly. Support for HTTP/1.1 host names exists if
@@ -12,17 +18,16 @@ module Rack
12
18
  # first, since they are most specific.
13
19
 
14
20
  class URLMap
15
- NEGATIVE_INFINITY = -1.0 / 0.0
16
- INFINITY = 1.0 / 0.0
17
-
18
21
  def initialize(map = {})
19
22
  remap(map)
20
23
  end
21
24
 
22
25
  def remap(map)
26
+ @known_hosts = Set[]
23
27
  @mapping = map.map { |location, app|
24
28
  if location =~ %r{\Ahttps?://(.*?)(/.*)}
25
29
  host, location = $1, $2
30
+ @known_hosts << host
26
31
  else
27
32
  host = nil
28
33
  end
@@ -36,7 +41,7 @@ module Rack
36
41
 
37
42
  [host, location, match, app]
38
43
  }.sort_by do |(host, location, _, _)|
39
- [host ? -host.size : INFINITY, -location.size]
44
+ [host ? -host.size : Float::INFINITY, -location.size]
40
45
  end
41
46
  end
42
47
 
@@ -50,10 +55,13 @@ module Rack
50
55
  is_same_server = casecmp?(http_host, server_name) ||
51
56
  casecmp?(http_host, "#{server_name}:#{server_port}")
52
57
 
58
+ is_host_known = @known_hosts.include? http_host
59
+
53
60
  @mapping.each do |host, location, match, app|
54
61
  unless casecmp?(http_host, host) \
55
62
  || casecmp?(server_name, host) \
56
- || (!host && is_same_server)
63
+ || (!host && is_same_server) \
64
+ || (!host && !is_host_known) # If we don't have a matching host, default to the first without a specified host
57
65
  next
58
66
  end
59
67
 
@@ -68,7 +76,7 @@ module Rack
68
76
  return app.call(env)
69
77
  end
70
78
 
71
- [404, {CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
79
+ [404, { CONTENT_TYPE => "text/plain", "x-cascade" => "pass" }, ["Not Found: #{path}"]]
72
80
 
73
81
  ensure
74
82
  env[PATH_INFO] = path