rack 1.6.13 → 2.0.0.alpha

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 (138) hide show
  1. checksums.yaml +5 -5
  2. data/HISTORY.md +139 -18
  3. data/README.rdoc +17 -25
  4. data/Rakefile +6 -14
  5. data/SPEC +8 -9
  6. data/contrib/rack_logo.svg +164 -111
  7. data/lib/rack.rb +70 -21
  8. data/lib/rack/auth/digest/request.rb +1 -1
  9. data/lib/rack/body_proxy.rb +14 -9
  10. data/lib/rack/builder.rb +3 -3
  11. data/lib/rack/chunked.rb +5 -5
  12. data/lib/rack/{commonlogger.rb → common_logger.rb} +2 -2
  13. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  14. data/lib/rack/content_length.rb +2 -2
  15. data/lib/rack/deflater.rb +4 -4
  16. data/lib/rack/directory.rb +49 -55
  17. data/lib/rack/etag.rb +2 -1
  18. data/lib/rack/events.rb +154 -0
  19. data/lib/rack/file.rb +55 -40
  20. data/lib/rack/handler.rb +2 -24
  21. data/lib/rack/handler/cgi.rb +15 -16
  22. data/lib/rack/handler/fastcgi.rb +13 -14
  23. data/lib/rack/handler/lsws.rb +11 -11
  24. data/lib/rack/handler/scgi.rb +15 -15
  25. data/lib/rack/handler/thin.rb +3 -0
  26. data/lib/rack/handler/webrick.rb +22 -24
  27. data/lib/rack/head.rb +15 -17
  28. data/lib/rack/lint.rb +38 -38
  29. data/lib/rack/lobster.rb +1 -1
  30. data/lib/rack/lock.rb +6 -10
  31. data/lib/rack/logger.rb +2 -2
  32. data/lib/rack/media_type.rb +38 -0
  33. data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
  34. data/lib/rack/mime.rb +18 -5
  35. data/lib/rack/mock.rb +35 -52
  36. data/lib/rack/multipart.rb +35 -6
  37. data/lib/rack/multipart/generator.rb +4 -4
  38. data/lib/rack/multipart/parser.rb +273 -158
  39. data/lib/rack/multipart/uploaded_file.rb +1 -2
  40. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  41. data/lib/rack/query_parser.rb +174 -0
  42. data/lib/rack/recursive.rb +8 -8
  43. data/lib/rack/reloader.rb +1 -2
  44. data/lib/rack/request.rb +370 -304
  45. data/lib/rack/response.rb +129 -56
  46. data/lib/rack/rewindable_input.rb +1 -12
  47. data/lib/rack/runtime.rb +10 -18
  48. data/lib/rack/sendfile.rb +5 -7
  49. data/lib/rack/server.rb +31 -25
  50. data/lib/rack/session/abstract/id.rb +93 -135
  51. data/lib/rack/session/cookie.rb +26 -28
  52. data/lib/rack/session/memcache.rb +8 -14
  53. data/lib/rack/session/pool.rb +14 -21
  54. data/lib/rack/show_exceptions.rb +386 -0
  55. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  56. data/lib/rack/static.rb +30 -5
  57. data/lib/rack/tempfile_reaper.rb +2 -2
  58. data/lib/rack/urlmap.rb +13 -14
  59. data/lib/rack/utils.rb +128 -221
  60. data/rack.gemspec +9 -5
  61. data/test/builder/an_underscore_app.rb +5 -0
  62. data/test/builder/options.ru +1 -1
  63. data/test/cgi/test.fcgi +1 -0
  64. data/test/cgi/test.gz +0 -0
  65. data/test/helper.rb +31 -0
  66. data/test/multipart/filename_with_encoded_words +7 -0
  67. data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
  68. data/test/multipart/quoted +15 -0
  69. data/test/multipart/rack-logo.png +0 -0
  70. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  71. data/test/spec_auth_basic.rb +20 -19
  72. data/test/spec_auth_digest.rb +47 -46
  73. data/test/spec_body_proxy.rb +27 -27
  74. data/test/spec_builder.rb +51 -41
  75. data/test/spec_cascade.rb +24 -22
  76. data/test/spec_cgi.rb +49 -67
  77. data/test/spec_chunked.rb +36 -34
  78. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  79. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  80. data/test/spec_config.rb +3 -2
  81. data/test/spec_content_length.rb +18 -17
  82. data/test/spec_content_type.rb +13 -12
  83. data/test/spec_deflater.rb +66 -40
  84. data/test/spec_directory.rb +72 -27
  85. data/test/spec_etag.rb +32 -31
  86. data/test/spec_events.rb +133 -0
  87. data/test/spec_fastcgi.rb +50 -72
  88. data/test/spec_file.rb +96 -77
  89. data/test/spec_handler.rb +19 -34
  90. data/test/spec_head.rb +15 -14
  91. data/test/spec_lint.rb +162 -197
  92. data/test/spec_lobster.rb +24 -23
  93. data/test/spec_lock.rb +69 -39
  94. data/test/spec_logger.rb +4 -3
  95. data/test/spec_media_type.rb +42 -0
  96. data/test/spec_method_override.rb +83 -0
  97. data/test/spec_mime.rb +19 -19
  98. data/test/spec_mock.rb +196 -151
  99. data/test/spec_multipart.rb +310 -202
  100. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  101. data/test/spec_recursive.rb +17 -14
  102. data/test/spec_request.rb +763 -607
  103. data/test/spec_response.rb +209 -156
  104. data/test/spec_rewindable_input.rb +50 -40
  105. data/test/spec_runtime.rb +11 -10
  106. data/test/spec_sendfile.rb +30 -35
  107. data/test/spec_server.rb +78 -52
  108. data/test/spec_session_abstract_id.rb +11 -33
  109. data/test/spec_session_cookie.rb +97 -65
  110. data/test/spec_session_memcache.rb +63 -101
  111. data/test/spec_session_pool.rb +48 -84
  112. data/test/spec_show_exceptions.rb +80 -0
  113. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  114. data/test/spec_static.rb +71 -32
  115. data/test/spec_tempfile_reaper.rb +11 -10
  116. data/test/spec_thin.rb +55 -50
  117. data/test/spec_urlmap.rb +79 -78
  118. data/test/spec_utils.rb +417 -345
  119. data/test/spec_version.rb +2 -8
  120. data/test/spec_webrick.rb +77 -67
  121. data/test/static/foo.html +1 -0
  122. data/test/testrequest.rb +1 -1
  123. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  124. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  125. metadata +116 -71
  126. data/KNOWN-ISSUES +0 -44
  127. data/lib/rack/backports/uri/common_18.rb +0 -56
  128. data/lib/rack/backports/uri/common_192.rb +0 -52
  129. data/lib/rack/backports/uri/common_193.rb +0 -29
  130. data/lib/rack/handler/evented_mongrel.rb +0 -8
  131. data/lib/rack/handler/mongrel.rb +0 -106
  132. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  133. data/lib/rack/showexceptions.rb +0 -387
  134. data/lib/rack/utils/okjson.rb +0 -600
  135. data/test/spec_methodoverride.rb +0 -111
  136. data/test/spec_mongrel.rb +0 -182
  137. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  138. data/test/spec_showexceptions.rb +0 -98
