PageRenderTime 63ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/test/mri/net/http/test_http.rb

http://github.com/jruby/jruby
Ruby | 990 lines | 813 code | 161 blank | 16 comment | 4 complexity | 10732a6524b54f7531a8078b7a4a385e MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, GPL-2.0, JSON, LGPL-2.1
  1. # coding: US-ASCII
  2. # frozen_string_literal: false
  3. require 'test/unit'
  4. require 'net/http'
  5. require 'stringio'
  6. require_relative 'utils'
  7. class TestNetHTTP < Test::Unit::TestCase
  8. def test_class_Proxy
  9. no_proxy_class = Net::HTTP.Proxy nil
  10. assert_equal Net::HTTP, no_proxy_class
  11. proxy_class = Net::HTTP.Proxy 'proxy.example', 8000, 'user', 'pass'
  12. refute_equal Net::HTTP, proxy_class
  13. assert_operator proxy_class, :<, Net::HTTP
  14. assert_equal 'proxy.example', proxy_class.proxy_address
  15. assert_equal 8000, proxy_class.proxy_port
  16. assert_equal 'user', proxy_class.proxy_user
  17. assert_equal 'pass', proxy_class.proxy_pass
  18. http = proxy_class.new 'hostname.example'
  19. refute http.proxy_from_env?
  20. proxy_class = Net::HTTP.Proxy 'proxy.example'
  21. assert_equal 'proxy.example', proxy_class.proxy_address
  22. assert_equal 80, proxy_class.proxy_port
  23. end
  24. def test_class_Proxy_from_ENV
  25. clean_http_proxy_env do
  26. ENV['http_proxy'] = 'http://proxy.example:8000'
  27. # These are ignored on purpose. See Bug 4388 and Feature 6546
  28. ENV['http_proxy_user'] = 'user'
  29. ENV['http_proxy_pass'] = 'pass'
  30. proxy_class = Net::HTTP.Proxy :ENV
  31. refute_equal Net::HTTP, proxy_class
  32. assert_operator proxy_class, :<, Net::HTTP
  33. assert_nil proxy_class.proxy_address
  34. assert_nil proxy_class.proxy_user
  35. assert_nil proxy_class.proxy_pass
  36. refute_equal 8000, proxy_class.proxy_port
  37. http = proxy_class.new 'hostname.example'
  38. assert http.proxy_from_env?
  39. end
  40. end
  41. def test_edit_path
  42. http = Net::HTTP.new 'hostname.example', nil, nil
  43. edited = http.send :edit_path, '/path'
  44. assert_equal '/path', edited
  45. http.use_ssl = true
  46. edited = http.send :edit_path, '/path'
  47. assert_equal '/path', edited
  48. end
  49. def test_edit_path_proxy
  50. http = Net::HTTP.new 'hostname.example', nil, 'proxy.example'
  51. edited = http.send :edit_path, '/path'
  52. assert_equal 'http://hostname.example/path', edited
  53. http.use_ssl = true
  54. edited = http.send :edit_path, '/path'
  55. assert_equal '/path', edited
  56. end
  57. def test_proxy_address
  58. clean_http_proxy_env do
  59. http = Net::HTTP.new 'hostname.example', nil, 'proxy.example'
  60. assert_equal 'proxy.example', http.proxy_address
  61. http = Net::HTTP.new 'hostname.example', nil
  62. assert_equal nil, http.proxy_address
  63. end
  64. end
  65. def test_proxy_from_env_ENV
  66. clean_http_proxy_env do
  67. ENV['http_proxy'] = 'http://proxy.example:8000'
  68. assert_equal false, Net::HTTP.proxy_class?
  69. http = Net::HTTP.new 'hostname.example'
  70. assert_equal true, http.proxy_from_env?
  71. end
  72. end
  73. def test_proxy_address_ENV
  74. clean_http_proxy_env do
  75. ENV['http_proxy'] = 'http://proxy.example:8000'
  76. http = Net::HTTP.new 'hostname.example'
  77. assert_equal 'proxy.example', http.proxy_address
  78. end
  79. end
  80. def test_proxy_eh_no_proxy
  81. clean_http_proxy_env do
  82. assert_equal false, Net::HTTP.new('hostname.example', nil, nil).proxy?
  83. end
  84. end
  85. def test_proxy_eh_ENV
  86. clean_http_proxy_env do
  87. ENV['http_proxy'] = 'http://proxy.example:8000'
  88. http = Net::HTTP.new 'hostname.example'
  89. assert_equal true, http.proxy?
  90. end
  91. end
  92. def test_proxy_eh_ENV_none_set
  93. clean_http_proxy_env do
  94. assert_equal false, Net::HTTP.new('hostname.example').proxy?
  95. end
  96. end
  97. def test_proxy_eh_ENV_no_proxy
  98. clean_http_proxy_env do
  99. ENV['http_proxy'] = 'http://proxy.example:8000'
  100. ENV['no_proxy'] = 'hostname.example'
  101. assert_equal false, Net::HTTP.new('hostname.example').proxy?
  102. end
  103. end
  104. def test_proxy_port
  105. clean_http_proxy_env do
  106. http = Net::HTTP.new 'exmaple', nil, 'proxy.example'
  107. assert_equal 'proxy.example', http.proxy_address
  108. assert_equal 80, http.proxy_port
  109. http = Net::HTTP.new 'exmaple', nil, 'proxy.example', 8000
  110. assert_equal 8000, http.proxy_port
  111. http = Net::HTTP.new 'exmaple', nil
  112. assert_equal nil, http.proxy_port
  113. end
  114. end
  115. def test_proxy_port_ENV
  116. clean_http_proxy_env do
  117. ENV['http_proxy'] = 'http://proxy.example:8000'
  118. http = Net::HTTP.new 'hostname.example'
  119. assert_equal 8000, http.proxy_port
  120. end
  121. end
  122. def test_newobj
  123. clean_http_proxy_env do
  124. ENV['http_proxy'] = 'http://proxy.example:8000'
  125. http = Net::HTTP.newobj 'hostname.example'
  126. assert_equal false, http.proxy?
  127. end
  128. end
  129. def clean_http_proxy_env
  130. orig = {
  131. 'http_proxy' => ENV['http_proxy'],
  132. 'http_proxy_user' => ENV['http_proxy_user'],
  133. 'http_proxy_pass' => ENV['http_proxy_pass'],
  134. 'no_proxy' => ENV['no_proxy'],
  135. }
  136. orig.each_key do |key|
  137. ENV.delete key
  138. end
  139. yield
  140. ensure
  141. orig.each do |key, value|
  142. ENV[key] = value
  143. end
  144. end
  145. def test_failure_message_includes_failed_domain_and_port
  146. # hostname to be included in the error message
  147. host = Struct.new(:to_s).new("<example>")
  148. port = 2119
  149. # hack to let TCPSocket.open fail
  150. def host.to_str; raise SocketError, "open failure"; end
  151. uri = Struct.new(:scheme, :hostname, :port).new("http", host, port)
  152. assert_raise_with_message(SocketError, /#{host}:#{port}/) do
  153. Net::HTTP.get(uri)
  154. end
  155. end
  156. end
  157. module TestNetHTTP_version_1_1_methods
  158. def test_s_get
  159. assert_equal $test_net_http_data,
  160. Net::HTTP.get(config('host'), '/', config('port'))
  161. end
  162. def test_head
  163. start {|http|
  164. res = http.head('/')
  165. assert_kind_of Net::HTTPResponse, res
  166. assert_equal $test_net_http_data_type, res['Content-Type']
  167. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  168. assert_equal $test_net_http_data.size, res['Content-Length'].to_i
  169. end
  170. }
  171. end
  172. def test_get
  173. start {|http|
  174. _test_get__get http
  175. _test_get__iter http
  176. _test_get__chunked http
  177. }
  178. end
  179. def _test_get__get(http)
  180. res = http.get('/')
  181. assert_kind_of Net::HTTPResponse, res
  182. assert_kind_of String, res.body
  183. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  184. assert_not_nil res['content-length']
  185. assert_equal $test_net_http_data.size, res['content-length'].to_i
  186. end
  187. assert_equal $test_net_http_data_type, res['Content-Type']
  188. assert_equal $test_net_http_data.size, res.body.size
  189. assert_equal $test_net_http_data, res.body
  190. assert_nothing_raised {
  191. http.get('/', { 'User-Agent' => 'test' }.freeze)
  192. }
  193. assert res.decode_content, '[Bug #7924]' if Net::HTTP::HAVE_ZLIB
  194. end
  195. def _test_get__iter(http)
  196. buf = ''
  197. res = http.get('/') {|s| buf << s }
  198. assert_kind_of Net::HTTPResponse, res
  199. # assert_kind_of String, res.body
  200. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  201. assert_not_nil res['content-length']
  202. assert_equal $test_net_http_data.size, res['content-length'].to_i
  203. end
  204. assert_equal $test_net_http_data_type, res['Content-Type']
  205. assert_equal $test_net_http_data.size, buf.size
  206. assert_equal $test_net_http_data, buf
  207. # assert_equal $test_net_http_data.size, res.body.size
  208. # assert_equal $test_net_http_data, res.body
  209. end
  210. def _test_get__chunked(http)
  211. buf = ''
  212. res = http.get('/') {|s| buf << s }
  213. assert_kind_of Net::HTTPResponse, res
  214. # assert_kind_of String, res.body
  215. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  216. assert_not_nil res['content-length']
  217. assert_equal $test_net_http_data.size, res['content-length'].to_i
  218. end
  219. assert_equal $test_net_http_data_type, res['Content-Type']
  220. assert_equal $test_net_http_data.size, buf.size
  221. assert_equal $test_net_http_data, buf
  222. # assert_equal $test_net_http_data.size, res.body.size
  223. # assert_equal $test_net_http_data, res.body
  224. end
  225. def test_get__break
  226. i = 0
  227. start {|http|
  228. http.get('/') do |str|
  229. i += 1
  230. break
  231. end
  232. }
  233. assert_equal 1, i
  234. @log_tester = nil # server may encount ECONNRESET
  235. end
  236. def test_get__implicit_start
  237. res = new().get('/')
  238. assert_kind_of Net::HTTPResponse, res
  239. assert_kind_of String, res.body
  240. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  241. assert_not_nil res['content-length']
  242. end
  243. assert_equal $test_net_http_data_type, res['Content-Type']
  244. assert_equal $test_net_http_data.size, res.body.size
  245. assert_equal $test_net_http_data, res.body
  246. end
  247. def test_get2
  248. start {|http|
  249. http.get2('/') {|res|
  250. EnvUtil.suppress_warning do
  251. assert_kind_of Net::HTTPResponse, res
  252. assert_kind_of Net::HTTPResponse, res.header
  253. end
  254. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  255. assert_not_nil res['content-length']
  256. end
  257. assert_equal $test_net_http_data_type, res['Content-Type']
  258. assert_kind_of String, res.body
  259. assert_kind_of String, res.entity
  260. assert_equal $test_net_http_data.size, res.body.size
  261. assert_equal $test_net_http_data, res.body
  262. assert_equal $test_net_http_data, res.entity
  263. }
  264. }
  265. end
  266. def test_post
  267. start {|http|
  268. _test_post__base http
  269. _test_post__file http
  270. _test_post__no_data http
  271. }
  272. end
  273. def _test_post__base(http)
  274. uheader = {}
  275. uheader['Accept'] = 'application/octet-stream'
  276. uheader['Content-Type'] = 'application/x-www-form-urlencoded'
  277. data = 'post data'
  278. res = http.post('/', data, uheader)
  279. assert_kind_of Net::HTTPResponse, res
  280. assert_kind_of String, res.body
  281. assert_equal data, res.body
  282. assert_equal data, res.entity
  283. end
  284. def _test_post__file(http)
  285. data = 'post data'
  286. f = StringIO.new
  287. http.post('/', data, {'content-type' => 'application/x-www-form-urlencoded'}, f)
  288. assert_equal data, f.string
  289. end
  290. def _test_post__no_data(http)
  291. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  292. EnvUtil.suppress_warning do
  293. data = nil
  294. res = http.post('/', data)
  295. assert_not_equal '411', res.code
  296. end
  297. end
  298. end
  299. def test_s_post_form
  300. url = "http://#{config('host')}:#{config('port')}/"
  301. res = Net::HTTP.post_form(
  302. URI.parse(url),
  303. "a" => "x")
  304. assert_equal ["a=x"], res.body.split(/[;&]/).sort
  305. res = Net::HTTP.post_form(
  306. URI.parse(url),
  307. "a" => "x",
  308. "b" => "y")
  309. assert_equal ["a=x", "b=y"], res.body.split(/[;&]/).sort
  310. res = Net::HTTP.post_form(
  311. URI.parse(url),
  312. "a" => ["x1", "x2"],
  313. "b" => "y")
  314. assert_equal url, res['X-request-uri']
  315. assert_equal ["a=x1", "a=x2", "b=y"], res.body.split(/[;&]/).sort
  316. res = Net::HTTP.post_form(
  317. URI.parse(url + '?a=x'),
  318. "b" => "y")
  319. assert_equal url + '?a=x', res['X-request-uri']
  320. assert_equal ["b=y"], res.body.split(/[;&]/).sort
  321. end
  322. def test_patch
  323. start {|http|
  324. _test_patch__base http
  325. }
  326. end
  327. def _test_patch__base(http)
  328. uheader = {}
  329. uheader['Accept'] = 'application/octet-stream'
  330. uheader['Content-Type'] = 'application/x-www-form-urlencoded'
  331. data = 'patch data'
  332. res = http.patch('/', data, uheader)
  333. assert_kind_of Net::HTTPResponse, res
  334. assert_kind_of String, res.body
  335. assert_equal data, res.body
  336. assert_equal data, res.entity
  337. end
  338. def test_timeout_during_HTTP_session
  339. bug4246 = "expected the HTTP session to have timed out but have not. c.f. [ruby-core:34203]"
  340. th = nil
  341. # listen for connections... but deliberately do not read
  342. TCPServer.open('localhost', 0) {|server|
  343. port = server.addr[1]
  344. conn = Net::HTTP.new('localhost', port)
  345. conn.read_timeout = 0.01
  346. conn.open_timeout = 0.1
  347. th = Thread.new do
  348. assert_raise(Net::ReadTimeout) {
  349. conn.get('/')
  350. }
  351. end
  352. assert th.join(10), bug4246
  353. }
  354. ensure
  355. th.kill
  356. th.join
  357. end
  358. end
  359. module TestNetHTTP_version_1_2_methods
  360. def test_request
  361. start {|http|
  362. _test_request__GET http
  363. _test_request__accept_encoding http
  364. _test_request__file http
  365. # _test_request__range http # WEBrick does not support Range: header.
  366. _test_request__HEAD http
  367. _test_request__POST http
  368. _test_request__stream_body http
  369. _test_request__uri http
  370. _test_request__uri_host http
  371. }
  372. end
  373. def _test_request__GET(http)
  374. req = Net::HTTP::Get.new('/')
  375. http.request(req) {|res|
  376. assert_kind_of Net::HTTPResponse, res
  377. assert_kind_of String, res.body
  378. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  379. assert_not_nil res['content-length']
  380. assert_equal $test_net_http_data.size, res['content-length'].to_i
  381. end
  382. assert_equal $test_net_http_data.size, res.body.size
  383. assert_equal $test_net_http_data, res.body
  384. assert res.decode_content, 'Bug #7831' if Net::HTTP::HAVE_ZLIB
  385. }
  386. end
  387. def _test_request__accept_encoding(http)
  388. req = Net::HTTP::Get.new('/', 'accept-encoding' => 'deflate')
  389. http.request(req) {|res|
  390. assert_kind_of Net::HTTPResponse, res
  391. assert_kind_of String, res.body
  392. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  393. assert_not_nil res['content-length']
  394. assert_equal $test_net_http_data.size, res['content-length'].to_i
  395. end
  396. assert_equal $test_net_http_data.size, res.body.size
  397. assert_equal $test_net_http_data, res.body
  398. refute res.decode_content, 'Bug #7831' if Net::HTTP::HAVE_ZLIB
  399. }
  400. end
  401. def _test_request__file(http)
  402. req = Net::HTTP::Get.new('/')
  403. http.request(req) {|res|
  404. assert_kind_of Net::HTTPResponse, res
  405. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  406. assert_not_nil res['content-length']
  407. assert_equal $test_net_http_data.size, res['content-length'].to_i
  408. end
  409. f = StringIO.new("".force_encoding("ASCII-8BIT"))
  410. res.read_body f
  411. assert_equal $test_net_http_data.bytesize, f.string.bytesize
  412. assert_equal $test_net_http_data.encoding, f.string.encoding
  413. assert_equal $test_net_http_data, f.string
  414. }
  415. end
  416. def _test_request__range(http)
  417. req = Net::HTTP::Get.new('/')
  418. req['range'] = 'bytes=0-5'
  419. assert_equal $test_net_http_data[0,6], http.request(req).body
  420. end
  421. def _test_request__HEAD(http)
  422. req = Net::HTTP::Head.new('/')
  423. http.request(req) {|res|
  424. assert_kind_of Net::HTTPResponse, res
  425. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  426. assert_not_nil res['content-length']
  427. assert_equal $test_net_http_data.size, res['content-length'].to_i
  428. end
  429. assert_nil res.body
  430. }
  431. end
  432. def _test_request__POST(http)
  433. data = 'post data'
  434. req = Net::HTTP::Post.new('/')
  435. req['Accept'] = $test_net_http_data_type
  436. req['Content-Type'] = 'application/x-www-form-urlencoded'
  437. http.request(req, data) {|res|
  438. assert_kind_of Net::HTTPResponse, res
  439. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  440. assert_equal data.size, res['content-length'].to_i
  441. end
  442. assert_kind_of String, res.body
  443. assert_equal data, res.body
  444. }
  445. end
  446. def _test_request__stream_body(http)
  447. req = Net::HTTP::Post.new('/')
  448. data = $test_net_http_data
  449. req.content_length = data.size
  450. req['Content-Type'] = 'application/x-www-form-urlencoded'
  451. req.body_stream = StringIO.new(data)
  452. res = http.request(req)
  453. assert_kind_of Net::HTTPResponse, res
  454. assert_kind_of String, res.body
  455. assert_equal data.size, res.body.size
  456. assert_equal data, res.body
  457. end
  458. def _test_request__path(http)
  459. uri = URI 'https://hostname.example/'
  460. req = Net::HTTP::Get.new('/')
  461. res = http.request(req)
  462. assert_kind_of URI::Generic, req.uri
  463. refute_equal uri, req.uri
  464. assert_equal uri, res.uri
  465. refute_same uri, req.uri
  466. refute_same req.uri, res.uri
  467. end
  468. def _test_request__uri(http)
  469. uri = URI 'https://hostname.example/'
  470. req = Net::HTTP::Get.new(uri)
  471. res = http.request(req)
  472. assert_kind_of URI::Generic, req.uri
  473. refute_equal uri, req.uri
  474. assert_equal req.uri, res.uri
  475. refute_same uri, req.uri
  476. refute_same req.uri, res.uri
  477. end
  478. def _test_request__uri_host(http)
  479. uri = URI 'http://other.example/'
  480. req = Net::HTTP::Get.new(uri)
  481. req['host'] = 'hostname.example'
  482. res = http.request(req)
  483. assert_kind_of URI::Generic, req.uri
  484. assert_equal URI("http://hostname.example:#{http.port}"), res.uri
  485. end
  486. def test_send_request
  487. start {|http|
  488. _test_send_request__GET http
  489. _test_send_request__HEAD http
  490. _test_send_request__POST http
  491. }
  492. end
  493. def _test_send_request__GET(http)
  494. res = http.send_request('GET', '/')
  495. assert_kind_of Net::HTTPResponse, res
  496. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  497. assert_equal $test_net_http_data.size, res['content-length'].to_i
  498. end
  499. assert_kind_of String, res.body
  500. assert_equal $test_net_http_data, res.body
  501. end
  502. def _test_send_request__HEAD(http)
  503. res = http.send_request('HEAD', '/')
  504. assert_kind_of Net::HTTPResponse, res
  505. unless self.is_a?(TestNetHTTP_v1_2_chunked)
  506. assert_not_nil res['content-length']
  507. assert_equal $test_net_http_data.size, res['content-length'].to_i
  508. end
  509. assert_nil res.body
  510. end
  511. def _test_send_request__POST(http)
  512. data = 'aaabbb cc ddddddddddd lkjoiu4j3qlkuoa'
  513. res = http.send_request('POST', '/', data, 'content-type' => 'application/x-www-form-urlencoded')
  514. assert_kind_of Net::HTTPResponse, res
  515. assert_kind_of String, res.body
  516. assert_equal data.size, res.body.size
  517. assert_equal data, res.body
  518. end
  519. def test_set_form
  520. require 'tempfile'
  521. Tempfile.create('ruby-test') {|file|
  522. file << "\u{30c7}\u{30fc}\u{30bf}"
  523. data = [
  524. ['name', 'Gonbei Nanashi'],
  525. ['name', "\u{540d}\u{7121}\u{3057}\u{306e}\u{6a29}\u{5175}\u{885b}"],
  526. ['s"i\o', StringIO.new("\u{3042 3044 4e9c 925b}")],
  527. ["file", file, filename: "ruby-test"]
  528. ]
  529. expected = <<"__EOM__".gsub(/\n/, "\r\n")
  530. --<boundary>
  531. Content-Disposition: form-data; name="name"
  532. Gonbei Nanashi
  533. --<boundary>
  534. Content-Disposition: form-data; name="name"
  535. \xE5\x90\x8D\xE7\x84\xA1\xE3\x81\x97\xE3\x81\xAE\xE6\xA8\xA9\xE5\x85\xB5\xE8\xA1\x9B
  536. --<boundary>
  537. Content-Disposition: form-data; name="s\\"i\\\\o"
  538. \xE3\x81\x82\xE3\x81\x84\xE4\xBA\x9C\xE9\x89\x9B
  539. --<boundary>
  540. Content-Disposition: form-data; name="file"; filename="ruby-test"
  541. Content-Type: application/octet-stream
  542. \xE3\x83\x87\xE3\x83\xBC\xE3\x82\xBF
  543. --<boundary>--
  544. __EOM__
  545. start {|http|
  546. _test_set_form_urlencoded(http, data.reject{|k,v|!v.is_a?(String)})
  547. _test_set_form_multipart(http, false, data, expected)
  548. _test_set_form_multipart(http, true, data, expected)
  549. }
  550. }
  551. end
  552. def _test_set_form_urlencoded(http, data)
  553. req = Net::HTTP::Post.new('/')
  554. req.set_form(data)
  555. res = http.request req
  556. assert_equal "name=Gonbei+Nanashi&name=%E5%90%8D%E7%84%A1%E3%81%97%E3%81%AE%E6%A8%A9%E5%85%B5%E8%A1%9B", res.body
  557. end
  558. def _test_set_form_multipart(http, chunked_p, data, expected)
  559. data.each{|k,v|v.rewind rescue nil}
  560. req = Net::HTTP::Post.new('/')
  561. req.set_form(data, 'multipart/form-data')
  562. req['Transfer-Encoding'] = 'chunked' if chunked_p
  563. res = http.request req
  564. body = res.body
  565. assert_match(/\A--(?<boundary>\S+)/, body)
  566. /\A--(?<boundary>\S+)/ =~ body
  567. expected = expected.gsub(/<boundary>/, boundary)
  568. assert_equal(expected, body)
  569. end
  570. def test_set_form_with_file
  571. require 'tempfile'
  572. Tempfile.create('ruby-test') {|file|
  573. file.binmode
  574. file << $test_net_http_data
  575. filename = File.basename(file.to_path)
  576. data = [['file', file]]
  577. expected = <<"__EOM__".gsub(/\n/, "\r\n")
  578. --<boundary>
  579. Content-Disposition: form-data; name="file"; filename="<filename>"
  580. Content-Type: application/octet-stream
  581. <data>
  582. --<boundary>--
  583. __EOM__
  584. expected.sub!(/<filename>/, filename)
  585. expected.sub!(/<data>/, $test_net_http_data)
  586. start {|http|
  587. data.each{|k,v|v.rewind rescue nil}
  588. req = Net::HTTP::Post.new('/')
  589. req.set_form(data, 'multipart/form-data')
  590. res = http.request req
  591. body = res.body
  592. header, _ = body.split(/\r\n\r\n/, 2)
  593. assert_match(/\A--(?<boundary>\S+)/, body)
  594. /\A--(?<boundary>\S+)/ =~ body
  595. expected = expected.gsub(/<boundary>/, boundary)
  596. assert_match(/^--(?<boundary>\S+)\r\n/, header)
  597. assert_match(
  598. /^Content-Disposition: form-data; name="file"; filename="#{filename}"\r\n/,
  599. header)
  600. assert_equal(expected, body)
  601. data.each{|k,v|v.rewind rescue nil}
  602. req['Transfer-Encoding'] = 'chunked'
  603. res = http.request req
  604. #assert_equal(expected, res.body)
  605. }
  606. }
  607. end
  608. end
  609. class TestNetHTTP_v1_2 < Test::Unit::TestCase
  610. CONFIG = {
  611. 'host' => '127.0.0.1',
  612. 'proxy_host' => nil,
  613. 'proxy_port' => nil,
  614. }
  615. include TestNetHTTPUtils
  616. include TestNetHTTP_version_1_1_methods
  617. include TestNetHTTP_version_1_2_methods
  618. def new
  619. Net::HTTP.version_1_2
  620. super
  621. end
  622. end
  623. class TestNetHTTP_v1_2_chunked < Test::Unit::TestCase
  624. CONFIG = {
  625. 'host' => '127.0.0.1',
  626. 'proxy_host' => nil,
  627. 'proxy_port' => nil,
  628. 'chunked' => true,
  629. }
  630. include TestNetHTTPUtils
  631. include TestNetHTTP_version_1_1_methods
  632. include TestNetHTTP_version_1_2_methods
  633. def new
  634. Net::HTTP.version_1_2
  635. super
  636. end
  637. def test_chunked_break
  638. assert_nothing_raised("[ruby-core:29229]") {
  639. start {|http|
  640. http.request_get('/') {|res|
  641. res.read_body {|chunk|
  642. break
  643. }
  644. }
  645. }
  646. }
  647. end
  648. end
  649. class TestNetHTTPContinue < Test::Unit::TestCase
  650. CONFIG = {
  651. 'host' => '127.0.0.1',
  652. 'proxy_host' => nil,
  653. 'proxy_port' => nil,
  654. 'chunked' => true,
  655. }
  656. include TestNetHTTPUtils
  657. def logfile
  658. @debug = StringIO.new('')
  659. end
  660. def mount_proc(&block)
  661. @server.mount('/continue', WEBrick::HTTPServlet::ProcHandler.new(block.to_proc))
  662. end
  663. def test_expect_continue
  664. mount_proc {|req, res|
  665. req.continue
  666. res.body = req.query['body']
  667. }
  668. start {|http|
  669. uheader = {'content-type' => 'application/x-www-form-urlencoded', 'expect' => '100-continue'}
  670. http.continue_timeout = 0.2
  671. http.request_post('/continue', 'body=BODY', uheader) {|res|
  672. assert_equal('BODY', res.read_body)
  673. }
  674. }
  675. assert_match(/Expect: 100-continue/, @debug.string)
  676. assert_match(/HTTP\/1.1 100 continue/, @debug.string)
  677. end
  678. def test_expect_continue_timeout
  679. mount_proc {|req, res|
  680. sleep 0.2
  681. req.continue # just ignored because it's '100'
  682. res.body = req.query['body']
  683. }
  684. start {|http|
  685. uheader = {'content-type' => 'application/x-www-form-urlencoded', 'expect' => '100-continue'}
  686. http.continue_timeout = 0
  687. http.request_post('/continue', 'body=BODY', uheader) {|res|
  688. assert_equal('BODY', res.read_body)
  689. }
  690. }
  691. assert_match(/Expect: 100-continue/, @debug.string)
  692. assert_match(/HTTP\/1.1 100 continue/, @debug.string)
  693. end
  694. def test_expect_continue_error
  695. mount_proc {|req, res|
  696. res.status = 501
  697. res.body = req.query['body']
  698. }
  699. start {|http|
  700. uheader = {'content-type' => 'application/x-www-form-urlencoded', 'expect' => '100-continue'}
  701. http.continue_timeout = 0
  702. http.request_post('/continue', 'body=ERROR', uheader) {|res|
  703. assert_equal('ERROR', res.read_body)
  704. }
  705. }
  706. assert_match(/Expect: 100-continue/, @debug.string)
  707. assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
  708. end
  709. def test_expect_continue_error_before_body
  710. @log_tester = nil
  711. mount_proc {|req, res|
  712. raise WEBrick::HTTPStatus::Forbidden
  713. }
  714. start {|http|
  715. uheader = {'content-length' => '5', 'expect' => '100-continue'}
  716. http.continue_timeout = 1 # allow the server to respond before sending
  717. http.request_post('/continue', 'data', uheader) {|res|
  718. assert_equal(res.code, '403')
  719. }
  720. }
  721. assert_match(/Expect: 100-continue/, @debug.string)
  722. assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
  723. end
  724. def test_expect_continue_error_while_waiting
  725. mount_proc {|req, res|
  726. res.status = 501
  727. res.body = req.query['body']
  728. }
  729. start {|http|
  730. uheader = {'content-type' => 'application/x-www-form-urlencoded', 'expect' => '100-continue'}
  731. http.continue_timeout = 0.5
  732. http.request_post('/continue', 'body=ERROR', uheader) {|res|
  733. assert_equal('ERROR', res.read_body)
  734. }
  735. }
  736. assert_match(/Expect: 100-continue/, @debug.string)
  737. assert_not_match(/HTTP\/1.1 100 continue/, @debug.string)
  738. end
  739. end
  740. class TestNetHTTPKeepAlive < Test::Unit::TestCase
  741. CONFIG = {
  742. 'host' => '127.0.0.1',
  743. 'proxy_host' => nil,
  744. 'proxy_port' => nil,
  745. 'RequestTimeout' => 1,
  746. }
  747. include TestNetHTTPUtils
  748. def test_keep_alive_get_auto_reconnect
  749. start {|http|
  750. res = http.get('/')
  751. http.keep_alive_timeout = 1
  752. assert_kind_of Net::HTTPResponse, res
  753. assert_kind_of String, res.body
  754. sleep 1.5
  755. assert_nothing_raised {
  756. res = http.get('/')
  757. }
  758. assert_kind_of Net::HTTPResponse, res
  759. assert_kind_of String, res.body
  760. }
  761. end
  762. def test_server_closed_connection_auto_reconnect
  763. start {|http|
  764. res = http.get('/')
  765. http.keep_alive_timeout = 5
  766. assert_kind_of Net::HTTPResponse, res
  767. assert_kind_of String, res.body
  768. sleep 1.5
  769. assert_nothing_raised {
  770. # Net::HTTP should detect the closed connection before attempting the
  771. # request, since post requests cannot be retried.
  772. res = http.post('/', 'query=foo', 'content-type' => 'application/x-www-form-urlencoded')
  773. }
  774. assert_kind_of Net::HTTPResponse, res
  775. assert_kind_of String, res.body
  776. }
  777. end
  778. def test_keep_alive_get_auto_retry
  779. start {|http|
  780. res = http.get('/')
  781. http.keep_alive_timeout = 5
  782. assert_kind_of Net::HTTPResponse, res
  783. assert_kind_of String, res.body
  784. sleep 1.5
  785. res = http.get('/')
  786. assert_kind_of Net::HTTPResponse, res
  787. assert_kind_of String, res.body
  788. }
  789. end
  790. def test_keep_alive_server_close
  791. def @server.run(sock)
  792. sock.close
  793. end
  794. start {|http|
  795. assert_raise(EOFError, Errno::ECONNRESET, IOError) {
  796. http.get('/')
  797. }
  798. }
  799. end
  800. end
  801. class TestNetHTTPLocalBind < Test::Unit::TestCase
  802. CONFIG = {
  803. 'host' => 'localhost',
  804. 'proxy_host' => nil,
  805. 'proxy_port' => nil,
  806. }
  807. include TestNetHTTPUtils
  808. def test_bind_to_local_host
  809. @server.mount_proc('/show_ip') { |req, res| res.body = req.remote_ip }
  810. http = Net::HTTP.new(config('host'), config('port'))
  811. http.local_host = Addrinfo.tcp(config('host'), config('port')).ip_address
  812. assert_not_nil(http.local_host)
  813. assert_nil(http.local_port)
  814. res = http.get('/show_ip')
  815. assert_equal(http.local_host, res.body)
  816. end
  817. def test_bind_to_local_port
  818. @server.mount_proc('/show_port') { |req, res| res.body = req.peeraddr[1].to_s }
  819. http = Net::HTTP.new(config('host'), config('port'))
  820. http.local_host = Addrinfo.tcp(config('host'), config('port')).ip_address
  821. http.local_port = Addrinfo.tcp(config('host'), 0).bind {|s|
  822. s.local_address.ip_port.to_s
  823. }
  824. assert_not_nil(http.local_host)
  825. assert_not_nil(http.local_port)
  826. res = http.get('/show_port')
  827. assert_equal(http.local_port, res.body)
  828. end
  829. end