Permalink
Browse files

Extract clean_path_info method from Rack::File#_call

  • Loading branch information...
1 parent 13adbd0 commit 9a74ba3b04f2dabe4741d2d82eae723d440c3aa2 @KitaitiMakoto KitaitiMakoto committed Jan 5, 2014
Showing with 35 additions and 10 deletions.
  1. +2 −10 lib/rack/file.rb
  2. +18 −0 lib/rack/utils.rb
  3. +15 −0 test/spec_utils.rb
View
@@ -12,7 +12,6 @@ module Rack
# like sendfile on the +path+.
class File
- SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
ALLOWED_VERBS = %w[GET HEAD OPTIONS]
ALLOW_HEADER = ALLOWED_VERBS.join(', ')
@@ -40,16 +39,9 @@ def _call(env)
end
path_info = Utils.unescape(env["PATH_INFO"])
- parts = path_info.split SEPS
+ clean_path_info = Utils.clean_path_info(path_info)
- clean = []
-
- parts.each do |part|
- next if part.empty? || part == '.'
- part == '..' ? clean.pop : clean << part
- end
-
- @path = F.join(@root, *clean)
+ @path = F.join(@root, clean_path_info)
available = begin
F.file?(@path) && F.readable?(@path)
View
@@ -625,5 +625,23 @@ def status_code(status)
Multipart = Rack::Multipart
+ PATH_SEPS = Regexp.union(*[::File::SEPARATOR, ::File::ALT_SEPARATOR].compact)
+
+ def clean_path_info(path_info)
+ parts = path_info.split PATH_SEPS
+
+ clean = []
+
+ parts.each do |part|
+ next if part.empty? || part == '.'
+ part == '..' ? clean.pop : clean << part
+ end
+
+ clean.unshift '/' if parts.first.empty?
+
+ ::File.join(*clean)
+ end
+ module_function :clean_path_info
+
end
end
View
@@ -388,6 +388,21 @@ def kcodeu
should "return rfc2109 format from rfc2109 helper" do
Rack::Utils.rfc2109(Time.at(0).gmtime).should == "Thu, 01-Jan-1970 00:00:00 GMT"
end
+
+ should "clean directory traversal" do
+ Rack::Utils.clean_path_info("/cgi/../cgi/test").should.equal "/cgi/test"
+ Rack::Utils.clean_path_info(".").should.empty
+ Rack::Utils.clean_path_info("test/..").should.empty
+ end
+
+ should "clean unsafe directory traversal to safe path" do
+ Rack::Utils.clean_path_info("/../README.rdoc").should.equal "/README.rdoc"
+ Rack::Utils.clean_path_info("../test/spec_utils.rb").should.equal "test/spec_utils.rb"
+ end
+
+ should "not clean directory traversal with encoded periods" do
+ Rack::Utils.clean_path_info("/%2E%2E/README").should.equal "/%2E%2E/README"
+ end
end
describe Rack::Utils, "byte_range" do

0 comments on commit 9a74ba3

Please sign in to comment.