@@ -7,7 +7,7 @@
7
7
  # modules and classes.
8
8
  #
9
9
  # All modules meant for use in your application are <tt>autoload</tt>ed here,
10
- # so it should be enough just to <tt>require rack.rb</tt> in your code.
10
+ # so it should be enough just to <tt>require 'rack'</tt> in your code.
11
11
 
12
12
  module Rack
13
13
  # The Rack protocol version number implemented.
@@ -18,27 +18,80 @@ module Rack
18
18
  VERSION.join(".")
19
19
  end
20
20
 
21
+ RELEASE = "2.0.0.alpha"
22
+
21
23
  # Return the Rack release as a dotted string.
22
24
  def self.release
23
- "1.6.13"
25
+ RELEASE
24
26
  end
25
- PATH_INFO = 'PATH_INFO'.freeze
26
- REQUEST_METHOD = 'REQUEST_METHOD'.freeze
27
- SCRIPT_NAME = 'SCRIPT_NAME'.freeze
28
- QUERY_STRING = 'QUERY_STRING'.freeze
29
- CACHE_CONTROL = 'Cache-Control'.freeze
30
- CONTENT_LENGTH = 'Content-Length'.freeze
31
- CONTENT_TYPE = 'Content-Type'.freeze
32
27
 
33
- GET = 'GET'.freeze
34
- HEAD = 'HEAD'.freeze
28
+ HTTP_HOST = 'HTTP_HOST'.freeze
29
+ HTTP_VERSION = 'HTTP_VERSION'.freeze
30
+ HTTPS = 'HTTPS'.freeze
31
+ PATH_INFO = 'PATH_INFO'.freeze
32
+ REQUEST_METHOD = 'REQUEST_METHOD'.freeze
33
+ REQUEST_PATH = 'REQUEST_PATH'.freeze
34
+ SCRIPT_NAME = 'SCRIPT_NAME'.freeze
35
+ QUERY_STRING = 'QUERY_STRING'.freeze
36
+ SERVER_PROTOCOL = 'SERVER_PROTOCOL'.freeze
37
+ SERVER_NAME = 'SERVER_NAME'.freeze
38
+ SERVER_ADDR = 'SERVER_ADDR'.freeze
39
+ SERVER_PORT = 'SERVER_PORT'.freeze
40
+ CACHE_CONTROL = 'Cache-Control'.freeze
41
+ CONTENT_LENGTH = 'Content-Length'.freeze
42
+ CONTENT_TYPE = 'Content-Type'.freeze
43
+ SET_COOKIE = 'Set-Cookie'.freeze
44
+ TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
45
+ HTTP_COOKIE = 'HTTP_COOKIE'.freeze
46
+ ETAG = 'ETag'.freeze
47
+
48
+ # HTTP method verbs
49
+ GET = 'GET'.freeze
50
+ POST = 'POST'.freeze
51
+ PUT = 'PUT'.freeze
52
+ PATCH = 'PATCH'.freeze
53
+ DELETE = 'DELETE'.freeze
54
+ HEAD = 'HEAD'.freeze
55
+ OPTIONS = 'OPTIONS'.freeze
56
+ LINK = 'LINK'.freeze
57
+ UNLINK = 'UNLINK'.freeze
58
+ TRACE = 'TRACE'.freeze
59
+
60
+ # Rack environment variables
61
+ RACK_VERSION = 'rack.version'.freeze
62
+ RACK_TEMPFILES = 'rack.tempfiles'.freeze
63
+ RACK_ERRORS = 'rack.errors'.freeze
64
+ RACK_LOGGER = 'rack.logger'.freeze
65
+ RACK_INPUT = 'rack.input'.freeze
66
+ RACK_SESSION = 'rack.session'.freeze
67
+ RACK_SESSION_OPTIONS = 'rack.session.options'.freeze
68
+ RACK_SHOWSTATUS_DETAIL = 'rack.showstatus.detail'.freeze
69
+ RACK_MULTITHREAD = 'rack.multithread'.freeze
70
+ RACK_MULTIPROCESS = 'rack.multiprocess'.freeze
71
+ RACK_RUNONCE = 'rack.run_once'.freeze
72
+ RACK_URL_SCHEME = 'rack.url_scheme'.freeze
73
+ RACK_HIJACK = 'rack.hijack'.freeze
74
+ RACK_IS_HIJACK = 'rack.hijack?'.freeze
75
+ RACK_HIJACK_IO = 'rack.hijack_io'.freeze
76
+ RACK_RECURSIVE_INCLUDE = 'rack.recursive.include'.freeze
77
+ RACK_MULTIPART_BUFFER_SIZE = 'rack.multipart.buffer_size'.freeze
78
+ RACK_MULTIPART_TEMPFILE_FACTORY = 'rack.multipart.tempfile_factory'.freeze
79
+ RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'.freeze
80
+ RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'.freeze
81
+ RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'.freeze
82
+ RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'.freeze
83
+ RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'.freeze
84
+ RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'.freeze
85
+ RACK_REQUEST_QUERY_STRING = 'rack.request.query_string'.freeze
86
+ RACK_METHODOVERRIDE_ORIGINAL_METHOD = 'rack.methodoverride.original_method'.freeze
87
+ RACK_SESSION_UNPACKED_COOKIE_DATA = 'rack.session.unpacked_cookie_data'.freeze
35
88
 
