rack 1.6.13 → 2.1.4.3

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 (188) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +105 -141
  5. data/Rakefile +27 -28
  6. data/SPEC +6 -7
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +7 -1
  14. data/lib/rack/auth/basic.rb +4 -1
  15. data/lib/rack/auth/digest/md5.rb +9 -7
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +3 -1
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +42 -18
  21. data/lib/rack/cascade.rb +6 -5
  22. data/lib/rack/chunked.rb +33 -10
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +14 -10
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +3 -1
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +5 -3
  27. data/lib/rack/content_type.rb +3 -1
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +33 -53
  30. data/lib/rack/directory.rb +75 -60
  31. data/lib/rack/etag.rb +8 -5
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -149
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +17 -16
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +22 -19
  39. data/lib/rack/handler/thin.rb +6 -1
  40. data/lib/rack/handler/webrick.rb +28 -28
  41. data/lib/rack/handler.rb +9 -26
  42. data/lib/rack/head.rb +17 -17
  43. data/lib/rack/lint.rb +55 -52
  44. data/lib/rack/lobster.rb +8 -6
  45. data/lib/rack/lock.rb +17 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  49. data/lib/rack/mime.rb +27 -6
  50. data/lib/rack/mock.rb +101 -60
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +292 -161
  53. data/lib/rack/multipart/uploaded_file.rb +3 -2
  54. data/lib/rack/multipart.rb +38 -8
  55. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +11 -9
  58. data/lib/rack/reloader.rb +10 -4
  59. data/lib/rack/request.rb +447 -305
  60. data/lib/rack/response.rb +196 -83
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +12 -18
  63. data/lib/rack/sendfile.rb +19 -14
  64. data/lib/rack/server.rb +118 -41
  65. data/lib/rack/session/abstract/id.rb +139 -94
  66. data/lib/rack/session/cookie.rb +34 -26
  67. data/lib/rack/session/memcache.rb +4 -93
  68. data/lib/rack/session/pool.rb +12 -10
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +7 -5
  71. data/lib/rack/static.rb +41 -11
  72. data/lib/rack/tempfile_reaper.rb +4 -2
  73. data/lib/rack/urlmap.rb +25 -15
  74. data/lib/rack/utils.rb +203 -277
  75. data/lib/rack.rb +76 -24
  76. data/rack.gemspec +25 -14
  77. metadata +62 -183
  78. data/HISTORY.md +0 -375
  79. data/KNOWN-ISSUES +0 -44
  80. data/lib/rack/backports/uri/common_18.rb +0 -56
  81. data/lib/rack/backports/uri/common_192.rb +0 -52
  82. data/lib/rack/backports/uri/common_193.rb +0 -29
  83. data/lib/rack/handler/evented_mongrel.rb +0 -8
  84. data/lib/rack/handler/mongrel.rb +0 -106
  85. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  86. data/lib/rack/showexceptions.rb +0 -387
  87. data/lib/rack/utils/okjson.rb +0 -600
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/rackup_stub.rb +0 -6
  101. data/test/cgi/sample_rackup.ru +0 -5
  102. data/test/cgi/test +0 -9
  103. data/test/cgi/test+directory/test+file +0 -1
  104. data/test/cgi/test.fcgi +0 -8
  105. data/test/cgi/test.ru +0 -5
  106. data/test/gemloader.rb +0 -10
  107. data/test/multipart/bad_robots +0 -259
  108. data/test/multipart/binary +0 -0
  109. data/test/multipart/content_type_and_no_filename +0 -6
  110. data/test/multipart/empty +0 -10
  111. data/test/multipart/fail_16384_nofile +0 -814
  112. data/test/multipart/file1.txt +0 -1
  113. data/test/multipart/filename_and_modification_param +0 -7
  114. data/test/multipart/filename_and_no_name +0 -6
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_null_byte +0 -7
  118. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  121. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  122. data/test/multipart/filename_with_unescaped_quotes +0 -6
  123. data/test/multipart/ie +0 -6
  124. data/test/multipart/invalid_character +0 -6
  125. data/test/multipart/mixed_files +0 -21
  126. data/test/multipart/nested +0 -10
  127. data/test/multipart/none +0 -9
  128. data/test/multipart/semicolon +0 -6
  129. data/test/multipart/text +0 -15
  130. data/test/multipart/three_files_three_fields +0 -31
  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 -81
  135. data/test/spec_auth_digest.rb +0 -259
  136. data/test/spec_body_proxy.rb +0 -85
  137. data/test/spec_builder.rb +0 -223
  138. data/test/spec_cascade.rb +0 -61
  139. data/test/spec_cgi.rb +0 -102
  140. data/test/spec_chunked.rb +0 -101
  141. data/test/spec_commonlogger.rb +0 -93
  142. data/test/spec_conditionalget.rb +0 -102
  143. data/test/spec_config.rb +0 -22
  144. data/test/spec_content_length.rb +0 -85
  145. data/test/spec_content_type.rb +0 -45
  146. data/test/spec_deflater.rb +0 -339
  147. data/test/spec_directory.rb +0 -88
  148. data/test/spec_etag.rb +0 -107
  149. data/test/spec_fastcgi.rb +0 -107
  150. data/test/spec_file.rb +0 -221
  151. data/test/spec_handler.rb +0 -72
  152. data/test/spec_head.rb +0 -45
  153. data/test/spec_lint.rb +0 -550
  154. data/test/spec_lobster.rb +0 -58
  155. data/test/spec_lock.rb +0 -164
  156. data/test/spec_logger.rb +0 -23
  157. data/test/spec_methodoverride.rb +0 -111
  158. data/test/spec_mime.rb +0 -51
  159. data/test/spec_mock.rb +0 -297
  160. data/test/spec_mongrel.rb +0 -182
  161. data/test/spec_multipart.rb +0 -600
  162. data/test/spec_nulllogger.rb +0 -20
  163. data/test/spec_recursive.rb +0 -72
  164. data/test/spec_request.rb +0 -1232
  165. data/test/spec_response.rb +0 -407
  166. data/test/spec_rewindable_input.rb +0 -118
  167. data/test/spec_runtime.rb +0 -49
  168. data/test/spec_sendfile.rb +0 -130
  169. data/test/spec_server.rb +0 -167
  170. data/test/spec_session_abstract_id.rb +0 -53
  171. data/test/spec_session_cookie.rb +0 -410
  172. data/test/spec_session_memcache.rb +0 -358
  173. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  174. data/test/spec_session_pool.rb +0 -246
  175. data/test/spec_showexceptions.rb +0 -98
  176. data/test/spec_showstatus.rb +0 -103
  177. data/test/spec_static.rb +0 -145
  178. data/test/spec_tempfile_reaper.rb +0 -63
  179. data/test/spec_thin.rb +0 -91
  180. data/test/spec_urlmap.rb +0 -236
  181. data/test/spec_utils.rb +0 -647
  182. data/test/spec_version.rb +0 -17
  183. data/test/spec_webrick.rb +0 -184
  184. data/test/static/another/index.html +0 -1
  185. data/test/static/index.html +0 -1
  186. data/test/testrequest.rb +0 -78
  187. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  188. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,99 +1,10 @@
