rack 1.6.13 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (144) hide show
  1. checksums.yaml +5 -5
  2. data/COPYING +1 -1
  3. data/HISTORY.md +138 -8
  4. data/README.rdoc +17 -25
  5. data/Rakefile +6 -14
  6. data/SPEC +8 -9
  7. data/contrib/rack_logo.svg +164 -111
  8. data/example/protectedlobster.rb +1 -1
  9. data/example/protectedlobster.ru +1 -1
  10. data/lib/rack/auth/abstract/request.rb +5 -1
  11. data/lib/rack/auth/digest/params.rb +2 -3
  12. data/lib/rack/auth/digest/request.rb +1 -1
  13. data/lib/rack/body_proxy.rb +14 -9
  14. data/lib/rack/builder.rb +3 -3
  15. data/lib/rack/chunked.rb +5 -5
  16. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  17. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  18. data/lib/rack/content_length.rb +2 -2
  19. data/lib/rack/deflater.rb +4 -4
  20. data/lib/rack/directory.rb +66 -54
  21. data/lib/rack/etag.rb +4 -3
  22. data/lib/rack/events.rb +154 -0
  23. data/lib/rack/file.rb +63 -39
  24. data/lib/rack/handler/cgi.rb +15 -16
  25. data/lib/rack/handler/fastcgi.rb +13 -14
  26. data/lib/rack/handler/lsws.rb +11 -11
  27. data/lib/rack/handler/scgi.rb +15 -15
  28. data/lib/rack/handler/thin.rb +3 -0
  29. data/lib/rack/handler/webrick.rb +22 -24
  30. data/lib/rack/handler.rb +3 -25
  31. data/lib/rack/head.rb +15 -17
  32. data/lib/rack/lint.rb +38 -38
  33. data/lib/rack/lobster.rb +1 -1
  34. data/lib/rack/lock.rb +6 -10
  35. data/lib/rack/logger.rb +2 -2
  36. data/lib/rack/media_type.rb +38 -0
  37. data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
  38. data/lib/rack/mime.rb +18 -5
  39. data/lib/rack/mock.rb +35 -53
  40. data/lib/rack/multipart/generator.rb +5 -5
  41. data/lib/rack/multipart/parser.rb +272 -158
  42. data/lib/rack/multipart/uploaded_file.rb +1 -2
  43. data/lib/rack/multipart.rb +35 -6
  44. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  45. data/lib/rack/query_parser.rb +192 -0
  46. data/lib/rack/recursive.rb +8 -8
  47. data/lib/rack/request.rb +383 -307
  48. data/lib/rack/response.rb +129 -56
  49. data/lib/rack/rewindable_input.rb +1 -12
  50. data/lib/rack/runtime.rb +10 -18
  51. data/lib/rack/sendfile.rb +5 -7
  52. data/lib/rack/server.rb +31 -25
  53. data/lib/rack/session/abstract/id.rb +95 -135
  54. data/lib/rack/session/cookie.rb +26 -28
  55. data/lib/rack/session/memcache.rb +8 -14
  56. data/lib/rack/session/pool.rb +14 -21
  57. data/lib/rack/show_exceptions.rb +386 -0
  58. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  59. data/lib/rack/static.rb +30 -5
  60. data/lib/rack/tempfile_reaper.rb +2 -2
  61. data/lib/rack/urlmap.rb +15 -14
  62. data/lib/rack/utils.rb +135 -210
  63. data/lib/rack.rb +70 -21
  64. data/rack.gemspec +7 -5
  65. data/test/builder/an_underscore_app.rb +5 -0
  66. data/test/builder/options.ru +1 -1
  67. data/test/cgi/test.fcgi +1 -0
  68. data/test/cgi/test.gz +0 -0
  69. data/test/helper.rb +34 -0
  70. data/test/multipart/filename_with_encoded_words +7 -0
  71. data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
  72. data/test/multipart/quoted +15 -0
  73. data/test/multipart/rack-logo.png +0 -0
  74. data/test/multipart/unity3d_wwwform +11 -0
  75. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  76. data/test/spec_auth_basic.rb +27 -19
  77. data/test/spec_auth_digest.rb +47 -46
  78. data/test/spec_body_proxy.rb +27 -27
  79. data/test/spec_builder.rb +51 -41
  80. data/test/spec_cascade.rb +24 -22
  81. data/test/spec_cgi.rb +49 -67
  82. data/test/spec_chunked.rb +36 -34
  83. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  84. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  85. data/test/spec_config.rb +3 -2
  86. data/test/spec_content_length.rb +18 -17
  87. data/test/spec_content_type.rb +13 -12
  88. data/test/spec_deflater.rb +66 -40
  89. data/test/spec_directory.rb +87 -27
  90. data/test/spec_etag.rb +32 -31
  91. data/test/spec_events.rb +133 -0
  92. data/test/spec_fastcgi.rb +50 -72
  93. data/test/spec_file.rb +107 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +162 -197
  97. data/test/spec_lobster.rb +24 -23
  98. data/test/spec_lock.rb +69 -39
  99. data/test/spec_logger.rb +4 -3
  100. data/test/spec_media_type.rb +42 -0
  101. data/test/spec_method_override.rb +83 -0
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +196 -151
  104. data/test/spec_multipart.rb +317 -201
  105. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  106. data/test/spec_recursive.rb +17 -14
  107. data/test/spec_request.rb +768 -607
  108. data/test/spec_response.rb +214 -111
  109. data/test/spec_rewindable_input.rb +50 -40
  110. data/test/spec_runtime.rb +11 -10
  111. data/test/spec_sendfile.rb +30 -35
  112. data/test/spec_server.rb +78 -52
  113. data/test/spec_session_abstract_id.rb +11 -33
  114. data/test/spec_session_abstract_session_hash.rb +28 -0
  115. data/test/spec_session_cookie.rb +97 -65
  116. data/test/spec_session_memcache.rb +63 -101
  117. data/test/spec_session_pool.rb +48 -84
  118. data/test/spec_show_exceptions.rb +80 -0
  119. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  120. data/test/spec_static.rb +71 -32
  121. data/test/spec_tempfile_reaper.rb +11 -10
  122. data/test/spec_thin.rb +55 -50
  123. data/test/spec_urlmap.rb +79 -78
  124. data/test/spec_utils.rb +441 -346
  125. data/test/spec_version.rb +2 -8
  126. data/test/spec_webrick.rb +91 -67
  127. data/test/static/foo.html +1 -0
  128. data/test/testrequest.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  130. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  131. metadata +103 -69
  132. data/KNOWN-ISSUES +0 -44
  133. data/lib/rack/backports/uri/common_18.rb +0 -56
  134. data/lib/rack/backports/uri/common_192.rb +0 -52
  135. data/lib/rack/backports/uri/common_193.rb +0 -29
  136. data/lib/rack/handler/evented_mongrel.rb +0 -8
  137. data/lib/rack/handler/mongrel.rb +0 -106
  138. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  139. data/lib/rack/showexceptions.rb +0 -387
  140. data/lib/rack/utils/okjson.rb +0 -600
  141. data/test/spec_methodoverride.rb +0 -111
  142. data/test/spec_mongrel.rb +0 -182
  143. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  144. data/test/spec_showexceptions.rb +0 -98