36
89
  autoload :Builder, "rack/builder"
37
90
  autoload :BodyProxy, "rack/body_proxy"
38
91
  autoload :Cascade, "rack/cascade"
39
92
  autoload :Chunked, "rack/chunked"
40
- autoload :CommonLogger, "rack/commonlogger"
41
- autoload :ConditionalGet, "rack/conditionalget"
93
+ autoload :CommonLogger, "rack/common_logger"
94
+ autoload :ConditionalGet, "rack/conditional_get"
42
95
  autoload :Config, "rack/config"
43
96
  autoload :ContentLength, "rack/content_length"
44
97
  autoload :ContentType, "rack/content_type"
@@ -52,16 +105,16 @@ module Rack
52
105
  autoload :Lint, "rack/lint"
53
106
  autoload :Lock, "rack/lock"
54
107
  autoload :Logger, "rack/logger"
55
- autoload :MethodOverride, "rack/methodoverride"
108
+ autoload :MethodOverride, "rack/method_override"
56
109
  autoload :Mime, "rack/mime"
57
- autoload :NullLogger, "rack/nulllogger"
110
+ autoload :NullLogger, "rack/null_logger"
58
111
  autoload :Recursive, "rack/recursive"
59
112
  autoload :Reloader, "rack/reloader"
60
113
  autoload :Runtime, "rack/runtime"