1
- # AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
1
+ # frozen_string_literal: true
2
2
 
3
- require 'rack/session/abstract/id'
4
- require 'memcache'
3
+ require 'rack/session/dalli'
5
4
 
6
5
  module Rack
7
6
  module Session
8
- # Rack::Session::Memcache provides simple cookie based session management.
9
- # Session data is stored in memcached. The corresponding session key is
10
- # maintained in the cookie.
11
- # You may treat Session::Memcache as you would Session::Pool with the
12
- # following caveats.
13
- #
14
- # * Setting :expire_after to 0 would note to the Memcache server to hang
15
- # onto the session data until it would drop it according to it's own
16
- # specifications. However, the cookie sent to the client would expire
17
- # immediately.
18
- #
19
- # Note that memcache does drop data before it may be listed to expire. For
20
- # a full description of behaviour, please see memcache's documentation.
21
-
22
- class Memcache < Abstract::PersistedSecure
23
- attr_reader :mutex, :pool
24
-
25
- DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \
26
- :namespace => 'rack:session',
27
- :memcache_server => 'localhost:11211'
28
-
29
- def initialize(app, options={})
30
- super
31
-
32
- @mutex = Mutex.new
33
- mserv = @default_options[:memcache_server]
34
- mopts = @default_options.reject{|k,v| !MemCache::DEFAULT_OPTIONS.include? k }
35
-
36
- @pool = options[:cache] || MemCache.new(mserv, mopts)
37
- unless @pool.active? and @pool.servers.any?{|c| c.alive? }
38
- raise 'No memcache servers'
39
- end
40
- end
41
-
42
- def generate_sid
43
- loop do
44
- sid = super
45
- break sid unless @pool.get(sid.private_id, true)
46
- end
47
- end
48
-
49
- def get_session(env, sid)
50
- with_lock(env) do
51
- unless sid and session = get_session_with_fallback(sid)
52
- sid, session = generate_sid, {}
53
- unless /^STORED/ =~ @pool.add(sid.private_id, session)
54
- raise "Session collision on '#{sid.inspect}'"
55
- end
56
- end
57
- [sid, session]
58
- end
59
- end
60
-
61
- def set_session(env, session_id, new_session, options)
62
- expiry = options[:expire_after]
63
- expiry = expiry.nil? ? 0 : expiry + 1
64
-
65
- with_lock(env) do
66
- @pool.set session_id.private_id, new_session, expiry
67
- session_id
68
- end
69
- end
70
-
71
- def destroy_session(env, session_id, options)
72
- with_lock(env) do
73
- @pool.delete(session_id.public_id)
74
- @pool.delete(session_id.private_id)
75
- generate_sid unless options[:drop]
76
- end
77
- end
78
-
79
- def with_lock(env)
80
- @mutex.lock if env['rack.multithread']
81
- yield
82
- rescue MemCache::MemCacheError, Errno::ECONNREFUSED
83
- if $VERBOSE
84
- warn "#{self} is unable to find memcached server."
85
- warn $!.inspect
86
- end
87
- raise
88
- ensure
89
- @mutex.unlock if @mutex.locked?
90
- end
91
-
92
- private
93
-
94
- def get_session_with_fallback(sid)
95
- @pool.get(sid.private_id) || @pool.get(sid.public_id)
96
- end
97
- end
7
+ warn "Rack::Session::Memcache is deprecated, please use Rack::Session::Dalli from 'dalli' gem instead."
8
+ Memcache = Dalli
98
9
  end