@@ -24,7 +24,7 @@ module Rack
24
24
  # )
25
25
  # Rack::Handler::WEBrick.run sessioned
26
26
 
27
- class Pool < Abstract::PersistedSecure
27
+ class Pool < Abstract::Persisted
28
28
  attr_reader :mutex, :pool
29
29
  DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge :drop => false
30
30
 
@@ -37,47 +37,40 @@ module Rack
37
37
  def generate_sid
38
38
  loop do
39
39
  sid = super
40
- break sid unless @pool.key? sid.private_id
40
+ break sid unless @pool.key? sid
41
41
  end
42
42
  end
43
43
 
44
- def get_session(env, sid)
45
- with_lock(env) do
46
- unless sid and session = get_session_with_fallback(sid)
44
+ def find_session(req, sid)
45
+ with_lock(req) do
46
+ unless sid and session = @pool[sid]
47
47
  sid, session = generate_sid, {}
48
- @pool.store sid.private_id, session
48
+ @pool.store sid, session
49
49
  end
50
50
  [sid, session]
51
51
  end
52
52
  end
53
53
 
54
- def set_session(env, session_id, new_session, options)
55
- with_lock(env) do
56
- @pool.store session_id.private_id, new_session
54
+ def write_session(req, session_id, new_session, options)
55
+ with_lock(req) do
56
+ @pool.store session_id, new_session
57
57
  session_id