61
114
  autoload :Sendfile, "rack/sendfile"
62
115
  autoload :Server, "rack/server"
63
- autoload :ShowExceptions, "rack/showexceptions"
64
- autoload :ShowStatus, "rack/showstatus"
116
+ autoload :ShowExceptions, "rack/show_exceptions"
117
+ autoload :ShowStatus, "rack/show_status"
65
118
  autoload :Static, "rack/static"
66
119
  autoload :TempfileReaper, "rack/tempfile_reaper"
67
120
  autoload :URLMap, "rack/urlmap"
@@ -91,8 +144,4 @@ module Rack
91
144
  autoload :Pool, "rack/session/pool"
92
145
  autoload :Memcache, "rack/session/memcache"
93
146
  end
94
-
95
- module Utils
96
- autoload :OkJson, "rack/utils/okjson"
97
- end
98
147
  end
@@ -7,7 +7,7 @@ module Rack
7
7
  module Digest
8
8
  class Request < Auth::AbstractRequest
9
9
  def method
10
- @env['rack.methodoverride.original_method'] || @env[REQUEST_METHOD]
10
+ @env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] || @env[REQUEST_METHOD]
11
11
  end
12
12
 
13
13
  def digest?
@@ -1,12 +1,17 @@
1
1
  module Rack
2
2
  class BodyProxy
3
3
  def initialize(body, &block)
4
- @body, @block, @closed = body, block, false
4
+ @body = body
5
+ @block = block
6
+ @closed = false
5
7
  end
6
8
 
7
- def respond_to?(*args)
8
- return false if args.first.to_s =~ /^to_ary$/
9
- super or @body.respond_to?(*args)
9
+ def respond_to?(method_name, include_all=false)
10
+ case method_name
11
+ when :to_ary, 'to_ary'
12
+ return false
13
+ end
14
+ super or @body.respond_to?(method_name, include_all)
10
15
  end
11
16
 
12
17
  def close
@@ -27,13 +32,13 @@ module Rack
27
32
  # We are applying this special case for #each only. Future bugs of this
28
33
  # class will be handled by requesting users to patch their ruby
29
34
  # implementation, to save adding too many methods in this class.
30
- def each(*args, &block)
31
- @body.each(*args, &block)
35
+ def each
36
+ @body.each { |body| yield body }
32
37
  end
33
38
 