99
10
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
2
4
  # THANKS:
3
5
  # apeiros, for session id generation, expiry setup, and threadiness
@@ -26,9 +28,9 @@ module Rack
26
28
 
27
29
  class Pool < Abstract::PersistedSecure
28
30
  attr_reader :mutex, :pool
29
- DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false
31
+ DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge drop: false
30
32
 
31
- def initialize(app, options={})
33
+ def initialize(app, options = {})
32
34
  super
33
35
  @pool = Hash.new
34
36
  @mutex = Mutex.new
@@ -41,8 +43,8 @@ module Rack
41
43
  end
42
44
  end
43
45
 
44
- def get_session(env, sid)
45
- with_lock(env) do
46
+ def find_session(req, sid)
47
+ with_lock(req) do
46
48
  unless sid and session = get_session_with_fallback(sid)
47
49
  sid, session = generate_sid, {}
48
50
  @pool.store sid.private_id, session
@@ -51,23 +53,23 @@ module Rack
51
53
  end
52
54
  end
53
55
 
54
- def set_session(env, session_id, new_session, options)
55
- with_lock(env) do
56
+ def write_session(req, session_id, new_session, options)
57
+ with_lock(req) do
56
58
  @pool.store session_id.private_id, new_session
57
59
  session_id
58
60
  end
59
61
  end
60
62
 
61
- def destroy_session(env, session_id, options)
62
- with_lock(env) do
63
+ def delete_session(req, session_id, options)
64
+ with_lock(req) do
63
65
  @pool.delete(session_id.public_id)
64
66
  @pool.delete(session_id.private_id)