58
58
  end
59
59
  end
60
60
 
61
- def destroy_session(env, session_id, options)
62
- with_lock(env) do
63
- @pool.delete(session_id.public_id)
64
- @pool.delete(session_id.private_id)
61
+ def delete_session(req, session_id, options)
62
+ with_lock(req) do
63
+ @pool.delete(session_id)
65
64
  generate_sid unless options[:drop]
66
65
  end
67
66
  end
68
67
 
69
- def with_lock(env)
70
- @mutex.lock if env['rack.multithread']
68
+ def with_lock(req)
69
+ @mutex.lock if req.multithread?
71
70
  yield
72
71
  ensure
73
72
  @mutex.unlock if @mutex.locked?
74
73
  end
75
-
76
- private
77
-
78
- def get_session_with_fallback(sid)
79
- @pool[sid.private_id] || @pool[sid.public_id]
80
- end
81
74
  end
82
75
  end
83
76
  end
@@ -0,0 +1,386 @@
1
+ require 'ostruct'
2
+ require 'erb'
3
+ require 'rack/request'
4
+ require 'rack/utils'
5
+
6
+ module Rack
7
+ # Rack::ShowExceptions catches all exceptions raised from the app it
8
+ # wraps. It shows a useful backtrace with the sourcefile and
9
+ # clickable context, the whole Rack environment and the request
10
+ # data.
11
+ #
12
+ # Be careful when you use this on public-facing sites as it could
13
+ # reveal information helpful to attackers.
14
+
15
+ class ShowExceptions
16
+ CONTEXT = 7
17
+
18
+ def initialize(app)
19
+ @app = app
20
+ end
21
+
22
+ def call(env)
23
+ @app.call(env)
24
+ rescue StandardError, LoadError, SyntaxError => e
25
+ exception_string = dump_exception(e)
26
+
27
+ env[RACK_ERRORS].puts(exception_string)
28
+ env[RACK_ERRORS].flush
29
+
30
+ if accepts_html?(env)
31
+ content_type = "text/html"
32
+ body = pretty(env, e)
33
+ else
34
+ content_type = "text/plain"
35
+ body = exception_string
36
+ end
37
+
38
+ [
39
+ 500,
40
+ {
41
+ CONTENT_TYPE => content_type,
42
+ CONTENT_LENGTH => body.bytesize.to_s,
43
+ },
44
+ [body],
45
+ ]
46
+ end
47
+
48
+ def prefers_plaintext?(env)
49
+ !accepts_html(env)
50
+ end
51
+
52
+ def accepts_html?(env)
53
+ Rack::Utils.best_q_match(env["HTTP_ACCEPT"], %w[text/html])
54
+ end
55
+ private :accepts_html?
56
+
57
+ def dump_exception(exception)
58
+ string = "#{exception.class}: #{exception.message}\n"
59
+ string << exception.backtrace.map { |l| "\t#{l}" }.join("\n")
60
+ string
61
+ end
62
+
63
+ def pretty(env, exception)
64
+ req = Rack::Request.new(env)
65
+
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.
68
+ path = path = (req.script_name + req.path_info).squeeze("/")
69
+
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.
72
+ frames = frames = exception.backtrace.map { |line|
73
+ frame = OpenStruct.new
74
+ if line =~ /(.*?):(\d+)(:in `(.*)')?/
75
+ frame.filename = $1
76
+ frame.lineno = $2.to_i
77
+ frame.function = $4
78
+
79
+ begin
80
+ lineno = frame.lineno-1
81
+ lines = ::File.readlines(frame.filename)
82
+ frame.pre_context_lineno = [lineno-CONTEXT, 0].max
83
+ frame.pre_context = lines[frame.pre_context_lineno...lineno]
84
+ 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]
87
+ rescue
88
+ end
89
+
90
+ frame
91
+ else
92
+ nil
93
+ end
94
+ }.compact
95
+
96
+ TEMPLATE.result(binding)
97
+ end
98
+
99
+ def h(obj) # :nodoc:
100
+ case obj
101
+ when String
102
+ Utils.escape_html(obj)
103
+ else
104
+ Utils.escape_html(obj.inspect)
105
+ end
106
+ end
107
+
108
+ # :stopdoc:
109
+
110
+ # adapted from Django <djangoproject.com>
111
+ # Copyright (c) 2005, the Lawrence Journal-World
112
+ # Used under the modified BSD license:
113
+ # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
114
+ TEMPLATE = ERB.new(<<-'HTML'.gsub(/^ /, ''))
115
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
116
+ <html lang="en">
117
+ <head>
118
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
119
+ <meta name="robots" content="NONE,NOARCHIVE" />
120
+ <title><%=h exception.class %> at <%=h path %></title>
121
+ <style type="text/css">
122
+ html * { padding:0; margin:0; }
123
+ body * { padding:10px 20px; }
124
+ body * * { padding:0; }
125
+ body { font:small sans-serif; }
126
+ body>div { border-bottom:1px solid #ddd; }
127
+ h1 { font-weight:normal; }
128
+ h2 { margin-bottom:.8em; }
129
+ h2 span { font-size:80%; color:#666; font-weight:normal; }
130
+ h3 { margin:1em 0 .5em 0; }
131
+ h4 { margin:0 0 .5em 0; font-weight: normal; }
132
+ table {
133
+ border:1px solid #ccc; border-collapse: collapse; background:white; }
134
+ tbody td, tbody th { vertical-align:top; padding:2px 3px; }
135
+ thead th {
136
+ padding:1px 6px 1px 3px; background:#fefefe; text-align:left;
137
+ font-weight:normal; font-size:11px; border:1px solid #ddd; }
138
+ tbody th { text-align:right; color:#666; padding-right:.5em; }
139
+ table.vars { margin:5px 0 2px 40px; }
140
+ table.vars td, table.req td { font-family:monospace; }
141
+ table td.code { width:100%;}
142
+ table td.code div { overflow:hidden; }
143
+ table.source th { color:#666; }
144
+ table.source td {
145
+ font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
146
+ ul.traceback { list-style-type:none; }
147
+ ul.traceback li.frame { margin-bottom:1em; }
148
+ div.context { margin: 10px 0; }
149
+ div.context ol {
150
+ padding-left:30px; margin:0 10px; list-style-position: inside; }
151
+ div.context ol li {
152
+ font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
153
+ div.context ol.context-line li { color:black; background-color:#ccc; }
154
+ div.context ol.context-line li span { float: right; }
155
+ div.commands { margin-left: 40px; }
156
+ div.commands a { color:black; text-decoration:none; }
157
+ #summary { background: #ffc; }
158
+ #summary h2 { font-weight: normal; color: #666; }
159
+ #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
160
+ #summary ul#quicklinks li { float: left; padding: 0 1em; }
161
+ #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
162
+ #explanation { background:#eee; }
163
+ #template, #template-not-exist { background:#f6f6f6; }
164
+ #template-not-exist ul { margin: 0 0 0 20px; }
165
+ #traceback { background:#eee; }
166
+ #requestinfo { background:#f6f6f6; padding-left:120px; }
167
+ #summary table { border:none; background:transparent; }
168
+ #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
169
+ #requestinfo h3 { margin-bottom:-1em; }
170
+ .error { background: #ffc; }
171
+ .specific { color:#cc3300; font-weight:bold; }
172
+ </style>
173
+ <script type="text/javascript">
174
+ //<!--
175
+ function getElementsByClassName(oElm, strTagName, strClassName){
176
+ // Written by Jonathan Snook, http://www.snook.ca/jon;
177
+ // Add-ons by Robert Nyman, http://www.robertnyman.com
178
+ var arrElements = (strTagName == "*" && document.all)? document.all :
179
+ oElm.getElementsByTagName(strTagName);
180
+ var arrReturnElements = new Array();
181
+ strClassName = strClassName.replace(/\-/g, "\\-");
182
+ var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)");
183
+ var oElement;
184
+ for(var i=0; i<arrElements.length; i++){
185
+ oElement = arrElements[i];
186
+ if(oRegExp.test(oElement.className)){
187
+ arrReturnElements.push(oElement);
188
+ }
189
+ }
190
+ return (arrReturnElements)
191
+ }
192
+ function hideAll(elems) {
193
+ for (var e = 0; e < elems.length; e++) {
194
+ elems[e].style.display = 'none';
195
+ }
196
+ }
197
+ window.onload = function() {
198
+ hideAll(getElementsByClassName(document, 'table', 'vars'));
199
+ hideAll(getElementsByClassName(document, 'ol', 'pre-context'));
200
+ hideAll(getElementsByClassName(document, 'ol', 'post-context'));
201
+ }
202
+ function toggle() {
203
+ for (var i = 0; i < arguments.length; i++) {
204
+ var e = document.getElementById(arguments[i]);
205
+ if (e) {
206
+ e.style.display = e.style.display == 'none' ? 'block' : 'none';
207
+ }
208
+ }
209
+ return false;
210
+ }
211
+ function varToggle(link, id) {
212
+ toggle('v' + id);
213
+ var s = link.getElementsByTagName('span')[0];
214
+ var uarr = String.fromCharCode(0x25b6);
215
+ var darr = String.fromCharCode(0x25bc);
216
+ s.innerHTML = s.innerHTML == uarr ? darr : uarr;
217
+ return false;
218
+ }
219
+ //-->
220
+ </script>
221
+ </head>
222
+ <body>
223
+
224
+ <div id="summary">
225
+ <h1><%=h exception.class %> at <%=h path %></h1>
226
+ <h2><%=h exception.message %></h2>
227
+ <table><tr>
228
+ <th>Ruby</th>
229
+ <td>
230
+ <% if first = frames.first %>
231
+ <code><%=h first.filename %></code>: in <code><%=h first.function %></code>, line <%=h frames.first.lineno %>
232
+ <% else %>
233
+ unknown location
234
+ <% end %>
235
+ </td>
236
+ </tr><tr>
237
+ <th>Web</th>
238
+ <td><code><%=h req.request_method %> <%=h(req.host + path)%></code></td>
239
+ </tr></table>
240
+
241
+ <h3>Jump to:</h3>
242
+ <ul id="quicklinks">
243
+ <li><a href="#get-info">GET</a></li>
244
+ <li><a href="#post-info">POST</a></li>
245
+ <li><a href="#cookie-info">Cookies</a></li>
246
+ <li><a href="#env-info">ENV</a></li>
247
+ </ul>
248
+ </div>
249
+
250
+ <div id="traceback">
251
+ <h2>Traceback <span>(innermost first)</span></h2>
252
+ <ul class="traceback">
253
+ <% frames.each { |frame| %>
254
+ <li class="frame">
255
+ <code><%=h frame.filename %></code>: in <code><%=h frame.function %></code>
256
+
257
+ <% if frame.context_line %>
258
+ <div class="context" id="c<%=h frame.object_id %>">
259
+ <% if frame.pre_context %>
260
+ <ol start="<%=h frame.pre_context_lineno+1 %>" class="pre-context" id="pre<%=h frame.object_id %>">
261
+ <% frame.pre_context.each { |line| %>
262
+ <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line %></li>
263
+ <% } %>
264
+ </ol>
265
+ <% end %>
266
+
267
+ <ol start="<%=h frame.lineno %>" class="context-line">
268
+ <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h frame.context_line %><span>...</span></li></ol>
269
+
270
+ <% if frame.post_context %>
271
+ <ol start='<%=h frame.lineno+1 %>' class="post-context" id="post<%=h frame.object_id %>">
272
+ <% frame.post_context.each { |line| %>
273
+ <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line %></li>
274
+ <% } %>
275
+ </ol>
276
+ <% end %>
277
+ </div>
278
+ <% end %>
279
+ </li>
280
+ <% } %>
281
+ </ul>
282
+ </div>
283
+
284
+ <div id="requestinfo">
285
+ <h2>Request information</h2>
286
+
287
+ <h3 id="get-info">GET</h3>
288
+ <% if req.GET and not req.GET.empty? %>
289
+ <table class="req">
290
+ <thead>
291
+ <tr>
292
+ <th>Variable</th>
293
+ <th>Value</th>
294
+ </tr>
295
+ </thead>
296
+ <tbody>
297
+ <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %>
298
+ <tr>
299
+ <td><%=h key %></td>
300
+ <td class="code"><div><%=h val.inspect %></div></td>
301
+ </tr>
302
+ <% } %>
303
+ </tbody>
304
+ </table>
305
+ <% else %>
306
+ <p>No GET data.</p>
307
+ <% end %>
308
+
309
+ <h3 id="post-info">POST</h3>
310
+ <% if req.POST and not req.POST.empty? %>
311
+ <table class="req">
312
+ <thead>
313
+ <tr>
314
+ <th>Variable</th>
315
+ <th>Value</th>
316
+ </tr>
317
+ </thead>
318
+ <tbody>
319
+ <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %>
320
+ <tr>
321
+ <td><%=h key %></td>
322
+ <td class="code"><div><%=h val.inspect %></div></td>
323
+ </tr>
324
+ <% } %>
325
+ </tbody>
326
+ </table>
327
+ <% else %>
328
+ <p>No POST data.</p>
329
+ <% end %>
330
+
331
+
332
+ <h3 id="cookie-info">COOKIES</h3>
333
+ <% unless req.cookies.empty? %>
334
+ <table class="req">
335
+ <thead>
336
+ <tr>
337
+ <th>Variable</th>
338
+ <th>Value</th>
339
+ </tr>
340
+ </thead>
341
+ <tbody>
342
+ <% req.cookies.each { |key, val| %>
343
+ <tr>
344
+ <td><%=h key %></td>
345
+ <td class="code"><div><%=h val.inspect %></div></td>
346
+ </tr>
347
+ <% } %>
348
+ </tbody>
349
+ </table>
350
+ <% else %>
351
+ <p>No cookie data.</p>
352
+ <% end %>
353
+
354
+ <h3 id="env-info">Rack ENV</h3>
355
+ <table class="req">
356
+ <thead>
357
+ <tr>
358
+ <th>Variable</th>
359
+ <th>Value</th>
360
+ </tr>
361
+ </thead>
362
+ <tbody>
363
+ <% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
364
+ <tr>
365
+ <td><%=h key %></td>
366
+ <td class="code"><div><%=h val %></div></td>
367
+ </tr>
368
+ <% } %>
369
+ </tbody>
370
+ </table>
371
+
372
+ </div>
373
+
374
+ <div id="explanation">
375
+ <p>
376
+ You're seeing this error because you use <code>Rack::ShowExceptions</code>.
377
+ </p>
378
+ </div>
379
+
380
+ </body>
381
+ </html>
382
+ HTML
383
+
384
+ # :startdoc:
385
+ end
386
+ end
@@ -22,7 +22,7 @@ module Rack
22
22
  empty = headers[CONTENT_LENGTH].to_i <= 0
23
23
 
24
24
  # client or server error, or explicit message
25
- if (status.to_i >= 400 && empty) || env["rack.showstatus.detail"]
25
+ if (status.to_i >= 400 && empty) || env[RACK_SHOWSTATUS_DETAIL]
26
26
  # This double assignment is to prevent an "unused variable" warning on
27
27
  # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me.
28
28
  req = req = Rack::Request.new(env)
@@ -31,10 +31,10 @@ module Rack
31
31
 
32
32
  # This double assignment is to prevent an "unused variable" warning on
33
33
  # 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
34
+ detail = detail = env[RACK_SHOWSTATUS_DETAIL] || message
35
35
 
36
36
  body = @template.result(binding)
37
- size = Rack::Utils.bytesize(body)
37
+ size = body.bytesize
38
38
  [status, headers.merge(CONTENT_TYPE => "text/html", CONTENT_LENGTH => size.to_s), [body]]
39
39
  else
40
40
  [status, headers, body]
data/lib/rack/static.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require "rack/file"
2
+ require "rack/utils"
3
+
1
4
  module Rack
2
5
 
3
6
  # The Rack::Static middleware intercepts requests for static files
@@ -84,18 +87,23 @@ module Rack
84
87
  @app = app
85
88
  @urls = options[:urls] || ["/favicon.ico"]
86
89
  @index = options[:index]
90
+ @gzip = options[:gzip]
87
91
  root = options[:root] || Dir.pwd
88
92
 
89
93
  # HTTP Headers
90
94
  @header_rules = options[:header_rules] || []
91
95
  # 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]
96
+ @header_rules.unshift([:all, {CACHE_CONTROL => options[:cache_control]}]) if options[:cache_control]
93
97
 
94
98
  @file_server = Rack::File.new(root)
95
99
  end
96
100
 
101
+ def add_index_root?(path)
102
+ @index && path =~ /\/$/
103
+ end
104
+
97
105
  def overwrite_file_path(path)
98
- @urls.kind_of?(Hash) && @urls.key?(path) || @index && path =~ /\/$/
106
+ @urls.kind_of?(Hash) && @urls.key?(path) || add_index_root?(path)
99
107
  end
100
108
 
101
109
  def route_file(path)
@@ -110,9 +118,26 @@ module Rack
110
118
  path = env[PATH_INFO]
111
119
 
112
120
  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)
121
+ if overwrite_file_path(path)
122
+ env[PATH_INFO] = (add_index_root?(path) ? path + @index : @urls[path])
123
+ elsif @gzip && env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/
124
+ path = env[PATH_INFO]
125
+ env[PATH_INFO] += '.gz'
126
+ response = @file_server.call(env)
127
+ env[PATH_INFO] = path
128
+
129
+ if response[0] == 404
130
+ response = nil
131
+ 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'
136
+ end
137
+ end
138
+
139
+ path = env[PATH_INFO]
140
+ response ||= @file_server.call(env)
116
141
 
117
142
  headers = response[1]
118
143
  applicable_rules(path).each do |rule, new_headers|
@@ -11,10 +11,10 @@ module Rack
11
11
  end
12
12
 
13
13
  def call(env)
14
- env['rack.tempfiles'] ||= []
14
+ env[RACK_TEMPFILES] ||= []
15
15
  status, headers, body = @app.call(env)
16
16
  body_proxy = BodyProxy.new(body) do
17
- env['rack.tempfiles'].each { |f| f.close! } unless env['rack.tempfiles'].nil?
17
+ env[RACK_TEMPFILES].each(&:close!) unless env[RACK_TEMPFILES].nil?
18
18
  end
19
19
  [status, headers, body_proxy]
20
20
  end
data/lib/rack/urlmap.rb CHANGED
@@ -41,17 +41,19 @@ module Rack
41
41
  end
42
42
 
43
43
  def call(env)
44
- path = env[PATH_INFO]
45
- script_name = env['SCRIPT_NAME']
46
- hHost = env['HTTP_HOST']
47
- sName = env['SERVER_NAME']
48
- sPort = env['SERVER_PORT']
44
+ path = env[PATH_INFO]
45
+ script_name = env[SCRIPT_NAME]
46
+ http_host = env[HTTP_HOST]
47
+ server_name = env[SERVER_NAME]
48
+ server_port = env[SERVER_PORT]
49
+
50
+ is_same_server = casecmp?(http_host, server_name) ||
51
+ casecmp?(http_host, "#{server_name}:#{server_port}")
49
52
 
50
53
  @mapping.each do |host, location, match, app|
51
- unless casecmp?(hHost, host) \
52
- || casecmp?(sName, host) \
53
- || (!host && (casecmp?(hHost, sName) ||
54
- casecmp?(hHost, sName+':'+sPort)))
54
+ unless casecmp?(http_host, host) \
55
+ || casecmp?(server_name, host) \
56
+ || (!host && is_same_server)
55
57
  next
56
58
  end
57
59
 
@@ -60,8 +62,8 @@ module Rack
60
62
  rest = m[1]
61
63
  next unless !rest || rest.empty? || rest[0] == ?/
62
64
 
63
- env['SCRIPT_NAME'] = (script_name + location)
64
- env['PATH_INFO'] = rest
65
+ env[SCRIPT_NAME] = (script_name + location)
66
+ env[PATH_INFO] = rest
65
67
 
66
68
  return app.call(env)
67
69
  end
@@ -69,8 +71,8 @@ module Rack
69
71
  [404, {CONTENT_TYPE => "text/plain", "X-Cascade" => "pass"}, ["Not Found: #{path}"]]
70
72
 
71
73
  ensure
72
- env['PATH_INFO'] = path
73
- env['SCRIPT_NAME'] = script_name
74
+ env[PATH_INFO] = path
75
+ env[SCRIPT_NAME] = script_name
74
76
  end
75
77
 
76
78
  private
@@ -87,4 +89,3 @@ module Rack
87
89
  end
88
90
  end
89
91
  end
90
-