PageRenderTime 30ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/jruby-1.7.3/test/externals/ruby1.9/open-uri/test_open-uri.rb

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Ruby | 730 lines | 684 code | 44 blank | 2 comment | 10 complexity | bdb32aecbe4d4768bc07ab4305d3c4fa MD5 | raw file
  1. require 'test/unit'
  2. require 'open-uri'
  3. require 'webrick'
  4. require 'webrick/httpproxy'
  5. require 'zlib'
  6. class TestOpenURI < Test::Unit::TestCase
  7. NullLog = Object.new
  8. def NullLog.<<(arg)
  9. end
  10. def with_http
  11. Dir.mktmpdir {|dr|
  12. srv = WEBrick::HTTPServer.new({
  13. :DocumentRoot => dr,
  14. :ServerType => Thread,
  15. :Logger => WEBrick::Log.new(NullLog),
  16. :AccessLog => [[NullLog, ""]],
  17. :BindAddress => '127.0.0.1',
  18. :Port => 0})
  19. _, port, _, host = srv.listeners[0].addr
  20. begin
  21. th = srv.start
  22. yield srv, dr, "http://#{host}:#{port}"
  23. ensure
  24. srv.shutdown
  25. end
  26. }
  27. end
  28. def with_env(h)
  29. begin
  30. old = {}
  31. h.each_key {|k| old[k] = ENV[k] }
  32. h.each {|k, v| ENV[k] = v }
  33. yield
  34. ensure
  35. h.each_key {|k| ENV[k] = old[k] }
  36. end
  37. end
  38. def setup
  39. @proxies = %w[http_proxy HTTP_PROXY ftp_proxy FTP_PROXY no_proxy]
  40. @old_proxies = @proxies.map {|k| ENV[k] }
  41. @proxies.each {|k| ENV[k] = nil }
  42. end
  43. def teardown
  44. @proxies.each_with_index {|k, i| ENV[k] = @old_proxies[i] }
  45. end
  46. def test_200
  47. with_http {|srv, dr, url|
  48. open("#{dr}/foo200", "w") {|f| f << "foo200" }
  49. open("#{url}/foo200") {|f|
  50. assert_equal("200", f.status[0])
  51. assert_equal("foo200", f.read)
  52. }
  53. }
  54. end
  55. def test_200big
  56. with_http {|srv, dr, url|
  57. content = "foo200big"*10240
  58. open("#{dr}/foo200big", "w") {|f| f << content }
  59. open("#{url}/foo200big") {|f|
  60. assert_equal("200", f.status[0])
  61. assert_equal(content, f.read)
  62. }
  63. }
  64. end
  65. def test_404
  66. with_http {|srv, dr, url|
  67. exc = assert_raise(OpenURI::HTTPError) { open("#{url}/not-exist") {} }
  68. assert_equal("404", exc.io.status[0])
  69. }
  70. end
  71. def test_open_uri
  72. with_http {|srv, dr, url|
  73. open("#{dr}/foo_ou", "w") {|f| f << "foo_ou" }
  74. u = URI("#{url}/foo_ou")
  75. open(u) {|f|
  76. assert_equal("200", f.status[0])
  77. assert_equal("foo_ou", f.read)
  78. }
  79. }
  80. end
  81. def test_open_too_many_arg
  82. assert_raise(ArgumentError) { open("http://192.0.2.1/tma", "r", 0666, :extra) {} }
  83. end
  84. def test_read_timeout
  85. TCPServer.open("127.0.0.1", 0) {|serv|
  86. port = serv.addr[1]
  87. th = Thread.new {
  88. sock = serv.accept
  89. begin
  90. req = sock.gets("\r\n\r\n")
  91. assert_match(%r{\AGET /foo/bar }, req)
  92. sock.print "HTTP/1.0 200 OK\r\n"
  93. sock.print "Content-Length: 4\r\n\r\n"
  94. sleep 1
  95. sock.print "ab\r\n"
  96. ensure
  97. sock.close
  98. end
  99. }
  100. begin
  101. assert_raise(Timeout::Error) { URI("http://127.0.0.1:#{port}/foo/bar").read(:read_timeout=>0.01) }
  102. ensure
  103. Thread.kill(th)
  104. th.join
  105. end
  106. }
  107. end
  108. def test_invalid_option
  109. assert_raise(ArgumentError) { open("http://127.0.0.1/", :invalid_option=>true) {} }
  110. end
  111. def test_mode
  112. with_http {|srv, dr, url|
  113. open("#{dr}/mode", "w") {|f| f << "mode" }
  114. open("#{url}/mode", "r") {|f|
  115. assert_equal("200", f.status[0])
  116. assert_equal("mode", f.read)
  117. }
  118. open("#{url}/mode", "r", 0600) {|f|
  119. assert_equal("200", f.status[0])
  120. assert_equal("mode", f.read)
  121. }
  122. assert_raise(ArgumentError) { open("#{url}/mode", "a") {} }
  123. open("#{url}/mode", "r:us-ascii") {|f|
  124. assert_equal(Encoding::US_ASCII, f.read.encoding)
  125. }
  126. open("#{url}/mode", "r:utf-8") {|f|
  127. assert_equal(Encoding::UTF_8, f.read.encoding)
  128. }
  129. assert_raise(ArgumentError) { open("#{url}/mode", "r:invalid-encoding") {} }
  130. }
  131. end
  132. def test_without_block
  133. with_http {|srv, dr, url|
  134. open("#{dr}/without_block", "w") {|g| g << "without_block" }
  135. begin
  136. f = open("#{url}/without_block")
  137. assert_equal("200", f.status[0])
  138. assert_equal("without_block", f.read)
  139. ensure
  140. f.close
  141. end
  142. }
  143. end
  144. def test_header
  145. myheader1 = 'barrrr'
  146. myheader2 = nil
  147. with_http {|srv, dr, url|
  148. srv.mount_proc("/h/") {|req, res| myheader2 = req['myheader']; res.body = "foo" }
  149. open("#{url}/h/", 'MyHeader'=>myheader1) {|f|
  150. assert_equal("foo", f.read)
  151. assert_equal(myheader1, myheader2)
  152. }
  153. }
  154. end
  155. def test_multi_proxy_opt
  156. assert_raise(ArgumentError) {
  157. open("http://127.0.0.1/", :proxy_http_basic_authentication=>true, :proxy=>true) {}
  158. }
  159. end
  160. def test_non_http_proxy
  161. assert_raise(RuntimeError) {
  162. open("http://127.0.0.1/", :proxy=>URI("ftp://127.0.0.1/")) {}
  163. }
  164. end
  165. def test_proxy
  166. with_http {|srv, dr, url|
  167. log = ''
  168. proxy = WEBrick::HTTPProxyServer.new({
  169. :ServerType => Thread,
  170. :Logger => WEBrick::Log.new(NullLog),
  171. :AccessLog => [[NullLog, ""]],
  172. :ProxyAuthProc => lambda {|req, res|
  173. log << req.request_line
  174. },
  175. :BindAddress => '127.0.0.1',
  176. :Port => 0})
  177. _, proxy_port, _, proxy_host = proxy.listeners[0].addr
  178. proxy_url = "http://#{proxy_host}:#{proxy_port}/"
  179. begin
  180. th = proxy.start
  181. open("#{dr}/proxy", "w") {|f| f << "proxy" }
  182. open("#{url}/proxy", :proxy=>proxy_url) {|f|
  183. assert_equal("200", f.status[0])
  184. assert_equal("proxy", f.read)
  185. }
  186. assert_match(/#{Regexp.quote url}/, log); log.clear
  187. open("#{url}/proxy", :proxy=>URI(proxy_url)) {|f|
  188. assert_equal("200", f.status[0])
  189. assert_equal("proxy", f.read)
  190. }
  191. assert_match(/#{Regexp.quote url}/, log); log.clear
  192. open("#{url}/proxy", :proxy=>nil) {|f|
  193. assert_equal("200", f.status[0])
  194. assert_equal("proxy", f.read)
  195. }
  196. assert_equal("", log); log.clear
  197. assert_raise(ArgumentError) {
  198. open("#{url}/proxy", :proxy=>:invalid) {}
  199. }
  200. assert_equal("", log); log.clear
  201. with_env("http_proxy"=>proxy_url) {
  202. # should not use proxy for 127.0.0.0/8.
  203. open("#{url}/proxy") {|f|
  204. assert_equal("200", f.status[0])
  205. assert_equal("proxy", f.read)
  206. }
  207. }
  208. assert_equal("", log); log.clear
  209. ensure
  210. proxy.shutdown
  211. end
  212. }
  213. end
  214. def test_proxy_http_basic_authentication
  215. with_http {|srv, dr, url|
  216. log = ''
  217. proxy = WEBrick::HTTPProxyServer.new({
  218. :ServerType => Thread,
  219. :Logger => WEBrick::Log.new(NullLog),
  220. :AccessLog => [[NullLog, ""]],
  221. :ProxyAuthProc => lambda {|req, res|
  222. log << req.request_line
  223. if req["Proxy-Authorization"] != "Basic #{['user:pass'].pack('m').chomp}"
  224. raise WEBrick::HTTPStatus::ProxyAuthenticationRequired
  225. end
  226. },
  227. :BindAddress => '127.0.0.1',
  228. :Port => 0})
  229. _, proxy_port, _, proxy_host = proxy.listeners[0].addr
  230. proxy_url = "http://#{proxy_host}:#{proxy_port}/"
  231. begin
  232. th = proxy.start
  233. open("#{dr}/proxy", "w") {|f| f << "proxy" }
  234. exc = assert_raise(OpenURI::HTTPError) { open("#{url}/proxy", :proxy=>proxy_url) {} }
  235. assert_equal("407", exc.io.status[0])
  236. assert_match(/#{Regexp.quote url}/, log); log.clear
  237. open("#{url}/proxy",
  238. :proxy_http_basic_authentication=>[proxy_url, "user", "pass"]) {|f|
  239. assert_equal("200", f.status[0])
  240. assert_equal("proxy", f.read)
  241. }
  242. assert_match(/#{Regexp.quote url}/, log); log.clear
  243. assert_raise(ArgumentError) {
  244. open("#{url}/proxy",
  245. :proxy_http_basic_authentication=>[true, "user", "pass"]) {}
  246. }
  247. assert_equal("", log); log.clear
  248. ensure
  249. proxy.shutdown
  250. end
  251. }
  252. end
  253. def test_redirect
  254. with_http {|srv, dr, url|
  255. srv.mount_proc("/r1/") {|req, res| res.status = 301; res["location"] = "#{url}/r2"; res.body = "r1" }
  256. srv.mount_proc("/r2/") {|req, res| res.body = "r2" }
  257. srv.mount_proc("/to-file/") {|req, res| res.status = 301; res["location"] = "file:///foo" }
  258. open("#{url}/r1/") {|f|
  259. assert_equal("#{url}/r2", f.base_uri.to_s)
  260. assert_equal("r2", f.read)
  261. }
  262. assert_raise(OpenURI::HTTPRedirect) { open("#{url}/r1/", :redirect=>false) {} }
  263. assert_raise(RuntimeError) { open("#{url}/to-file/") {} }
  264. }
  265. end
  266. def test_redirect_loop
  267. with_http {|srv, dr, url|
  268. srv.mount_proc("/r1/") {|req, res| res.status = 301; res["location"] = "#{url}/r2"; res.body = "r1" }
  269. srv.mount_proc("/r2/") {|req, res| res.status = 301; res["location"] = "#{url}/r1"; res.body = "r2" }
  270. assert_raise(RuntimeError) { open("#{url}/r1/") {} }
  271. }
  272. end
  273. def test_redirect_relative
  274. TCPServer.open("127.0.0.1", 0) {|serv|
  275. port = serv.addr[1]
  276. th = Thread.new {
  277. sock = serv.accept
  278. begin
  279. req = sock.gets("\r\n\r\n")
  280. assert_match(%r{\AGET /foo/bar }, req)
  281. sock.print "HTTP/1.0 302 Found\r\n"
  282. sock.print "Location: ../baz\r\n\r\n"
  283. ensure
  284. sock.close
  285. end
  286. sock = serv.accept
  287. begin
  288. req = sock.gets("\r\n\r\n")
  289. assert_match(%r{\AGET /baz }, req)
  290. sock.print "HTTP/1.0 200 OK\r\n"
  291. sock.print "Content-Length: 4\r\n\r\n"
  292. sock.print "ab\r\n"
  293. ensure
  294. sock.close
  295. end
  296. }
  297. begin
  298. content = URI("http://127.0.0.1:#{port}/foo/bar").read
  299. assert_equal("ab\r\n", content)
  300. ensure
  301. Thread.kill(th)
  302. th.join
  303. end
  304. }
  305. end
  306. def test_redirect_invalid
  307. TCPServer.open("127.0.0.1", 0) {|serv|
  308. port = serv.addr[1]
  309. th = Thread.new {
  310. sock = serv.accept
  311. begin
  312. req = sock.gets("\r\n\r\n")
  313. assert_match(%r{\AGET /foo/bar }, req)
  314. sock.print "HTTP/1.0 302 Found\r\n"
  315. sock.print "Location: ::\r\n\r\n"
  316. ensure
  317. sock.close
  318. end
  319. }
  320. begin
  321. assert_raise(OpenURI::HTTPError) {
  322. URI("http://127.0.0.1:#{port}/foo/bar").read
  323. }
  324. ensure
  325. Thread.kill(th)
  326. th.join
  327. end
  328. }
  329. end
  330. def test_redirect_auth
  331. with_http {|srv, dr, url|
  332. srv.mount_proc("/r1/") {|req, res| res.status = 301; res["location"] = "#{url}/r2" }
  333. srv.mount_proc("/r2/") {|req, res|
  334. if req["Authorization"] != "Basic #{['user:pass'].pack('m').chomp}"
  335. raise WEBrick::HTTPStatus::Unauthorized
  336. end
  337. res.body = "r2"
  338. }
  339. exc = assert_raise(OpenURI::HTTPError) { open("#{url}/r2/") {} }
  340. assert_equal("401", exc.io.status[0])
  341. open("#{url}/r2/", :http_basic_authentication=>['user', 'pass']) {|f|
  342. assert_equal("r2", f.read)
  343. }
  344. exc = assert_raise(OpenURI::HTTPError) { open("#{url}/r1/", :http_basic_authentication=>['user', 'pass']) {} }
  345. assert_equal("401", exc.io.status[0])
  346. }
  347. end
  348. def test_userinfo
  349. if "1.9.0" <= RUBY_VERSION
  350. assert_raise(ArgumentError) { open("http://user:pass@127.0.0.1/") {} }
  351. end
  352. end
  353. def test_progress
  354. with_http {|srv, dr, url|
  355. content = "a" * 100000
  356. srv.mount_proc("/data/") {|req, res| res.body = content }
  357. length = []
  358. progress = []
  359. open("#{url}/data/",
  360. :content_length_proc => lambda {|n| length << n },
  361. :progress_proc => lambda {|n| progress << n }
  362. ) {|f|
  363. assert_equal(1, length.length)
  364. assert_equal(content.length, length[0])
  365. assert(progress.length>1,"maybe test is wrong")
  366. assert(progress.sort == progress,"monotone increasing expected but was\n#{progress.inspect}")
  367. assert_equal(content.length, progress[-1])
  368. assert_equal(content, f.read)
  369. }
  370. }
  371. end
  372. def test_progress_chunked
  373. with_http {|srv, dr, url|
  374. content = "a" * 100000
  375. srv.mount_proc("/data/") {|req, res| res.body = content; res.chunked = true }
  376. length = []
  377. progress = []
  378. open("#{url}/data/",
  379. :content_length_proc => lambda {|n| length << n },
  380. :progress_proc => lambda {|n| progress << n }
  381. ) {|f|
  382. assert_equal(1, length.length)
  383. assert_equal(nil, length[0])
  384. assert(progress.length>1,"maybe test is worng")
  385. assert(progress.sort == progress,"monotone increasing expected but was\n#{progress.inspect}")
  386. assert_equal(content.length, progress[-1])
  387. assert_equal(content, f.read)
  388. }
  389. }
  390. end
  391. def test_uri_read
  392. with_http {|srv, dr, url|
  393. open("#{dr}/uriread", "w") {|f| f << "uriread" }
  394. data = URI("#{url}/uriread").read
  395. assert_equal("200", data.status[0])
  396. assert_equal("uriread", data)
  397. }
  398. end
  399. def test_encoding
  400. with_http {|srv, dr, url|
  401. content_u8 = "\u3042"
  402. content_ej = "\xa2\xa4".force_encoding("euc-jp")
  403. srv.mount_proc("/u8/") {|req, res| res.body = content_u8; res['content-type'] = 'text/plain; charset=utf-8' }
  404. srv.mount_proc("/ej/") {|req, res| res.body = content_ej; res['content-type'] = 'TEXT/PLAIN; charset=EUC-JP' }
  405. srv.mount_proc("/nc/") {|req, res| res.body = "aa"; res['content-type'] = 'Text/Plain' }
  406. open("#{url}/u8/") {|f|
  407. assert_equal(content_u8, f.read)
  408. assert_equal("text/plain", f.content_type)
  409. assert_equal("utf-8", f.charset)
  410. }
  411. open("#{url}/ej/") {|f|
  412. assert_equal(content_ej, f.read)
  413. assert_equal("text/plain", f.content_type)
  414. assert_equal("euc-jp", f.charset)
  415. }
  416. open("#{url}/nc/") {|f|
  417. assert_equal("aa", f.read)
  418. assert_equal("text/plain", f.content_type)
  419. assert_equal("iso-8859-1", f.charset)
  420. assert_equal("unknown", f.charset { "unknown" })
  421. }
  422. }
  423. end
  424. def test_quoted_attvalue
  425. with_http {|srv, dr, url|
  426. content_u8 = "\u3042"
  427. srv.mount_proc("/qu8/") {|req, res| res.body = content_u8; res['content-type'] = 'text/plain; charset="utf\-8"' }
  428. open("#{url}/qu8/") {|f|
  429. assert_equal(content_u8, f.read)
  430. assert_equal("text/plain", f.content_type)
  431. assert_equal("utf-8", f.charset)
  432. }
  433. }
  434. end
  435. def test_last_modified
  436. with_http {|srv, dr, url|
  437. srv.mount_proc("/data/") {|req, res| res.body = "foo"; res['last-modified'] = 'Fri, 07 Aug 2009 06:05:04 GMT' }
  438. open("#{url}/data/") {|f|
  439. assert_equal("foo", f.read)
  440. assert_equal(Time.utc(2009,8,7,6,5,4), f.last_modified)
  441. }
  442. }
  443. end
  444. def test_content_encoding
  445. with_http {|srv, dr, url|
  446. content = "abc" * 10000
  447. Zlib::GzipWriter.wrap(StringIO.new(content_gz="".force_encoding("ascii-8bit"))) {|z| z.write content }
  448. srv.mount_proc("/data/") {|req, res| res.body = content_gz; res['content-encoding'] = 'gzip' }
  449. srv.mount_proc("/data2/") {|req, res| res.body = content_gz; res['content-encoding'] = 'gzip'; res.chunked = true }
  450. srv.mount_proc("/noce/") {|req, res| res.body = content_gz }
  451. open("#{url}/data/") {|f|
  452. assert_equal ['gzip'], f.content_encoding
  453. assert_equal(content_gz, f.read.force_encoding("ascii-8bit"))
  454. }
  455. open("#{url}/data2/") {|f|
  456. assert_equal ['gzip'], f.content_encoding
  457. assert_equal(content_gz, f.read.force_encoding("ascii-8bit"))
  458. }
  459. open("#{url}/noce/") {|f|
  460. assert_equal [], f.content_encoding
  461. assert_equal(content_gz, f.read.force_encoding("ascii-8bit"))
  462. }
  463. }
  464. end
  465. # 192.0.2.0/24 is TEST-NET. [RFC3330]
  466. def test_find_proxy
  467. assert_nil(URI("http://192.0.2.1/").find_proxy)
  468. assert_nil(URI("ftp://192.0.2.1/").find_proxy)
  469. with_env('http_proxy'=>'http://127.0.0.1:8080') {
  470. assert_equal(URI('http://127.0.0.1:8080'), URI("http://192.0.2.1/").find_proxy)
  471. assert_nil(URI("ftp://192.0.2.1/").find_proxy)
  472. }
  473. with_env('ftp_proxy'=>'http://127.0.0.1:8080') {
  474. assert_nil(URI("http://192.0.2.1/").find_proxy)
  475. assert_equal(URI('http://127.0.0.1:8080'), URI("ftp://192.0.2.1/").find_proxy)
  476. }
  477. with_env('REQUEST_METHOD'=>'GET') {
  478. assert_nil(URI("http://192.0.2.1/").find_proxy)
  479. }
  480. with_env('CGI_HTTP_PROXY'=>'http://127.0.0.1:8080', 'REQUEST_METHOD'=>'GET') {
  481. assert_equal(URI('http://127.0.0.1:8080'), URI("http://192.0.2.1/").find_proxy)
  482. }
  483. with_env('http_proxy'=>'http://127.0.0.1:8080', 'no_proxy'=>'192.0.2.2') {
  484. assert_equal(URI('http://127.0.0.1:8080'), URI("http://192.0.2.1/").find_proxy)
  485. assert_nil(URI("http://192.0.2.2/").find_proxy)
  486. }
  487. end
  488. def test_find_proxy_case_sensitive_env
  489. with_env('http_proxy'=>'http://127.0.0.1:8080', 'REQUEST_METHOD'=>'GET') {
  490. assert_equal(URI('http://127.0.0.1:8080'), URI("http://192.0.2.1/").find_proxy)
  491. }
  492. with_env('HTTP_PROXY'=>'http://127.0.0.1:8081', 'REQUEST_METHOD'=>'GET') {
  493. assert_nil(nil, URI("http://192.0.2.1/").find_proxy)
  494. }
  495. with_env('http_proxy'=>'http://127.0.0.1:8080', 'HTTP_PROXY'=>'http://127.0.0.1:8081', 'REQUEST_METHOD'=>'GET') {
  496. assert_equal(URI('http://127.0.0.1:8080'), URI("http://192.0.2.1/").find_proxy)
  497. }
  498. end unless RUBY_PLATFORM =~ /mswin|mingw/
  499. def test_ftp_invalid_request
  500. assert_raise(ArgumentError) { URI("ftp://127.0.0.1/").read }
  501. assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Db").read }
  502. assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Ab").read }
  503. assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Db/f").read }
  504. assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Ab/f").read }
  505. assert_raise(URI::InvalidComponentError) { URI("ftp://127.0.0.1/d/f;type=x") }
  506. end
  507. def test_ftp
  508. TCPServer.open("127.0.0.1", 0) {|serv|
  509. _, port, _, host = serv.addr
  510. th = Thread.new {
  511. s = serv.accept
  512. begin
  513. s.print "220 Test FTP Server\r\n"
  514. assert_equal("USER anonymous\r\n", s.gets); s.print "331 name ok\r\n"
  515. assert_match(/\APASS .*\r\n\z/, s.gets); s.print "230 logged in\r\n"
  516. assert_equal("TYPE I\r\n", s.gets); s.print "200 type set to I\r\n"
  517. assert_equal("CWD foo\r\n", s.gets); s.print "250 CWD successful\r\n"
  518. assert_equal("PASV\r\n", s.gets)
  519. TCPServer.open("127.0.0.1", 0) {|data_serv|
  520. _, data_serv_port, _, data_serv_host = data_serv.addr
  521. hi = data_serv_port >> 8
  522. lo = data_serv_port & 0xff
  523. s.print "227 Entering Passive Mode (127,0,0,1,#{hi},#{lo}).\r\n"
  524. assert_equal("RETR bar\r\n", s.gets); s.print "150 file okay\r\n"
  525. data_sock = data_serv.accept
  526. begin
  527. data_sock << "content"
  528. ensure
  529. data_sock.close
  530. end
  531. s.print "226 transfer complete\r\n"
  532. assert_nil(s.gets)
  533. }
  534. ensure
  535. s.close if s
  536. end
  537. }
  538. begin
  539. content = URI("ftp://#{host}:#{port}/foo/bar").read
  540. assert_equal("content", content)
  541. ensure
  542. Thread.kill(th)
  543. th.join
  544. end
  545. }
  546. end
  547. def test_ftp_active
  548. TCPServer.open("127.0.0.1", 0) {|serv|
  549. _, port, _, host = serv.addr
  550. th = Thread.new {
  551. s = serv.accept
  552. begin
  553. content = "content"
  554. s.print "220 Test FTP Server\r\n"
  555. assert_equal("USER anonymous\r\n", s.gets); s.print "331 name ok\r\n"
  556. assert_match(/\APASS .*\r\n\z/, s.gets); s.print "230 logged in\r\n"
  557. assert_equal("TYPE I\r\n", s.gets); s.print "200 type set to I\r\n"
  558. assert_equal("CWD foo\r\n", s.gets); s.print "250 CWD successful\r\n"
  559. assert(m = /\APORT 127,0,0,1,(\d+),(\d+)\r\n\z/.match(s.gets))
  560. active_port = m[1].to_i << 8 | m[2].to_i
  561. TCPSocket.open("127.0.0.1", active_port) {|data_sock|
  562. s.print "200 data connection opened\r\n"
  563. assert_equal("RETR bar\r\n", s.gets); s.print "150 file okay\r\n"
  564. begin
  565. data_sock << content
  566. ensure
  567. data_sock.close
  568. end
  569. s.print "226 transfer complete\r\n"
  570. assert_nil(s.gets)
  571. }
  572. ensure
  573. s.close if s
  574. end
  575. }
  576. begin
  577. content = URI("ftp://#{host}:#{port}/foo/bar").read(:ftp_active_mode=>true)
  578. assert_equal("content", content)
  579. ensure
  580. Thread.kill(th)
  581. th.join
  582. end
  583. }
  584. end
  585. def test_ftp_ascii
  586. TCPServer.open("127.0.0.1", 0) {|serv|
  587. _, port, _, host = serv.addr
  588. th = Thread.new {
  589. s = serv.accept
  590. begin
  591. content = "content"
  592. s.print "220 Test FTP Server\r\n"
  593. assert_equal("USER anonymous\r\n", s.gets); s.print "331 name ok\r\n"
  594. assert_match(/\APASS .*\r\n\z/, s.gets); s.print "230 logged in\r\n"
  595. assert_equal("TYPE I\r\n", s.gets); s.print "200 type set to I\r\n"
  596. assert_equal("CWD /foo\r\n", s.gets); s.print "250 CWD successful\r\n"
  597. assert_equal("TYPE A\r\n", s.gets); s.print "200 type set to A\r\n"
  598. assert_equal("SIZE bar\r\n", s.gets); s.print "213 #{content.bytesize}\r\n"
  599. assert_equal("PASV\r\n", s.gets)
  600. TCPServer.open("127.0.0.1", 0) {|data_serv|
  601. _, data_serv_port, _, data_serv_host = data_serv.addr
  602. hi = data_serv_port >> 8
  603. lo = data_serv_port & 0xff
  604. s.print "227 Entering Passive Mode (127,0,0,1,#{hi},#{lo}).\r\n"
  605. assert_equal("RETR bar\r\n", s.gets); s.print "150 file okay\r\n"
  606. data_sock = data_serv.accept
  607. begin
  608. data_sock << content
  609. ensure
  610. data_sock.close
  611. end
  612. s.print "226 transfer complete\r\n"
  613. assert_nil(s.gets)
  614. }
  615. ensure
  616. s.close if s
  617. end
  618. }
  619. begin
  620. length = []
  621. progress = []
  622. content = URI("ftp://#{host}:#{port}/%2Ffoo/b%61r;type=a").read(
  623. :content_length_proc => lambda {|n| length << n },
  624. :progress_proc => lambda {|n| progress << n })
  625. assert_equal("content", content)
  626. assert_equal([7], length)
  627. assert_equal(7, progress.inject(&:+))
  628. ensure
  629. Thread.kill(th)
  630. th.join
  631. end
  632. }
  633. end
  634. def test_ftp_over_http_proxy
  635. TCPServer.open("127.0.0.1", 0) {|proxy_serv|
  636. proxy_port = proxy_serv.addr[1]
  637. th = Thread.new {
  638. proxy_sock = proxy_serv.accept
  639. begin
  640. req = proxy_sock.gets("\r\n\r\n")
  641. assert_match(%r{\AGET ftp://192.0.2.1/foo/bar }, req)
  642. proxy_sock.print "HTTP/1.0 200 OK\r\n"
  643. proxy_sock.print "Content-Length: 4\r\n\r\n"
  644. proxy_sock.print "ab\r\n"
  645. ensure
  646. proxy_sock.close
  647. end
  648. }
  649. begin
  650. with_env('ftp_proxy'=>"http://127.0.0.1:#{proxy_port}") {
  651. content = URI("ftp://192.0.2.1/foo/bar").read
  652. assert_equal("ab\r\n", content)
  653. }
  654. ensure
  655. Thread.kill(th)
  656. th.join
  657. end
  658. }
  659. end
  660. def test_ftp_over_http_proxy_auth
  661. TCPServer.open("127.0.0.1", 0) {|proxy_serv|
  662. proxy_port = proxy_serv.addr[1]
  663. th = Thread.new {
  664. proxy_sock = proxy_serv.accept
  665. begin
  666. req = proxy_sock.gets("\r\n\r\n")
  667. assert_match(%r{\AGET ftp://192.0.2.1/foo/bar }, req)
  668. assert_match(%r{Proxy-Authorization: Basic #{['proxy-user:proxy-password'].pack('m').chomp}\r\n}, req)
  669. proxy_sock.print "HTTP/1.0 200 OK\r\n"
  670. proxy_sock.print "Content-Length: 4\r\n\r\n"
  671. proxy_sock.print "ab\r\n"
  672. ensure
  673. proxy_sock.close
  674. end
  675. }
  676. begin
  677. content = URI("ftp://192.0.2.1/foo/bar").read(
  678. :proxy_http_basic_authentication => ["http://127.0.0.1:#{proxy_port}", "proxy-user", "proxy-password"])
  679. assert_equal("ab\r\n", content)
  680. ensure
  681. Thread.kill(th)
  682. th.join
  683. end
  684. }
  685. end
  686. end