65
67
  generate_sid unless options[:drop]
66
68
  end
67
69
  end
68
70
 
69
- def with_lock(env)
70
- @mutex.lock if env['rack.multithread']
71
+ def with_lock(req)
72
+ @mutex.lock if req.multithread?
71
73
  yield
72
74
  ensure
73
75
  @mutex.unlock if @mutex.locked?
@@ -0,0 +1,392 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+ require 'erb'
5
+ require 'rack/request'
6
+ require 'rack/utils'
7
+
8
+ module Rack
9
+ # Rack::ShowExceptions catches all exceptions raised from the app it
10
+ # wraps. It shows a useful backtrace with the sourcefile and
11
+ # clickable context, the whole Rack environment and the request
12
+ # data.
13
+ #
14
+ # Be careful when you use this on public-facing sites as it could
15
+ # reveal information helpful to attackers.
16
+
17
+ class ShowExceptions
18
+ CONTEXT = 7
19
+
20
+ def initialize(app)
21
+ @app = app
22
+ end
23
+
24
+ def call(env)
25
+ @app.call(env)
26
+ rescue StandardError, LoadError, SyntaxError => e
27
+ exception_string = dump_exception(e)
28
+
29
+ env[RACK_ERRORS].puts(exception_string)
30
+ env[RACK_ERRORS].flush
31
+
32
+ if accepts_html?(env)
33
+ content_type = "text/html"
34
+ body = pretty(env, e)
35
+ else
36
+ content_type = "text/plain"
37
+ body = exception_string
38
+ end
39
+
40
+ [
41
+ 500,
42
+ {
43
+ CONTENT_TYPE => content_type,
44
+ CONTENT_LENGTH => body.bytesize.to_s,
45
+ },
46
+ [body],
47
+ ]
48
+ end
49
+
50
+ def prefers_plaintext?(env)
51
+ !accepts_html?(env)
52
+ end
53
+
54
+ def accepts_html?(env)
55
+ Rack::Utils.best_q_match(env["HTTP_ACCEPT"], %w[text/html])
56
+ end
57
+ private :accepts_html?
58
+
59
+ def dump_exception(exception)
60
+ string = "#{exception.class}: #{exception.message}\n".dup
61
+ string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
62
+ string
63
+ end
64
+
65
+ def pretty(env, exception)
66
+ req = Rack::Request.new(env)
67
+
68
+ # This double assignment is to prevent an "unused variable" warning on
69
+ # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
70
+ path = path = (req.script_name + req.path_info).squeeze("/")
71
+
72
+ # This double assignment is to prevent an "unused variable" warning on
73
+ # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
74
+ frames = frames = exception.backtrace.map { |line|
75
+ frame = OpenStruct.new
76
+ if line =~ /(.*?):(\d+)(:in `(.*)')?/
77
+ frame.filename = $1
78
+ frame.lineno = $2.to_i
79
+ frame.function = $4
80
+
81
+ begin
82
+ lineno = frame.lineno - 1
83
+ lines = ::File.readlines(frame.filename)
84
+ frame.pre_context_lineno = [lineno - CONTEXT, 0].max
85
+ frame.pre_context = lines[frame.pre_context_lineno...lineno]
86
+ frame.context_line = lines[lineno].chomp
87
+ frame.post_context_lineno = [lineno + CONTEXT, lines.size].min
88
+ frame.post_context = lines[lineno + 1..frame.post_context_lineno]
89
+ rescue
90
+ end
91
+
92
+ frame
93
+ else
94
+ nil
95
+ end
96
+ }.compact
97
+
98
+ template.result(binding)
99
+ end
100
+
101
+ def template
102
+ TEMPLATE
103
+ end
104
+
105
+ def h(obj) # :nodoc:
106
+ case obj
107
+ when String
108
+ Utils.escape_html(obj)
109
+ else
110
+ Utils.escape_html(obj.inspect)
111
+ end
112
+ end
113
+
114
+ # :stopdoc:
115
+
116
+ # adapted from Django <www.djangoproject.com>
117
+ # Copyright (c) Django Software Foundation and individual contributors.
118
+ # Used under the modified BSD license:
119
+ # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
120
+ TEMPLATE = ERB.new(<<-'HTML'.gsub(/^ /, ''))
121
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
122
+ <html lang="en">
123
+ <head>
124
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
125
+ <meta name="robots" content="NONE,NOARCHIVE" />
126
+ <title><%=h exception.class %> at <%=h path %></title>
127
+ <style type="text/css">
128
+ html * { padding:0; margin:0; }
129
+ body * { padding:10px 20px; }
130
+ body * * { padding:0; }
131
+ body { font:small sans-serif; }
132
+ body>div { border-bottom:1px solid #ddd; }
133
+ h1 { font-weight:normal; }
134
+ h2 { margin-bottom:.8em; }
135
+ h2 span { font-size:80%; color:#666; font-weight:normal; }
136
+ h3 { margin:1em 0 .5em 0; }
137
+ h4 { margin:0 0 .5em 0; font-weight: normal; }
138
+ table {
139
+ border:1px solid #ccc; border-collapse: collapse; background:white; }
140
+ tbody td, tbody th { vertical-align:top; padding:2px 3px; }
141
+ thead th {
142
+ padding:1px 6px 1px 3px; background:#fefefe; text-align:left;
143
+ font-weight:normal; font-size:11px; border:1px solid #ddd; }
144
+ tbody th { text-align:right; color:#666; padding-right:.5em; }
145
+ table.vars { margin:5px 0 2px 40px; }
146
+ table.vars td, table.req td { font-family:monospace; }
147
+ table td.code { width:100%;}
148
+ table td.code div { overflow:hidden; }
149
+ table.source th { color:#666; }
150
+ table.source td {
151
+ font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
152
+ ul.traceback { list-style-type:none; }
153
+ ul.traceback li.frame { margin-bottom:1em; }
154
+ div.context { margin: 10px 0; }
155
+ div.context ol {
156
+ padding-left:30px; margin:0 10px; list-style-position: inside; }
157
+ div.context ol li {
158
+ font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
159
+ div.context ol.context-line li { color:black; background-color:#ccc; }
160
+ div.context ol.context-line li span { float: right; }
161
+ div.commands { margin-left: 40px; }
162
+ div.commands a { color:black; text-decoration:none; }
163
+ #summary { background: #ffc; }
164
+ #summary h2 { font-weight: normal; color: #666; }
165
+ #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
166
+ #summary ul#quicklinks li { float: left; padding: 0 1em; }
167
+ #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
168
+ #explanation { background:#eee; }
169
+ #template, #template-not-exist { background:#f6f6f6; }
170
+ #template-not-exist ul { margin: 0 0 0 20px; }
171
+ #traceback { background:#eee; }
172
+ #requestinfo { background:#f6f6f6; padding-left:120px; }
173
+ #summary table { border:none; background:transparent; }
174
+ #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
175
+ #requestinfo h3 { margin-bottom:-1em; }
176
+ .error { background: #ffc; }
177
+ .specific { color:#cc3300; font-weight:bold; }
178
+ </style>
179
+ <script type="text/javascript">
180
+ //<!--
181
+ function getElementsByClassName(oElm, strTagName, strClassName){
182
+ // Written by Jonathan Snook, http://www.snook.ca/jon;
183
+ // Add-ons by Robert Nyman, http://www.robertnyman.com
184
+ var arrElements = (strTagName == "*" && document.all)? document.all :
185
+ oElm.getElementsByTagName(strTagName);
186
+ var arrReturnElements = new Array();
187
+ strClassName = strClassName.replace(/\-/g, "\\-");
188
+ var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)");
189
+ var oElement;
190
+ for(var i=0; i<arrElements.length; i++){
191
+ oElement = arrElements[i];
192
+ if(oRegExp.test(oElement.className)){
193
+ arrReturnElements.push(oElement);
194
+ }
195
+ }
196
+ return (arrReturnElements)
197
+ }
198
+ function hideAll(elems) {
199
+ for (var e = 0; e < elems.length; e++) {
200
+ elems[e].style.display = 'none';
201
+ }
202
+ }
203
+ window.onload = function() {
204
+ hideAll(getElementsByClassName(document, 'table', 'vars'));
205
+ hideAll(getElementsByClassName(document, 'ol', 'pre-context'));
206
+ hideAll(getElementsByClassName(document, 'ol', 'post-context'));
207
+ }
208
+ function toggle() {
209
+ for (var i = 0; i < arguments.length; i++) {
210
+ var e = document.getElementById(arguments[i]);
211
+ if (e) {
212
+ e.style.display = e.style.display == 'none' ? 'block' : 'none';
213
+ }
214
+ }
215
+ return false;
216
+ }
217
+ function varToggle(link, id) {
218
+ toggle('v' + id);
219
+ var s = link.getElementsByTagName('span')[0];
220
+ var uarr = String.fromCharCode(0x25b6);
221
+ var darr = String.fromCharCode(0x25bc);
222
+ s.innerHTML = s.innerHTML == uarr ? darr : uarr;
223
+ return false;
224
+ }
225
+ //-->
226
+ </script>
227
+ </head>
228
+ <body>
229
+
230
+ <div id="summary">
231
+ <h1><%=h exception.class %> at <%=h path %></h1>
232
+ <h2><%=h exception.message %></h2>
233
+ <table><tr>
234
+ <th>Ruby</th>
235
+ <td>
236
+ <% if first = frames.first %>
237
+ <code><%=h first.filename %></code>: in <code><%=h first.function %></code>, line <%=h frames.first.lineno %>
238
+ <% else %>
239
+ unknown location
240
+ <% end %>
241
+ </td>
242
+ </tr><tr>
243
+ <th>Web</th>
244
+ <td><code><%=h req.request_method %> <%=h(req.host + path)%></code></td>
245
+ </tr></table>
246
+
247
+ <h3>Jump to:</h3>
248
+ <ul id="quicklinks">
249
+ <li><a href="#get-info">GET</a></li>
250
+ <li><a href="#post-info">POST</a></li>
251
+ <li><a href="#cookie-info">Cookies</a></li>
252
+ <li><a href="#env-info">ENV</a></li>
253
+ </ul>
254
+ </div>
255
+
256
+ <div id="traceback">
257
+ <h2>Traceback <span>(innermost first)</span></h2>
258
+ <ul class="traceback">
259
+ <% frames.each { |frame| %>
260
+ <li class="frame">
261
+ <code><%=h frame.filename %></code>: in <code><%=h frame.function %></code>
262
+
263
+ <% if frame.context_line %>
264
+ <div class="context" id="c<%=h frame.object_id %>">
265
+ <% if frame.pre_context %>
266
+ <ol start="<%=h frame.pre_context_lineno+1 %>" class="pre-context" id="pre<%=h frame.object_id %>">
267
+ <% frame.pre_context.each { |line| %>
268
+ <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line %></li>
269
+ <% } %>
270
+ </ol>
271
+ <% end %>
272
+
273
+ <ol start="<%=h frame.lineno %>" class="context-line">
274
+ <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h frame.context_line %><span>...</span></li></ol>
275
+
276
+ <% if frame.post_context %>
277
+ <ol start='<%=h frame.lineno+1 %>' class="post-context" id="post<%=h frame.object_id %>">
278
+ <% frame.post_context.each { |line| %>
279
+ <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line %></li>
280
+ <% } %>
281
+ </ol>
282
+ <% end %>
283
+ </div>
284
+ <% end %>
285
+ </li>
286
+ <% } %>
287
+ </ul>
288
+ </div>
289
+
290
+ <div id="requestinfo">
291
+ <h2>Request information</h2>
292
+
293
+ <h3 id="get-info">GET</h3>
294
+ <% if req.GET and not req.GET.empty? %>
295
+ <table class="req">
296
+ <thead>
297
+ <tr>
298
+ <th>Variable</th>
299
+ <th>Value</th>
300
+ </tr>
301
+ </thead>
302
+ <tbody>
303
+ <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %>
304
+ <tr>
305
+ <td><%=h key %></td>
306
+ <td class="code"><div><%=h val.inspect %></div></td>
307
+ </tr>
308
+ <% } %>
309
+ </tbody>
310
+ </table>
311
+ <% else %>
312
+ <p>No GET data.</p>
313
+ <% end %>
314
+
315
+ <h3 id="post-info">POST</h3>
316
+ <% if req.POST and not req.POST.empty? %>
317
+ <table class="req">
318
+ <thead>
319
+ <tr>
320
+ <th>Variable</th>
321
+ <th>Value</th>
322
+ </tr>
323
+ </thead>
324
+ <tbody>
325
+ <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %>
326
+ <tr>
327
+ <td><%=h key %></td>
328
+ <td class="code"><div><%=h val.inspect %></div></td>
329
+ </tr>
330
+ <% } %>
331
+ </tbody>
332
+ </table>
333
+ <% else %>
334
+ <p>No POST data.</p>
335
+ <% end %>
336
+
337
+
338
+ <h3 id="cookie-info">COOKIES</h3>
339
+ <% unless req.cookies.empty? %>
340
+ <table class="req">
341
+ <thead>
342
+ <tr>
343
+ <th>Variable</th>
344
+ <th>Value</th>
345
+ </tr>
346
+ </thead>
347
+ <tbody>
348
+ <% req.cookies.each { |key, val| %>
349
+ <tr>
350
+ <td><%=h key %></td>
351
+ <td class="code"><div><%=h val.inspect %></div></td>
352
+ </tr>
353
+ <% } %>
354
+ </tbody>
355
+ </table>
356
+ <% else %>
357
+ <p>No cookie data.</p>
358
+ <% end %>
359
+
360
+ <h3 id="env-info">Rack ENV</h3>
361
+ <table class="req">
362
+ <thead>
363
+ <tr>
364
+ <th>Variable</th>
365
+ <th>Value</th>
366
+ </tr>
367
+ </thead>
368
+ <tbody>
369
+ <% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
370
+ <tr>
371
+ <td><%=h key %></td>
372
+ <td class="code"><div><%=h val.inspect %></div></td>
373
+ </tr>
374
+ <% } %>
375
+ </tbody>
376
+ </table>
377
+
378
+ </div>
379
+
380
+ <div id="explanation">
381
+ <p>
382
+ You're seeing this error because you use <code>Rack::ShowExceptions</code>.
383
+ </p>
384
+ </div>
385
+
386
+ </body>
387
+ </html>
388
+ HTML
389
+
390
+ # :startdoc:
391
+ end
392
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'erb'
2
4
  require 'rack/request'
3
5
  require 'rack/utils'
@@ -22,7 +24,7 @@ module Rack
22
24
  empty = headers[CONTENT_LENGTH].to_i <= 0
23
25
 
24
26
  # client or server error, or explicit message
25
- if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"]
27
+ if (status.to_i >= 400 && empty) || env[RACK_SHOWSTATUS_DETAIL]
26
28
  # This double assignment is to prevent an "unused variable" warning on
27
29
  # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
28
30
  req = req = Rack::Request.new(env)
@@ -31,10 +33,10 @@ module Rack
31
33
 
32
34
  # This double assignment is to prevent an "unused variable" warning on
33
35
  # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
34
- detail = detail = env["rack.showstatus.detail"] || message
36
+ detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message
35
37
 
36
38
  body = @template.result(binding)
37
- size = Rack::Utils.bytesize(body)
39
+ size = body.bytesize
38
40
  [status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), [body]]
39
41
  else
40
42
  [status, headers, body]
@@ -52,8 +54,8 @@ module Rack
52
54
 
53
55
  # :stopdoc:
54
56
 
55
- # adapted from Django <djangoproject.com>
56
- # Copyright (c) 2005, the Lawrence Journal-World
57
+ # adapted from Django <www.djangoproject.com>
58
+ # Copyright (c) Django Software Foundation and individual contributors.
57
59
  # Used under the modified BSD license:
58
60
  # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
59
61
  TEMPLATE = <<'HTML'
data/lib/rack/static.rb CHANGED
@@ -1,8 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/files"
4
+ require "rack/utils"
5
+
6
+ require_relative 'core_ext/regexp'
7
+
1
8
  module Rack
2
9
 
3
10
  # The Rack::Static middleware intercepts requests for static files
4
11
  # (javascript files, images, stylesheets, etc) based on the url prefixes or
5
- # route mappings passed in the options, and serves them using a Rack::File
12
+ # route mappings passed in the options, and serves them using a Rack::Files
6
13
  # object. This allows a Rack stack to serve both static and dynamic content.
7
14
  #
8
15
  # Examples:
@@ -79,23 +86,29 @@ module Rack
79
86
  # ]
80
87
  #
81
88
  class Static
89
+ using ::Rack::RegexpExtensions
82
90
 
83
- def initialize(app, options={})
91
+ def initialize(app, options = {})
84
92
  @app = app
85
93
  @urls = options[:urls] || ["/favicon.ico"]
86
94
  @index = options[:index]
95
+ @gzip = options[:gzip]
87
96
  root = options[:root] || Dir.pwd
88
97
 
89
98
  # HTTP Headers
90
99
  @header_rules = options[:header_rules] || []
91
100
  # Allow for legacy :cache_control option while prioritizing global header_rules setting
92
- @header_rules.insert(0, [:all, {'Cache-Control' => options[:cache_control]}]) if options[:cache_control]
101
+ @header_rules.unshift([:all, { CACHE_CONTROL => options[:cache_control] }]) if options[:cache_control]
102
+
103
+ @file_server = Rack::Files.new(root)
104
+ end
93
105
 
94
- @file_server = Rack::File.new(root)
106
+ def add_index_root?(path)
107
+ @index && route_file(path) && path.end_with?('/')
95
108
  end
96
109
 
97
110
  def overwrite_file_path(path)
98
- @urls.kind_of?(Hash) && @urls.key?(path) || @index && path =~ /\/$/
111
+ @urls.kind_of?(Hash) && @urls.key?(path) || add_index_root?(path)
99
112
  end
100
113
 
101
114
  def route_file(path)
@@ -110,9 +123,26 @@ module Rack
110
123
  path = env[PATH_INFO]
111
124
 
112
125
  if can_serve(path)
113
- env["PATH_INFO"] = (path =~ /\/$/ ? path + @index : @urls[path]) if overwrite_file_path(path)
114
- path = env["PATH_INFO"]
115
- response = @file_server.call(env)
126
+ if overwrite_file_path(path)
127
+ env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path])
128
+ elsif @gzip && env['HTTP_ACCEPT_ENCODING'] && /\bgzip\b/.match?(env['HTTP_ACCEPT_ENCODING'])
129
+ path = env[PATH_INFO]
130
+ env[PATH_INFO] += '.gz'
131
+ response = @file_server.call(env)
132
+ env[PATH_INFO] = path
133
+
134
+ if response[0] == 404
135
+ response = nil
136
+ else
137
+ if mime_type = Mime.mime_type(::File.extname(path), 'text/plain')
138
+ response[1][CONTENT_TYPE] = mime_type
139
+ end
140
+ response[1]['Content-Encoding'] = 'gzip'
141
+ end
142
+ end
143
+
144
+ path = env[PATH_INFO]
145
+ response ||= @file_server.call(env)
116
146
 
117
147
  headers = response[1]
118
148
  applicable_rules(path).each do |rule, new_headers|
@@ -132,14 +162,14 @@ module Rack
132
162
  when :all
133
163
  true
134
164
  when :fonts
135
- path =~ /\.(?:ttf|otf|eot|woff2|woff|svg)\z/
165
+ /\.(?:ttf|otf|eot|woff2|woff|svg)\z/.match?(path)
136
166
  when String
137
167
  path = ::Rack::Utils.unescape(path)
138
168
  path.start_with?(rule) || path.start_with?('/' + rule)
139
169
  when Array
140
- path =~ /\.(#{rule.join('|')})\z/
170
+ /\.(#{rule.join('|')})\z/.match?(path)
141
171
  when Regexp
142
- path =~ rule
172
+ rule.match?(path)
143
173
  else
144
174
  false
145
175
  end