actionpack 2.3.2 → 2.3.3

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

Potentially problematic release.


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

Files changed (117) hide show
  1. data/CHANGELOG +5 -0
  2. data/Rakefile +10 -9
  3. data/lib/action_controller.rb +2 -7
  4. data/lib/action_controller/assertions/response_assertions.rb +11 -3
  5. data/lib/action_controller/base.rb +7 -2
  6. data/lib/action_controller/caching.rb +1 -1
  7. data/lib/action_controller/caching/actions.rb +9 -1
  8. data/lib/action_controller/caching/sweeper.rb +45 -0
  9. data/lib/action_controller/caching/sweeping.rb +0 -42
  10. data/lib/action_controller/failsafe.rb +40 -6
  11. data/lib/action_controller/flash.rb +11 -3
  12. data/lib/action_controller/http_authentication.rb +5 -2
  13. data/lib/action_controller/integration.rb +5 -12
  14. data/lib/action_controller/middlewares.rb +0 -1
  15. data/lib/action_controller/reloader.rb +34 -3
  16. data/lib/action_controller/request.rb +6 -2
  17. data/lib/action_controller/response.rb +2 -2
  18. data/lib/action_controller/routing/route_set.rb +2 -1
  19. data/lib/action_controller/streaming.rb +1 -1
  20. data/lib/action_controller/test_process.rb +9 -1
  21. data/lib/action_pack/version.rb +1 -1
  22. data/lib/action_view/helpers.rb +1 -1
  23. data/lib/action_view/helpers/asset_tag_helper.rb +21 -9
  24. data/lib/action_view/helpers/date_helper.rb +2 -2
  25. data/lib/action_view/helpers/form_helper.rb +25 -12
  26. data/lib/action_view/helpers/form_options_helper.rb +2 -0
  27. data/lib/action_view/helpers/form_tag_helper.rb +10 -4
  28. data/lib/action_view/helpers/number_helper.rb +1 -1
  29. data/lib/action_view/helpers/prototype_helper.rb +7 -7
  30. data/lib/action_view/helpers/scriptaculous_helper.rb +5 -5
  31. data/lib/action_view/helpers/text_helper.rb +3 -3
  32. data/lib/action_view/helpers/url_helper.rb +1 -1
  33. data/lib/action_view/paths.rb +1 -1
  34. data/lib/action_view/template.rb +22 -33
  35. data/test/abstract_unit.rb +1 -1
  36. data/test/activerecord/active_record_store_test.rb +3 -3
  37. data/test/controller/action_pack_assertions_test.rb +27 -0
  38. data/test/controller/caching_test.rb +39 -0
  39. data/test/controller/cookie_test.rb +10 -0
  40. data/test/controller/dispatcher_test.rb +9 -7
  41. data/test/controller/failsafe_test.rb +60 -0
  42. data/test/controller/filter_params_test.rb +2 -1
  43. data/test/controller/flash_test.rb +6 -1
  44. data/test/controller/http_digest_authentication_test.rb +34 -3
  45. data/test/controller/integration_test.rb +31 -3
  46. data/test/controller/redirect_test.rb +4 -1
  47. data/test/controller/reloader_test.rb +97 -0
  48. data/test/controller/render_test.rb +19 -9
  49. data/test/controller/request/multipart_params_parsing_test.rb +1 -62
  50. data/test/controller/request/test_request_test.rb +35 -0
  51. data/test/controller/request/url_encoded_params_parsing_test.rb +0 -38
  52. data/test/controller/request_test.rb +218 -230
  53. data/test/controller/resources_test.rb +8 -0
  54. data/test/controller/routing_test.rb +21 -0
  55. data/test/controller/send_file_test.rb +1 -1
  56. data/test/controller/session/cookie_store_test.rb +9 -32
  57. data/test/controller/test_test.rb +8 -0
  58. data/test/fixtures/failsafe/500.html +1 -0
  59. data/test/template/active_record_helper_test.rb +1 -1
  60. data/test/template/asset_tag_helper_test.rb +46 -0
  61. data/test/template/form_helper_test.rb +117 -6
  62. data/test/template/form_options_helper_test.rb +22 -0
  63. data/test/template/form_tag_helper_test.rb +23 -6
  64. data/test/template/prototype_helper_test.rb +11 -11
  65. data/test/template/template_test.rb +32 -0
  66. metadata +20 -63
  67. data/lib/action_controller/rewindable_input.rb +0 -28
  68. data/lib/action_controller/vendor/rack-1.0/rack.rb +0 -89
  69. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +0 -22
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +0 -37
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +0 -37
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +0 -58
  73. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +0 -124
  74. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +0 -51
  75. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +0 -55
  76. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +0 -40
  77. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +0 -480
  78. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +0 -63
  79. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +0 -36
  80. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +0 -49
  81. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +0 -61
  82. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +0 -45
  83. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +0 -29
  84. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +0 -23
  85. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +0 -85
  86. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +0 -153
  87. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +0 -88
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +0 -48
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +0 -61
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +0 -8
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +0 -89
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +0 -55
  93. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +0 -84
  94. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +0 -59
  95. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +0 -8
  96. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +0 -18
  97. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +0 -67
  98. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +0 -19
  99. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +0 -462
  100. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +0 -65
  101. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +0 -16
  102. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +0 -27
  103. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +0 -204
  104. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +0 -160
  105. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +0 -57
  106. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +0 -64
  107. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +0 -241
  108. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +0 -179
  109. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +0 -142
  110. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +0 -91
  111. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +0 -109
  112. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +0 -100
  113. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +0 -349
  114. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +0 -106
  115. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +0 -38
  116. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +0 -55
  117. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +0 -392
