PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/test/webrick/test_filehandler.rb

https://gitlab.com/0072016/0072016-ruby
Ruby | 324 lines | 287 code | 36 blank | 1 comment | 10 complexity | 7214e20238787999d0cf834fa0c84d29 MD5 | raw file
  1. # frozen_string_literal: false
  2. require "test/unit"
  3. require_relative "utils.rb"
  4. require "webrick"
  5. require "stringio"
  6. class WEBrick::TestFileHandler < Test::Unit::TestCase
  7. def teardown
  8. WEBrick::Utils::TimeoutHandler.terminate
  9. super
  10. end
  11. def default_file_handler(filename)
  12. klass = WEBrick::HTTPServlet::DefaultFileHandler
  13. klass.new(WEBrick::Config::HTTP, filename)
  14. end
  15. def windows?
  16. File.directory?("\\")
  17. end
  18. def get_res_body(res)
  19. body = res.body
  20. if defined? body.read
  21. begin
  22. body.read
  23. ensure
  24. body.close
  25. end
  26. else
  27. body
  28. end
  29. end
  30. def make_range_request(range_spec)
  31. msg = <<-END_OF_REQUEST
  32. GET / HTTP/1.0
  33. Range: #{range_spec}
  34. END_OF_REQUEST
  35. return StringIO.new(msg.gsub(/^ {6}/, ""))
  36. end
  37. def make_range_response(file, range_spec)
  38. req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
  39. req.parse(make_range_request(range_spec))
  40. res = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
  41. size = File.size(file)
  42. handler = default_file_handler(file)
  43. handler.make_partial_content(req, res, file, size)
  44. return res
  45. end
  46. def test_make_partial_content
  47. filename = __FILE__
  48. filesize = File.size(filename)
  49. res = make_range_response(filename, "bytes=#{filesize-100}-")
  50. assert_match(%r{^text/plain}, res["content-type"])
  51. assert_equal(100, get_res_body(res).size)
  52. res = make_range_response(filename, "bytes=-100")
  53. assert_match(%r{^text/plain}, res["content-type"])
  54. assert_equal(100, get_res_body(res).size)
  55. res = make_range_response(filename, "bytes=0-99")
  56. assert_match(%r{^text/plain}, res["content-type"])
  57. assert_equal(100, get_res_body(res).size)
  58. res = make_range_response(filename, "bytes=100-199")
  59. assert_match(%r{^text/plain}, res["content-type"])
  60. assert_equal(100, get_res_body(res).size)
  61. res = make_range_response(filename, "bytes=0-0")
  62. assert_match(%r{^text/plain}, res["content-type"])
  63. assert_equal(1, get_res_body(res).size)
  64. res = make_range_response(filename, "bytes=-1")
  65. assert_match(%r{^text/plain}, res["content-type"])
  66. assert_equal(1, get_res_body(res).size)
  67. res = make_range_response(filename, "bytes=0-0, -2")
  68. assert_match(%r{^multipart/byteranges}, res["content-type"])
  69. end
  70. def test_filehandler
  71. config = { :DocumentRoot => File.dirname(__FILE__), }
  72. this_file = File.basename(__FILE__)
  73. filesize = File.size(__FILE__)
  74. this_data = File.open(__FILE__, "rb") {|f| f.read}
  75. range = nil
  76. bug2593 = '[ruby-dev:40030]'
  77. TestWEBrick.start_httpserver(config) do |server, addr, port, log|
  78. http = Net::HTTP.new(addr, port)
  79. req = Net::HTTP::Get.new("/")
  80. http.request(req){|res|
  81. assert_equal("200", res.code, log.call)
  82. assert_equal("text/html", res.content_type, log.call)
  83. assert_match(/HREF="#{this_file}"/, res.body, log.call)
  84. }
  85. req = Net::HTTP::Get.new("/#{this_file}")
  86. http.request(req){|res|
  87. assert_equal("200", res.code, log.call)
  88. assert_equal("text/plain", res.content_type, log.call)
  89. assert_equal(File.read(__FILE__), res.body, log.call)
  90. }
  91. req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=#{filesize-100}-")
  92. http.request(req){|res|
  93. assert_equal("206", res.code, log.call)
  94. assert_equal("text/plain", res.content_type, log.call)
  95. assert_nothing_raised(bug2593) {range = res.content_range}
  96. assert_equal((filesize-100)..(filesize-1), range, log.call)
  97. assert_equal(this_data[-100..-1], res.body, log.call)
  98. }
  99. req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-100")
  100. http.request(req){|res|
  101. assert_equal("206", res.code, log.call)
  102. assert_equal("text/plain", res.content_type, log.call)
  103. assert_nothing_raised(bug2593) {range = res.content_range}
  104. assert_equal((filesize-100)..(filesize-1), range, log.call)
  105. assert_equal(this_data[-100..-1], res.body, log.call)
  106. }
  107. req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-99")
  108. http.request(req){|res|
  109. assert_equal("206", res.code, log.call)
  110. assert_equal("text/plain", res.content_type, log.call)
  111. assert_nothing_raised(bug2593) {range = res.content_range}
  112. assert_equal(0..99, range, log.call)
  113. assert_equal(this_data[0..99], res.body, log.call)
  114. }
  115. req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=100-199")
  116. http.request(req){|res|
  117. assert_equal("206", res.code, log.call)
  118. assert_equal("text/plain", res.content_type, log.call)
  119. assert_nothing_raised(bug2593) {range = res.content_range}
  120. assert_equal(100..199, range, log.call)
  121. assert_equal(this_data[100..199], res.body, log.call)
  122. }
  123. req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0")
  124. http.request(req){|res|
  125. assert_equal("206", res.code, log.call)
  126. assert_equal("text/plain", res.content_type, log.call)
  127. assert_nothing_raised(bug2593) {range = res.content_range}
  128. assert_equal(0..0, range, log.call)
  129. assert_equal(this_data[0..0], res.body, log.call)
  130. }
  131. req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=-1")
  132. http.request(req){|res|
  133. assert_equal("206", res.code, log.call)
  134. assert_equal("text/plain", res.content_type, log.call)
  135. assert_nothing_raised(bug2593) {range = res.content_range}
  136. assert_equal((filesize-1)..(filesize-1), range, log.call)
  137. assert_equal(this_data[-1, 1], res.body, log.call)
  138. }
  139. req = Net::HTTP::Get.new("/#{this_file}", "range"=>"bytes=0-0, -2")
  140. http.request(req){|res|
  141. assert_equal("206", res.code, log.call)
  142. assert_equal("multipart/byteranges", res.content_type, log.call)
  143. }
  144. end
  145. end
  146. def test_non_disclosure_name
  147. config = { :DocumentRoot => File.dirname(__FILE__), }
  148. log_tester = lambda {|log, access_log|
  149. log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
  150. log = log.reject {|s| /WARN the request refers nondisclosure name/ =~ s }
  151. assert_equal([], log)
  152. }
  153. this_file = File.basename(__FILE__)
  154. TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
  155. http = Net::HTTP.new(addr, port)
  156. doc_root_opts = server[:DocumentRootOptions]
  157. doc_root_opts[:NondisclosureName] = %w(.ht* *~ test_*)
  158. req = Net::HTTP::Get.new("/")
  159. http.request(req){|res|
  160. assert_equal("200", res.code, log.call)
  161. assert_equal("text/html", res.content_type, log.call)
  162. assert_no_match(/HREF="#{File.basename(__FILE__)}"/, res.body)
  163. }
  164. req = Net::HTTP::Get.new("/#{this_file}")
  165. http.request(req){|res|
  166. assert_equal("404", res.code, log.call)
  167. }
  168. doc_root_opts[:NondisclosureName] = %w(.ht* *~ TEST_*)
  169. http.request(req){|res|
  170. assert_equal("404", res.code, log.call)
  171. }
  172. end
  173. end
  174. def test_directory_traversal
  175. return if File.executable?(__FILE__) # skip on strange file system
  176. config = { :DocumentRoot => File.dirname(__FILE__), }
  177. log_tester = lambda {|log, access_log|
  178. log = log.reject {|s| /ERROR bad URI/ =~ s }
  179. log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
  180. assert_equal([], log)
  181. }
  182. TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
  183. http = Net::HTTP.new(addr, port)
  184. req = Net::HTTP::Get.new("/../../")
  185. http.request(req){|res| assert_equal("400", res.code, log.call) }
  186. req = Net::HTTP::Get.new("/..%5c../#{File.basename(__FILE__)}")
  187. http.request(req){|res| assert_equal(windows? ? "200" : "404", res.code, log.call) }
  188. req = Net::HTTP::Get.new("/..%5c..%5cruby.c")
  189. http.request(req){|res| assert_equal("404", res.code, log.call) }
  190. end
  191. end
  192. def test_unwise_in_path
  193. if windows?
  194. config = { :DocumentRoot => File.dirname(__FILE__), }
  195. TestWEBrick.start_httpserver(config) do |server, addr, port, log|
  196. http = Net::HTTP.new(addr, port)
  197. req = Net::HTTP::Get.new("/..%5c..")
  198. http.request(req){|res| assert_equal("301", res.code, log.call) }
  199. end
  200. end
  201. end
  202. def test_short_filename
  203. return if File.executable?(__FILE__) # skip on strange file system
  204. config = {
  205. :CGIInterpreter => TestWEBrick::RubyBin,
  206. :DocumentRoot => File.dirname(__FILE__),
  207. :CGIPathEnv => ENV['PATH'],
  208. }
  209. log_tester = lambda {|log, access_log|
  210. log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
  211. log = log.reject {|s| /WARN the request refers nondisclosure name/ =~ s }
  212. assert_equal([], log)
  213. }
  214. TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
  215. http = Net::HTTP.new(addr, port)
  216. if windows?
  217. root = config[:DocumentRoot].tr("/", "\\")
  218. fname = IO.popen(%W[dir /x #{root}\\webrick_long_filename.cgi], &:read)
  219. fname.sub!(/\A.*$^$.*$^$/m, '')
  220. if fname
  221. fname = fname[/\s(w.+?cgi)\s/i, 1]
  222. fname.downcase!
  223. end
  224. else
  225. fname = "webric~1.cgi"
  226. end
  227. req = Net::HTTP::Get.new("/#{fname}/test")
  228. http.request(req) do |res|
  229. if windows?
  230. assert_equal("200", res.code, log.call)
  231. assert_equal("/test", res.body, log.call)
  232. else
  233. assert_equal("404", res.code, log.call)
  234. end
  235. end
  236. req = Net::HTTP::Get.new("/.htaccess")
  237. http.request(req) {|res| assert_equal("404", res.code, log.call) }
  238. req = Net::HTTP::Get.new("/htacce~1")
  239. http.request(req) {|res| assert_equal("404", res.code, log.call) }
  240. req = Net::HTTP::Get.new("/HTACCE~1")
  241. http.request(req) {|res| assert_equal("404", res.code, log.call) }
  242. end
  243. end
  244. def test_script_disclosure
  245. return if File.executable?(__FILE__) # skip on strange file system
  246. config = {
  247. :CGIInterpreter => TestWEBrick::RubyBin,
  248. :DocumentRoot => File.dirname(__FILE__),
  249. :CGIPathEnv => ENV['PATH'],
  250. :RequestCallback => Proc.new{|req, res|
  251. def req.meta_vars
  252. meta = super
  253. meta["RUBYLIB"] = $:.join(File::PATH_SEPARATOR)
  254. meta[RbConfig::CONFIG['LIBPATHENV']] = ENV[RbConfig::CONFIG['LIBPATHENV']] if RbConfig::CONFIG['LIBPATHENV']
  255. return meta
  256. end
  257. },
  258. }
  259. log_tester = lambda {|log, access_log|
  260. log = log.reject {|s| /ERROR `.*\' not found\./ =~ s }
  261. assert_equal([], log)
  262. }
  263. TestWEBrick.start_httpserver(config, log_tester) do |server, addr, port, log|
  264. http = Net::HTTP.new(addr, port)
  265. req = Net::HTTP::Get.new("/webrick.cgi/test")
  266. http.request(req) do |res|
  267. assert_equal("200", res.code, log.call)
  268. assert_equal("/test", res.body, log.call)
  269. end
  270. resok = windows?
  271. response_assertion = Proc.new do |res|
  272. if resok
  273. assert_equal("200", res.code, log.call)
  274. assert_equal("/test", res.body, log.call)
  275. else
  276. assert_equal("404", res.code, log.call)
  277. end
  278. end
  279. req = Net::HTTP::Get.new("/webrick.cgi%20/test")
  280. http.request(req, &response_assertion)
  281. req = Net::HTTP::Get.new("/webrick.cgi./test")
  282. http.request(req, &response_assertion)
  283. resok &&= File.exist?(__FILE__+"::$DATA")
  284. req = Net::HTTP::Get.new("/webrick.cgi::$DATA/test")
  285. http.request(req, &response_assertion)
  286. end
  287. end
  288. end