34
- def method_missing(*args, &block)
35
- super if args.first.to_s =~ /^to_ary$/
36
- @body.__send__(*args, &block)
39
+ def method_missing(method_name, *args, &block)
40
+ super if :to_ary == method_name
41
+ @body.__send__(method_name, *args, &block)
37
42
  end
38
43
  end
39
44
  end
@@ -40,7 +40,7 @@ module Rack
40
40
  app = new_from_string cfgfile, config
41
41
  else
42
42
  require config
43
- app = Object.const_get(::File.basename(config, '.rb').capitalize)
43
+ app = Object.const_get(::File.basename(config, '.rb').split('_').map(&:capitalize).join(''))
44
44
  end
45
45
  return app, options
46
46
  end
@@ -50,7 +50,7 @@ module Rack
50
50
  TOPLEVEL_BINDING, file, 0
51
51
  end
52
52
 
53
- def initialize(default_app = nil,&block)
53
+ def initialize(default_app = nil, &block)
54
54
  @use, @map, @run, @warmup = [], nil, default_app, nil
55
55
  instance_eval(&block) if block_given?
56
56
  end
@@ -96,7 +96,7 @@ module Rack
96
96
  # class Heartbeat
97
97
  # def self.call(env)
98
98
  # [200, { "Content-Type" => "text/plain" }, ["OK"]]
99
- # end
99
+ # end
100
100
  # end
101
101
  #
102
102
  # run Heartbeat
@@ -21,10 +21,10 @@ module Rack
21
21
  def each
22
22
  term = TERM
23
23
  @body.each do |chunk|
24
- size = bytesize(chunk)
24
+ size = chunk.bytesize
25
25
  next if size == 0
26
26
 
27
- chunk = chunk.dup.force_encoding(Encoding::BINARY) if chunk.respond_to?(:force_encoding)
27
+ chunk = chunk.dup.force_encoding(Encoding::BINARY)
28
28
  yield [size.to_s(16), term, chunk, term].join
29
29
  end
30
30
  yield TAIL
@@ -54,14 +54,14 @@ module Rack
54
54
  status, headers, body = @app.call(env)
55
55
  headers = HeaderHash.new(headers)
56
56
 
57
- if ! chunkable_version?(env['HTTP_VERSION']) ||
57
+ if ! chunkable_version?(env[HTTP_VERSION]) ||
58
58
  STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
59
59
  headers[CONTENT_LENGTH] ||
60
- headers['Transfer-Encoding']
60
+ headers[TRANSFER_ENCODING]
61
61
  [status, headers, body]
62
62
  else
63
63
  headers.delete(CONTENT_LENGTH)
64
- headers['Transfer-Encoding'] = 'chunked'
64
+ headers[TRANSFER_ENCODING] = 'chunked'
65
65
  [status, headers, Body.new(body)]
66
66
  end
67
67
  end
@@ -49,12 +49,12 @@ module Rack
49
49
  env[REQUEST_METHOD],
50
50
  env[PATH_INFO],
51
51
  env[QUERY_STRING].empty? ? "" : "?"+env[QUERY_STRING],
52
- env["HTTP_VERSION"],
52
+ env[HTTP_VERSION],
53
53
  status.to_s[0..3],
54
54
  length,
55
55
  now - began_at ]
56
56
 
57
- logger = @logger || env['rack.errors']
57
+ logger = @logger || env[RACK_ERRORS]
58
58
  # Standard library logger doesn't support write but it supports << which actually
59
59
  # calls to write on the log device without formatting
60
60
  if logger.respond_to?(:write)
@@ -17,12 +17,12 @@ module Rack
17
17
 
18
18
  if !STATUS_WITH_NO_ENTITY_BODY.include?(status.to_i) &&
19
19
  !headers[CONTENT_LENGTH] &&
20
- !headers['Transfer-Encoding'] &&
20
+ !headers[TRANSFER_ENCODING] &&
21
21
  body.respond_to?(:to_ary)
22
22
 
23
23
  obody = body
24
24
  body, length = [], 0
25
- obody.each { |part| body << part; length += bytesize(part) }
25
+ obody.each { |part| body << part; length += part.bytesize }
26
26
 
27
27
  body = BodyProxy.new(body) do