@@ -1,63 +0,0 @@
1
- module Rack
2
- # Rack::Builder implements a small DSL to iteratively construct Rack
3
- # applications.
4
- #
5
- # Example:
6
- #
7
- # app = Rack::Builder.new {
8
- # use Rack::CommonLogger
9
- # use Rack::ShowExceptions
10
- # map "/lobster" do
11
- # use Rack::Lint
12
- # run Rack::Lobster.new
13
- # end
14
- # }
15
- #
16
- # Or
17
- #
18
- # app = Rack::Builder.app do
19
- # use Rack::CommonLogger
20
- # lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] }
21
- # end
22
- #
23
- # +use+ adds a middleware to the stack, +run+ dispatches to an application.
24
- # You can use +map+ to construct a Rack::URLMap in a convenient way.
25
-
26
- class Builder
27
- def initialize(&block)
28
- @ins = []
29
- instance_eval(&block) if block_given?
30
- end
31
-
32
- def self.app(&block)
33
- self.new(&block).to_app
34
- end
35
-
36
- def use(middleware, *args, &block)
37
- @ins << lambda { |app| middleware.new(app, *args, &block) }
38
- end
39
-
40
- def run(app)
41
- @ins << app #lambda { |nothing| app }
42
- end
43
-
44
- def map(path, &block)
45
- if @ins.last.kind_of? Hash
46
- @ins.last[path] = self.class.new(&block).to_app
47
- else
48
- @ins << {}
49
- map(path, &block)
50
- end
51
- end
52
-
53
- def to_app
54
- @ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last
55
- inner_app = @ins.last
56
- @ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) }
57
- end
58
-
59
- def call(env)
60
- to_app.call(env)
61
- end
62
- end
63
- end
@@ -1,36 +0,0 @@
1
- module Rack
2
- # Rack::Cascade tries an request on several apps, and returns the
3
- # first response that is not 404 (or in a list of configurable
4
- # status codes).
5
-
6
- class Cascade
7
- attr_reader :apps
8
-
9
- def initialize(apps, catch=404)
10
- @apps = apps
11
- @catch = [*catch]
12
- end
13
-
14
- def call(env)
15
- status = headers = body = nil
16
- raise ArgumentError, "empty cascade" if @apps.empty?
17
- @apps.each { |app|
18
- begin
19
- status, headers, body = app.call(env)
20
- break unless @catch.include?(status.to_i)
21
- end
22
- }
23
- [status, headers, body]
24
- end
25
-
26
- def add app
27
- @apps << app
28
- end
29
-
30
- def include? app
31
- @apps.include? app
32
- end
33
-
34
- alias_method :<<, :add
35
- end
36
- end
@@ -1,49 +0,0 @@
1
- require 'rack/utils'
2
-
3
- module Rack
4
-
5
- # Middleware that applies chunked transfer encoding to response bodies
6
- # when the response does not include a Content-Length header.
7
- class Chunked
8
- include Rack::Utils
9
-
10
- def initialize(app)
11
- @app = app
12
- end
13
-
14
- def call(env)
15
- status, headers, body = @app.call(env)
16
- headers = HeaderHash.new(headers)
17
-
18
- if env['HTTP_VERSION'] == 'HTTP/1.0' ||
19
- STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
20
- headers['Content-Length'] ||
21
- headers['Transfer-Encoding']
22
- [status, headers.to_hash, body]
23
- else
24
- dup.chunk(status, headers, body)
25
- end
26
- end
27
-
28
- def chunk(status, headers, body)
29
- @body = body
30
- headers.delete('Content-Length')
31
- headers['Transfer-Encoding'] = 'chunked'
32
- [status, headers.to_hash, self]
33
- end
34
-
35
- def each
36
- term = "\r\n"
37
- @body.each do |chunk|
38
- size = bytesize(chunk)
39
- next if size == 0
40
- yield [size.to_s(16), term, chunk, term].join
41
- end
42
- yield ["0", term, "", term].join
43
- end
44
-
45
- def close
46
- @body.close if @body.respond_to?(:close)
47
- end
48
- end
49
- end
@@ -1,61 +0,0 @@
1
- module Rack
2
- # Rack::CommonLogger forwards every request to an +app+ given, and
3
- # logs a line in the Apache common log format to the +logger+, or
4
- # rack.errors by default.
5
-
6
- class CommonLogger
7
- def initialize(app, logger=nil)
8
- @app = app
9
- @logger = logger
10
- end
11
-
12
- def call(env)
13
- dup._call(env)
14
- end
15
-
16
- def _call(env)
17
- @env = env
18
- @logger ||= self
19
- @time = Time.now
20
- @status, @header, @body = @app.call(env)
21
- [@status, @header, self]
22
- end
23
-
24
- def close
25
- @body.close if @body.respond_to? :close
26
- end
27
-
28
- # By default, log to rack.errors.
29
- def <<(str)
30
- @env["rack.errors"].write(str)
31
- @env["rack.errors"].flush
32
- end
33
-
34
- def each
35
- length = 0
36
- @body.each { |part|
37
- length += part.size
38
- yield part
39
- }
40
-
41
- @now = Time.now
42
-
43
- # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
44
- # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
45
- # %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
46
- @logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} %
47
- [
48
- @env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-",
49
- @env["REMOTE_USER"] || "-",
50
- @now.strftime("%d/%b/%Y %H:%M:%S"),
51
- @env["REQUEST_METHOD"],
52
- @env["PATH_INFO"],
53
- @env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"],
54
- @env["HTTP_VERSION"],
55
- @status.to_s[0..3],
56
- (length.zero? ? "-" : length.to_s),
57
- @now - @time
58
- ]
59
- end
60
- end
61
- end
@@ -1,45 +0,0 @@
1
- require 'rack/utils'
2
-
3
- module Rack
4
-
5
- # Middleware that enables conditional GET using If-None-Match and
6
- # If-Modified-Since. The application should set either or both of the
7
- # Last-Modified or Etag response headers according to RFC 2616. When
8
- # either of the conditions is met, the response body is set to be zero
9
- # length and the response status is set to 304 Not Modified.
10
- #
11
- # Applications that defer response body generation until the body's each
12
- # message is received will avoid response body generation completely when
13
- # a conditional GET matches.
14
- #
15
- # Adapted from Michael Klishin's Merb implementation:
16
- # http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb
17
- class ConditionalGet
18
- def initialize(app)
19
- @app = app
20
- end
21
-
22
- def call(env)
23
- return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD'])
24
-
25
- status, headers, body = @app.call(env)
26
- headers = Utils::HeaderHash.new(headers)
27
- if etag_matches?(env, headers) || modified_since?(env, headers)
28
- status = 304
29
- body = []
30
- end
31
- [status, headers, body]
32
- end
33
-
34
- private
35
- def etag_matches?(env, headers)
36
- etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH']
37
- end
38
-
39
- def modified_since?(env, headers)
40
- last_modified = headers['Last-Modified'] and
41
- last_modified == env['HTTP_IF_MODIFIED_SINCE']
42
- end
43
- end
44
-
45
- end
@@ -1,29 +0,0 @@
1
- require 'rack/utils'
2
-
3
- module Rack
4
- # Sets the Content-Length header on responses with fixed-length bodies.
5
- class ContentLength
6
- include Rack::Utils
7
-
8
- def initialize(app)
9
- @app = app
10
- end
11
-
12
- def call(env)
13
- status, headers, body = @app.call(env)
14
- headers = HeaderHash.new(headers)
15
-
16
- if !STATUS_WITH_NO_ENTITY_BODY.include?(status) &&
17
- !headers['Content-Length'] &&
18
- !headers['Transfer-Encoding'] &&
19
- (body.respond_to?(:to_ary) || body.respond_to?(:to_str))
20
-
21
- body = [body] if body.respond_to?(:to_str) # rack 0.4 compat
22
- length = body.to_ary.inject(0) { |len, part| len + bytesize(part) }
23
- headers['Content-Length'] = length.to_s
24
- end
25
-
26
- [status, headers, body]
27
- end
28
- end
29
- end
@@ -1,23 +0,0 @@
1
- require 'rack/utils'
2
-
3
- module Rack
4
-
5
- # Sets the Content-Type header on responses which don't have one.
6
- #
7
- # Builder Usage:
8
- # use Rack::ContentType, "text/plain"
9
- #
10
- # When no content type argument is provided, "text/html" is assumed.
11
- class ContentType
12
- def initialize(app, content_type = "text/html")
13
- @app, @content_type = app, content_type
14
- end
15
-
16
- def call(env)
17
- status, headers, body = @app.call(env)
18
- headers = Utils::HeaderHash.new(headers)
19
- headers['Content-Type'] ||= @content_type
20
- [status, headers.to_hash, body]
21
- end
22
- end
23
- end
@@ -1,85 +0,0 @@
1
- require "zlib"
2
- require "stringio"
3
- require "time" # for Time.httpdate
4
- require 'rack/utils'
5
-
6
- module Rack
7
- class Deflater
8
- def initialize(app)
9
- @app = app
10
- end
11
-
12
- def call(env)
13
- status, headers, body = @app.call(env)
14
- headers = Utils::HeaderHash.new(headers)
15
-
16
- # Skip compressing empty entity body responses and responses with
17
- # no-transform set.
18
- if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
19
- headers['Cache-Control'].to_s =~ /\bno-transform\b/
20
- return [status, headers, body]
21
- end
22
-
23
- request = Request.new(env)
24
-
25
- encoding = Utils.select_best_encoding(%w(gzip deflate identity),
26
- request.accept_encoding)
27
-
28
- # Set the Vary HTTP header.
29
- vary = headers["Vary"].to_s.split(",").map { |v| v.strip }
30
- unless vary.include?("*") || vary.include?("Accept-Encoding")
31
- headers["Vary"] = vary.push("Accept-Encoding").join(",")
32
- end
33
-
34
- case encoding
35
- when "gzip"
36
- mtime = headers.key?("Last-Modified") ?
37
- Time.httpdate(headers["Last-Modified"]) : Time.now
38
- body = self.class.gzip(body, mtime)
39
- size = Rack::Utils.bytesize(body)
40
- headers = headers.merge("Content-Encoding" => "gzip", "Content-Length" => size.to_s)
41
- [status, headers, [body]]
42
- when "deflate"
43
- body = self.class.deflate(body)
44
- size = Rack::Utils.bytesize(body)
45
- headers = headers.merge("Content-Encoding" => "deflate", "Content-Length" => size.to_s)
46
- [status, headers, [body]]
47
- when "identity"
48
- [status, headers, body]
49
- when nil
50
- message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
51
- [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]]
52
- end
53
- end
54
-
55
- def self.gzip(body, mtime)
56
- io = StringIO.new
57
- gzip = Zlib::GzipWriter.new(io)
58
- gzip.mtime = mtime
59
-
60
- # TODO: Add streaming
61
- body.each { |part| gzip << part }
62
-
63
- gzip.close
64
- return io.string
65
- end
66
-
67
- DEFLATE_ARGS = [
68
- Zlib::DEFAULT_COMPRESSION,
69
- # drop the zlib header which causes both Safari and IE to choke
70
- -Zlib::MAX_WBITS,
71
- Zlib::DEF_MEM_LEVEL,
72
- Zlib::DEFAULT_STRATEGY
73
- ]
74
-
75
- # Loosely based on Mongrel's Deflate handler
76
- def self.deflate(body)
77
- deflater = Zlib::Deflate.new(*DEFLATE_ARGS)
78
-
79
- # TODO: Add streaming
80
- body.each { |part| deflater << part }
81
-
82
- return deflater.finish
83
- end
84
- end
85
- end
@@ -1,153 +0,0 @@
1
- require 'time'
2
- require 'rack/utils'
3
- require 'rack/mime'
4
-
5
- module Rack
6
- # Rack::Directory serves entries below the +root+ given, according to the
7
- # path info of the Rack request. If a directory is found, the file's contents
8
- # will be presented in an html based index. If a file is found, the env will
9
- # be passed to the specified +app+.
10
- #
11
- # If +app+ is not specified, a Rack::File of the same +root+ will be used.
12
-
13
- class Directory
14
- DIR_FILE = "<tr><td class='name'><a href='%s'>%s</a></td><td class='size'>%s</td><td class='type'>%s</td><td class='mtime'>%s</td></tr>"
15
- DIR_PAGE = <<-PAGE
16
- <html><head>
17
- <title>%s</title>
18
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
19
- <style type='text/css'>
20
- table { width:100%%; }
21
- .name { text-align:left; }
22
- .size, .mtime { text-align:right; }
23
- .type { width:11em; }
24
- .mtime { width:15em; }
25
- </style>
26
- </head><body>
27
- <h1>%s</h1>
28
- <hr />
29
- <table>
30
- <tr>
31
- <th class='name'>Name</th>
32
- <th class='size'>Size</th>
33
- <th class='type'>Type</th>
34
- <th class='mtime'>Last Modified</th>
35
- </tr>
36
- %s
37
- </table>
38
- <hr />
39
- </body></html>
40
- PAGE
41
-
42
- attr_reader :files
43
- attr_accessor :root, :path
44
-
45
- def initialize(root, app=nil)
46
- @root = F.expand_path(root)
47
- @app = app || Rack::File.new(@root)
48
- end
49
-
50
- def call(env)
51
- dup._call(env)
52
- end
53
-
54
- F = ::File
55
-
56
- def _call(env)
57
- @env = env
58
- @script_name = env['SCRIPT_NAME']
59
- @path_info = Utils.unescape(env['PATH_INFO'])
60
-
61
- if forbidden = check_forbidden
62
- forbidden
63
- else
64
- @path = F.join(@root, @path_info)
65
- list_path
66
- end
67
- end
68
-
69
- def check_forbidden
70
- return unless @path_info.include? ".."
71
-
72
- body = "Forbidden\n"
73
- size = Rack::Utils.bytesize(body)
74
- return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]]
75
- end
76
-
77
- def list_directory
78
- @files = [['../','Parent Directory','','','']]
79
- glob = F.join(@path, '*')
80
-
81
- Dir[glob].sort.each do |node|
82
- stat = stat(node)
83
- next unless stat
84
- basename = F.basename(node)
85
- ext = F.extname(node)
86
-
87
- url = F.join(@script_name, @path_info, basename)
88
- size = stat.size
89
- type = stat.directory? ? 'directory' : Mime.mime_type(ext)
90
- size = stat.directory? ? '-' : filesize_format(size)
91
- mtime = stat.mtime.httpdate
92
- url << '/' if stat.directory?
93
- basename << '/' if stat.directory?
94
-
95
- @files << [ url, basename, size, type, mtime ]
96
- end
97
-
98
- return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ]
99
- end
100
-
101
- def stat(node, max = 10)
102
- F.stat(node)
103
- rescue Errno::ENOENT, Errno::ELOOP
104
- return nil
105
- end
106
-
107
- # TODO: add correct response if not readable, not sure if 404 is the best
108
- # option
109
- def list_path
110
- @stat = F.stat(@path)
111
-
112
- if @stat.readable?
113
- return @app.call(@env) if @stat.file?
114
- return list_directory if @stat.directory?
115
- else
116
- raise Errno::ENOENT, 'No such file or directory'
117
- end
118
-
119
- rescue Errno::ENOENT, Errno::ELOOP
120
- return entity_not_found
121
- end
122
-
123
- def entity_not_found
124
- body = "Entity not found: #{@path_info}\n"
125
- size = Rack::Utils.bytesize(body)
126
- return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]]
127
- end
128
-
129
- def each
130
- show_path = @path.sub(/^#{@root}/,'')
131
- files = @files.map{|f| DIR_FILE % f }*"\n"
132
- page = DIR_PAGE % [ show_path, show_path , files ]
133
- page.each_line{|l| yield l }
134
- end
135
-
136
- # Stolen from Ramaze
137
-
138
- FILESIZE_FORMAT = [
139
- ['%.1fT', 1 << 40],
140
- ['%.1fG', 1 << 30],
141
- ['%.1fM', 1 << 20],
142
- ['%.1fK', 1 << 10],
143
- ]
144
-
145
- def filesize_format(int)
146
- FILESIZE_FORMAT.each do |format, size|
147
- return format % (int.to_f / size) if int >= size
148
- end
149
-
150
- int.to_s + 'B'
151
- end
152
- end
153
- end