28
28
  obody.close if obody.respond_to?(:close)
@@ -45,7 +45,7 @@ module Rack
45
45
  request.accept_encoding)
46
46
 
47
47
  # Set the Vary HTTP header.
48
- vary = headers["Vary"].to_s.split(",").map { |v| v.strip }
48
+ vary = headers["Vary"].to_s.split(",").map(&:strip)
49
49
  unless vary.include?("*") || vary.include?("Accept-Encoding")
50
50
  headers["Vary"] = vary.push("Accept-Encoding").join(",")
51
51
  end
@@ -118,9 +118,9 @@ module Rack
118
118
  def each
119
119
  deflator = ::Zlib::Deflate.new(*DEFLATE_ARGS)
120
120
  @body.each { |part| yield deflator.deflate(part, Zlib::SYNC_FLUSH) }
121
- yield deflator.finish
122
- nil
121
+ yield fin = deflator.finish
123
122
  ensure
123
+ deflator.finish unless fin
124
124
  deflator.close
125
125
  end
126
126
 
@@ -143,7 +143,7 @@ module Rack
143
143
  end
144
144
 
145
145
  # Skip if @compressible_types are given and does not include request's content type
146
- return false if @compressible_types && !(headers.has_key?('Content-Type') && @compressible_types.include?(headers['Content-Type'][/[^;]*/]))
146
+ return false if @compressible_types && !(headers.has_key?(CONTENT_TYPE) && @compressible_types.include?(headers[CONTENT_TYPE][/[^;]*/]))
147
147
 
148
148
  # Skip if @condition lambda is given and evaluates to false
149
149
  return false if @condition && !@condition.call(env, status, headers, body)
@@ -39,58 +39,65 @@ table { width:100%%; }
39
39
  </body></html>
40
40
  PAGE
41
41
 
42
- attr_reader :files
43
- attr_accessor :root, :path
42
+ class DirectoryBody < Struct.new(:root, :path, :files)
43
+ def each
44
+ show_path = Rack::Utils.escape_html(path.sub(/^#{root}/,''))
45
+ listings = files.map{|f| DIR_FILE % DIR_FILE_escape(*f) }*"\n"
46
+ page = DIR_PAGE % [ show_path, show_path , listings ]
47
+ page.each_line{|l| yield l }
48
+ end
49
+
50
+ private
51
+ # Assumes url is already escaped.
52
+ def DIR_FILE_escape url, *html
53
+ [url, *html.map { |e| Utils.escape_html(e) }]
54
+ end
55
+ end
56
+
57
+ attr_reader :root, :path
44
58
 
45
59
  def initialize(root, app=nil)
46
- @root = F.expand_path(root)
60
+ @root = ::File.expand_path(root)
47
61
  @app = app || Rack::File.new(@root)
48
62
  end
49
63
 
50
64
  def call(env)
51
- dup._call(env)
52
- end
65
+ script_name = env[SCRIPT_NAME]
66
+ path_info = Utils.unescape_path(env[PATH_INFO])
53
67
 
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
68
+ if forbidden = check_forbidden(path_info)
62
69
  forbidden
63
70
  else
64
- @path = F.join(@root, @path_info)
65
- list_path
71
+ path = ::File.join(@root, path_info)
72
+ list_path(env, path, path_info, script_name)
66
73
  end
67
74
  end
68
75
 
69
- def check_forbidden
70
- return unless @path_info.include? ".."
76
+ def check_forbidden(path_info)
77
+ return unless path_info.include? ".."
71
78
 
72
79
  body = "Forbidden\n"
73
- size = Rack::Utils.bytesize(body)
74
- return [403, {"Content-Type" => "text/plain",
80
+ size = body.bytesize
81
+ return [403, {CONTENT_TYPE => "text/plain",
75
82
  CONTENT_LENGTH => size.to_s,
76
83
  "X-Cascade" => "pass"}, [body]]
77
84
  end
78
85
 
79
- def list_directory
80
- @files = [['../','Parent Directory','','','']]
81
- glob = F.join(@path, '*')
86
+ def list_directory(path_info, path, script_name)
87
+ files = [['../','Parent Directory','','','']]
88
+ glob = ::File.join(path, '*')
82
89
 
83
- url_head = (@script_name.split('/') + @path_info.split('/')).map do |part|
84
- Rack::Utils.escape part
90
+ url_head = (script_name.split('/') + path_info.split('/')).map do |part|
91
+ Rack::Utils.escape_path part
85
92
  end
86
93
 
87
94
  Dir[glob].sort.each do |node|
88
95
  stat = stat(node)
89
- next unless stat
90
- basename = F.basename(node)
91
- ext = F.extname(node)
96
+ next unless stat
97
+ basename = ::File.basename(node)
98
+ ext = ::File.extname(node)
92
99
 
93
- url = F.join(*url_head + [Rack::Utils.escape(basename)])
100
+ url = ::File.join(*url_head + [Rack::Utils.escape_path(basename)])
94
101
  size = stat.size
95
102
  type = stat.directory? ? 'directory' : Mime.mime_type(ext)
96
103
  size = stat.directory? ? '-' : filesize_format(size)
@@ -98,49 +105,42 @@ table { width:100%%; }
98
105
  url << '/' if stat.directory?
99
106
  basename << '/' if stat.directory?
100
107
 
101
- @files << [ url, basename, size, type, mtime ]
108
+ files << [ url, basename, size, type, mtime ]
102
109
  end
103
110
 
104
- return [ 200, { CONTENT_TYPE =>'text/html; charset=utf-8'}, self ]
111
+ return [ 200, { CONTENT_TYPE =>'text/html; charset=utf-8'}, DirectoryBody.new(@root, path, files) ]
105
112
  end
106
113
 
107
- def stat(node, max = 10)
108
- F.stat(node)
114
+ def stat(node)
115
+ ::File.stat(node)
109
116
  rescue Errno::ENOENT, Errno::ELOOP
110
117
  return nil
111
118
  end
112
119
 
113
120
  # TODO: add correct response if not readable, not sure if 404 is the best
114
121
  # option
115
- def list_path
116
- @stat = F.stat(@path)
122
+ def list_path(env, path, path_info, script_name)
123
+ stat = ::File.stat(path)
117
124
 
118
- if @stat.readable?
119
- return @app.call(@env) if @stat.file?
120
- return list_directory if @stat.directory?
125
+ if stat.readable?
126
+ return @app.call(env) if stat.file?
127
+ return list_directory(path_info, path, script_name) if stat.directory?
121
128
  else
122
129
  raise Errno::ENOENT, 'No such file or directory'
123
130
  end
124
131
 
125
132
  rescue Errno::ENOENT, Errno::ELOOP
126
- return entity_not_found
133
+ return entity_not_found(path_info)
127
134
  end
128
135
 
129
- def entity_not_found
130
- body = "Entity not found: #{@path_info}\n"
131
- size = Rack::Utils.bytesize(body)
132
- return [404, {"Content-Type" => "text/plain",
136
+ def entity_not_found(path_info)
137
+ body = "Entity not found: #{path_info}\n"
138
+ size = body.bytesize
139
+ return [404, {CONTENT_TYPE => "text/plain",
133
140
  CONTENT_LENGTH => size.to_s,
134
141
  "X-Cascade" => "pass"}, [body]]
135
142
  end
136
143
 
137
- def each
138
- show_path = Rack::Utils.escape_html(@path.sub(/^#{@root}/,''))
139
- files = @files.map{|f| DIR_FILE % DIR_FILE_escape(*f) }*"\n"
140
- page = DIR_PAGE % [ show_path, show_path , files ]
141
- page.each_line{|l| yield l }
142
- end
143
-
144
144
  # Stolen from Ramaze
145
145
 
146
146
  FILESIZE_FORMAT = [
@@ -157,11 +157,5 @@ table { width:100%%; }
157
157
 
158
158
  int.to_s + 'B'
159
159
  end
160
-
161
- private
162
- # Assumes url is already escaped.
163
- def DIR_FILE_escape url, *html
164
- [url, *html.map { |e| Utils.escape_html(e) }]
165
- end
166
160
  end
167
161
  end