PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/test/net/imap/test_imap.rb

http://github.com/ruby/ruby
Ruby | 843 lines | 794 code | 37 blank | 12 comment | 27 complexity | b154227cc0742f5f68bda81eac963c94 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # frozen_string_literal: true
  2. require "net/imap"
  3. require "test/unit"
  4. class IMAPTest < Test::Unit::TestCase
  5. CA_FILE = File.expand_path("../fixtures/cacert.pem", __dir__)
  6. SERVER_KEY = File.expand_path("../fixtures/server.key", __dir__)
  7. SERVER_CERT = File.expand_path("../fixtures/server.crt", __dir__)
  8. def setup
  9. @do_not_reverse_lookup = Socket.do_not_reverse_lookup
  10. Socket.do_not_reverse_lookup = true
  11. @threads = []
  12. end
  13. def teardown
  14. if !@threads.empty?
  15. assert_join_threads(@threads)
  16. end
  17. ensure
  18. Socket.do_not_reverse_lookup = @do_not_reverse_lookup
  19. end
  20. def test_encode_utf7
  21. assert_equal("foo", Net::IMAP.encode_utf7("foo"))
  22. assert_equal("&-", Net::IMAP.encode_utf7("&"))
  23. utf8 = "\357\274\241\357\274\242\357\274\243".dup.force_encoding("UTF-8")
  24. s = Net::IMAP.encode_utf7(utf8)
  25. assert_equal("&,yH,Iv8j-", s)
  26. s = Net::IMAP.encode_utf7("foo&#{utf8}-bar".encode("EUC-JP"))
  27. assert_equal("foo&-&,yH,Iv8j--bar", s)
  28. utf8 = "\343\201\202&".dup.force_encoding("UTF-8")
  29. s = Net::IMAP.encode_utf7(utf8)
  30. assert_equal("&MEI-&-", s)
  31. s = Net::IMAP.encode_utf7(utf8.encode("EUC-JP"))
  32. assert_equal("&MEI-&-", s)
  33. end
  34. def test_decode_utf7
  35. assert_equal("&", Net::IMAP.decode_utf7("&-"))
  36. assert_equal("&-", Net::IMAP.decode_utf7("&--"))
  37. s = Net::IMAP.decode_utf7("&,yH,Iv8j-")
  38. utf8 = "\357\274\241\357\274\242\357\274\243".dup.force_encoding("UTF-8")
  39. assert_equal(utf8, s)
  40. end
  41. def test_format_date
  42. time = Time.mktime(2009, 7, 24)
  43. s = Net::IMAP.format_date(time)
  44. assert_equal("24-Jul-2009", s)
  45. end
  46. def test_format_datetime
  47. time = Time.mktime(2009, 7, 24, 1, 23, 45)
  48. s = Net::IMAP.format_datetime(time)
  49. assert_match(/\A24-Jul-2009 01:23 [+\-]\d{4}\z/, s)
  50. end
  51. if defined?(OpenSSL::SSL::SSLError)
  52. def test_imaps_unknown_ca
  53. assert_raise(OpenSSL::SSL::SSLError) do
  54. imaps_test do |port|
  55. begin
  56. Net::IMAP.new("localhost",
  57. :port => port,
  58. :ssl => true)
  59. rescue SystemCallError
  60. skip $!
  61. end
  62. end
  63. end
  64. end
  65. def test_imaps_with_ca_file
  66. assert_nothing_raised do
  67. imaps_test do |port|
  68. begin
  69. Net::IMAP.new("localhost",
  70. :port => port,
  71. :ssl => { :ca_file => CA_FILE })
  72. rescue SystemCallError
  73. skip $!
  74. end
  75. end
  76. end
  77. end
  78. def test_imaps_verify_none
  79. assert_nothing_raised do
  80. imaps_test do |port|
  81. Net::IMAP.new(server_addr,
  82. :port => port,
  83. :ssl => { :verify_mode => OpenSSL::SSL::VERIFY_NONE })
  84. end
  85. end
  86. end
  87. def test_imaps_post_connection_check
  88. assert_raise(OpenSSL::SSL::SSLError) do
  89. imaps_test do |port|
  90. # server_addr is different from the hostname in the certificate,
  91. # so the following code should raise a SSLError.
  92. Net::IMAP.new(server_addr,
  93. :port => port,
  94. :ssl => { :ca_file => CA_FILE })
  95. end
  96. end
  97. end
  98. end
  99. if defined?(OpenSSL::SSL)
  100. def test_starttls
  101. imap = nil
  102. starttls_test do |port|
  103. imap = Net::IMAP.new("localhost", :port => port)
  104. imap.starttls(:ca_file => CA_FILE)
  105. imap
  106. end
  107. rescue SystemCallError
  108. skip $!
  109. ensure
  110. if imap && !imap.disconnected?
  111. imap.disconnect
  112. end
  113. end
  114. end
  115. def start_server
  116. th = Thread.new do
  117. yield
  118. end
  119. @threads << th
  120. sleep 0.1 until th.stop?
  121. end
  122. def test_unexpected_eof
  123. server = create_tcp_server
  124. port = server.addr[1]
  125. start_server do
  126. sock = server.accept
  127. begin
  128. sock.print("* OK test server\r\n")
  129. sock.gets
  130. # sock.print("* BYE terminating connection\r\n")
  131. # sock.print("RUBY0001 OK LOGOUT completed\r\n")
  132. ensure
  133. sock.close
  134. server.close
  135. end
  136. end
  137. begin
  138. imap = Net::IMAP.new(server_addr, :port => port)
  139. assert_raise(EOFError) do
  140. imap.logout
  141. end
  142. ensure
  143. imap.disconnect if imap
  144. end
  145. end
  146. def test_idle
  147. server = create_tcp_server
  148. port = server.addr[1]
  149. requests = []
  150. start_server do
  151. sock = server.accept
  152. begin
  153. sock.print("* OK test server\r\n")
  154. requests.push(sock.gets)
  155. sock.print("+ idling\r\n")
  156. sock.print("* 3 EXISTS\r\n")
  157. sock.print("* 2 EXPUNGE\r\n")
  158. requests.push(sock.gets)
  159. sock.print("RUBY0001 OK IDLE terminated\r\n")
  160. sock.gets
  161. sock.print("* BYE terminating connection\r\n")
  162. sock.print("RUBY0002 OK LOGOUT completed\r\n")
  163. ensure
  164. sock.close
  165. server.close
  166. end
  167. end
  168. begin
  169. imap = Net::IMAP.new(server_addr, :port => port)
  170. responses = []
  171. imap.idle do |res|
  172. responses.push(res)
  173. if res.name == "EXPUNGE"
  174. imap.idle_done
  175. end
  176. end
  177. assert_equal(3, responses.length)
  178. assert_instance_of(Net::IMAP::ContinuationRequest, responses[0])
  179. assert_equal("EXISTS", responses[1].name)
  180. assert_equal(3, responses[1].data)
  181. assert_equal("EXPUNGE", responses[2].name)
  182. assert_equal(2, responses[2].data)
  183. assert_equal(2, requests.length)
  184. assert_equal("RUBY0001 IDLE\r\n", requests[0])
  185. assert_equal("DONE\r\n", requests[1])
  186. imap.logout
  187. ensure
  188. imap.disconnect if imap
  189. end
  190. end
  191. def test_exception_during_idle
  192. server = create_tcp_server
  193. port = server.addr[1]
  194. requests = []
  195. start_server do
  196. sock = server.accept
  197. begin
  198. sock.print("* OK test server\r\n")
  199. requests.push(sock.gets)
  200. sock.print("+ idling\r\n")
  201. sock.print("* 3 EXISTS\r\n")
  202. sock.print("* 2 EXPUNGE\r\n")
  203. requests.push(sock.gets)
  204. sock.print("RUBY0001 OK IDLE terminated\r\n")
  205. sock.gets
  206. sock.print("* BYE terminating connection\r\n")
  207. sock.print("RUBY0002 OK LOGOUT completed\r\n")
  208. ensure
  209. sock.close
  210. server.close
  211. end
  212. end
  213. begin
  214. imap = Net::IMAP.new(server_addr, :port => port)
  215. begin
  216. th = Thread.current
  217. m = Monitor.new
  218. in_idle = false
  219. exception_raised = false
  220. c = m.new_cond
  221. raiser = Thread.start do
  222. m.synchronize do
  223. until in_idle
  224. c.wait(0.1)
  225. end
  226. end
  227. th.raise(Interrupt)
  228. m.synchronize do
  229. exception_raised = true
  230. c.signal
  231. end
  232. end
  233. @threads << raiser
  234. imap.idle do |res|
  235. m.synchronize do
  236. in_idle = true
  237. c.signal
  238. until exception_raised
  239. c.wait(0.1)
  240. end
  241. end
  242. end
  243. rescue Interrupt
  244. end
  245. assert_equal(2, requests.length)
  246. assert_equal("RUBY0001 IDLE\r\n", requests[0])
  247. assert_equal("DONE\r\n", requests[1])
  248. imap.logout
  249. ensure
  250. imap.disconnect if imap
  251. raiser.kill unless in_idle
  252. end
  253. end
  254. def test_idle_done_not_during_idle
  255. server = create_tcp_server
  256. port = server.addr[1]
  257. start_server do
  258. sock = server.accept
  259. begin
  260. sock.print("* OK test server\r\n")
  261. ensure
  262. sock.close
  263. server.close
  264. end
  265. end
  266. begin
  267. imap = Net::IMAP.new(server_addr, :port => port)
  268. assert_raise(Net::IMAP::Error) do
  269. imap.idle_done
  270. end
  271. ensure
  272. imap.disconnect if imap
  273. end
  274. end
  275. def test_idle_timeout
  276. server = create_tcp_server
  277. port = server.addr[1]
  278. requests = []
  279. start_server do
  280. sock = server.accept
  281. begin
  282. sock.print("* OK test server\r\n")
  283. requests.push(sock.gets)
  284. sock.print("+ idling\r\n")
  285. sock.print("* 3 EXISTS\r\n")
  286. sock.print("* 2 EXPUNGE\r\n")
  287. requests.push(sock.gets)
  288. sock.print("RUBY0001 OK IDLE terminated\r\n")
  289. sock.gets
  290. sock.print("* BYE terminating connection\r\n")
  291. sock.print("RUBY0002 OK LOGOUT completed\r\n")
  292. ensure
  293. sock.close
  294. server.close
  295. end
  296. end
  297. begin
  298. imap = Net::IMAP.new(server_addr, :port => port)
  299. responses = []
  300. Thread.pass
  301. imap.idle(0.2) do |res|
  302. responses.push(res)
  303. end
  304. # There is no guarantee that this thread has received all the responses,
  305. # so check the response length.
  306. if responses.length > 0
  307. assert_instance_of(Net::IMAP::ContinuationRequest, responses[0])
  308. if responses.length > 1
  309. assert_equal("EXISTS", responses[1].name)
  310. assert_equal(3, responses[1].data)
  311. if responses.length > 2
  312. assert_equal("EXPUNGE", responses[2].name)
  313. assert_equal(2, responses[2].data)
  314. end
  315. end
  316. end
  317. # Also, there is no guarantee that the server thread has stored
  318. # all the requests into the array, so check the length.
  319. if requests.length > 0
  320. assert_equal("RUBY0001 IDLE\r\n", requests[0])
  321. if requests.length > 1
  322. assert_equal("DONE\r\n", requests[1])
  323. end
  324. end
  325. imap.logout
  326. ensure
  327. imap.disconnect if imap
  328. end
  329. end
  330. def test_unexpected_bye
  331. server = create_tcp_server
  332. port = server.addr[1]
  333. start_server do
  334. sock = server.accept
  335. begin
  336. sock.print("* OK Gimap ready for requests from 75.101.246.151 33if2752585qyk.26\r\n")
  337. sock.gets
  338. sock.print("* BYE System Error 33if2752585qyk.26\r\n")
  339. ensure
  340. sock.close
  341. server.close
  342. end
  343. end
  344. begin
  345. imap = Net::IMAP.new(server_addr, :port => port)
  346. assert_raise(Net::IMAP::ByeResponseError) do
  347. imap.login("user", "password")
  348. end
  349. end
  350. end
  351. def test_exception_during_shutdown
  352. server = create_tcp_server
  353. port = server.addr[1]
  354. start_server do
  355. sock = server.accept
  356. begin
  357. sock.print("* OK test server\r\n")
  358. sock.gets
  359. sock.print("* BYE terminating connection\r\n")
  360. sock.print("RUBY0001 OK LOGOUT completed\r\n")
  361. ensure
  362. sock.close
  363. server.close
  364. end
  365. end
  366. begin
  367. imap = Net::IMAP.new(server_addr, :port => port)
  368. imap.instance_eval do
  369. def @sock.shutdown(*args)
  370. super
  371. ensure
  372. raise "error"
  373. end
  374. end
  375. imap.logout
  376. ensure
  377. assert_raise(RuntimeError) do
  378. imap.disconnect
  379. end
  380. end
  381. end
  382. def test_connection_closed_during_idle
  383. server = create_tcp_server
  384. port = server.addr[1]
  385. requests = []
  386. sock = nil
  387. threads = []
  388. started = false
  389. threads << Thread.start do
  390. started = true
  391. begin
  392. sock = server.accept
  393. sock.print("* OK test server\r\n")
  394. requests.push(sock.gets)
  395. sock.print("+ idling\r\n")
  396. rescue IOError # sock is closed by another thread
  397. ensure
  398. server.close
  399. end
  400. end
  401. sleep 0.1 until started
  402. threads << Thread.start do
  403. imap = Net::IMAP.new(server_addr, :port => port)
  404. begin
  405. m = Monitor.new
  406. in_idle = false
  407. closed = false
  408. c = m.new_cond
  409. threads << Thread.start do
  410. m.synchronize do
  411. until in_idle
  412. c.wait(0.1)
  413. end
  414. end
  415. sock.close
  416. m.synchronize do
  417. closed = true
  418. c.signal
  419. end
  420. end
  421. assert_raise(EOFError) do
  422. imap.idle do |res|
  423. m.synchronize do
  424. in_idle = true
  425. c.signal
  426. until closed
  427. c.wait(0.1)
  428. end
  429. end
  430. end
  431. end
  432. assert_equal(1, requests.length)
  433. assert_equal("RUBY0001 IDLE\r\n", requests[0])
  434. ensure
  435. imap.disconnect if imap
  436. end
  437. end
  438. assert_join_threads(threads)
  439. ensure
  440. if sock && !sock.closed?
  441. sock.close
  442. end
  443. end
  444. def test_connection_closed_without_greeting
  445. server = create_tcp_server
  446. port = server.addr[1]
  447. h = {
  448. server: server,
  449. port: port,
  450. server_created: {
  451. server: server.inspect,
  452. t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
  453. }
  454. }
  455. net_imap = Class.new(Net::IMAP) do
  456. @@h = h
  457. def tcp_socket(host, port)
  458. @@h[:in_tcp_socket] = {
  459. host: host,
  460. port: port,
  461. server: @@h[:server].inspect,
  462. t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
  463. }
  464. #super
  465. s = Socket.tcp(host, port, :connect_timeout => @open_timeout)
  466. @@h[:in_tcp_socket_2] = {
  467. s: s.inspect,
  468. local_address: s.local_address,
  469. remote_address: s.remote_address,
  470. t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
  471. }
  472. s.setsockopt(:SOL_SOCKET, :SO_KEEPALIVE, true)
  473. s
  474. end
  475. end
  476. start_server do
  477. begin
  478. h[:in_start_server_before_accept] = {
  479. t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
  480. }
  481. sock = server.accept
  482. h[:in_start_server] = {
  483. sock_addr: sock.addr,
  484. sock_peeraddr: sock.peeraddr,
  485. t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
  486. }
  487. sock.close
  488. h[:in_start_server_sock_closed] = {
  489. t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
  490. }
  491. ensure
  492. server.close
  493. end
  494. end
  495. assert_raise(Net::IMAP::Error) do
  496. #Net::IMAP.new(server_addr, :port => port)
  497. if true
  498. net_imap.new(server_addr, :port => port)
  499. else
  500. # for testing debug print
  501. begin
  502. net_imap.new(server_addr, :port => port)
  503. rescue Net::IMAP::Error
  504. raise Errno::EINVAL
  505. end
  506. end
  507. rescue SystemCallError => e # for debug on OpenCSW
  508. h[:in_rescue] = {
  509. e: e,
  510. server_addr: server_addr,
  511. t: Process.clock_gettime(Process::CLOCK_MONOTONIC),
  512. }
  513. require 'pp'
  514. raise(PP.pp(h, +''))
  515. end
  516. end
  517. def test_default_port
  518. assert_equal(143, Net::IMAP.default_port)
  519. assert_equal(143, Net::IMAP.default_imap_port)
  520. assert_equal(993, Net::IMAP.default_tls_port)
  521. assert_equal(993, Net::IMAP.default_ssl_port)
  522. assert_equal(993, Net::IMAP.default_imaps_port)
  523. end
  524. def test_send_invalid_number
  525. server = create_tcp_server
  526. port = server.addr[1]
  527. start_server do
  528. sock = server.accept
  529. begin
  530. sock.print("* OK test server\r\n")
  531. sock.gets
  532. sock.print("RUBY0001 OK TEST completed\r\n")
  533. sock.gets
  534. sock.print("RUBY0002 OK TEST completed\r\n")
  535. sock.gets
  536. sock.print("RUBY0003 OK TEST completed\r\n")
  537. sock.gets
  538. sock.print("RUBY0004 OK TEST completed\r\n")
  539. sock.gets
  540. sock.print("* BYE terminating connection\r\n")
  541. sock.print("RUBY0005 OK LOGOUT completed\r\n")
  542. ensure
  543. sock.close
  544. server.close
  545. end
  546. end
  547. begin
  548. imap = Net::IMAP.new(server_addr, :port => port)
  549. assert_raise(Net::IMAP::DataFormatError) do
  550. imap.send(:send_command, "TEST", -1)
  551. end
  552. imap.send(:send_command, "TEST", 0)
  553. imap.send(:send_command, "TEST", 4294967295)
  554. assert_raise(Net::IMAP::DataFormatError) do
  555. imap.send(:send_command, "TEST", 4294967296)
  556. end
  557. assert_raise(Net::IMAP::DataFormatError) do
  558. imap.send(:send_command, "TEST", Net::IMAP::MessageSet.new(-1))
  559. end
  560. assert_raise(Net::IMAP::DataFormatError) do
  561. imap.send(:send_command, "TEST", Net::IMAP::MessageSet.new(0))
  562. end
  563. imap.send(:send_command, "TEST", Net::IMAP::MessageSet.new(1))
  564. imap.send(:send_command, "TEST", Net::IMAP::MessageSet.new(4294967295))
  565. assert_raise(Net::IMAP::DataFormatError) do
  566. imap.send(:send_command, "TEST", Net::IMAP::MessageSet.new(4294967296))
  567. end
  568. imap.logout
  569. ensure
  570. imap.disconnect
  571. end
  572. end
  573. def test_send_literal
  574. server = create_tcp_server
  575. port = server.addr[1]
  576. requests = []
  577. literal = nil
  578. start_server do
  579. sock = server.accept
  580. begin
  581. sock.print("* OK test server\r\n")
  582. line = sock.gets
  583. requests.push(line)
  584. size = line.slice(/{(\d+)}\r\n/, 1).to_i
  585. sock.print("+ Ready for literal data\r\n")
  586. literal = sock.read(size)
  587. requests.push(sock.gets)
  588. sock.print("RUBY0001 OK TEST completed\r\n")
  589. sock.gets
  590. sock.print("* BYE terminating connection\r\n")
  591. sock.print("RUBY0002 OK LOGOUT completed\r\n")
  592. ensure
  593. sock.close
  594. server.close
  595. end
  596. end
  597. begin
  598. imap = Net::IMAP.new(server_addr, :port => port)
  599. imap.send(:send_command, "TEST", ["\xDE\xAD\xBE\xEF".b])
  600. assert_equal(2, requests.length)
  601. assert_equal("RUBY0001 TEST ({4}\r\n", requests[0])
  602. assert_equal("\xDE\xAD\xBE\xEF".b, literal)
  603. assert_equal(")\r\n", requests[1])
  604. imap.logout
  605. ensure
  606. imap.disconnect
  607. end
  608. end
  609. def test_disconnect
  610. server = create_tcp_server
  611. port = server.addr[1]
  612. start_server do
  613. sock = server.accept
  614. begin
  615. sock.print("* OK test server\r\n")
  616. sock.gets
  617. sock.print("* BYE terminating connection\r\n")
  618. sock.print("RUBY0001 OK LOGOUT completed\r\n")
  619. ensure
  620. sock.close
  621. server.close
  622. end
  623. end
  624. begin
  625. imap = Net::IMAP.new(server_addr, :port => port)
  626. imap.logout
  627. imap.disconnect
  628. assert_equal(true, imap.disconnected?)
  629. imap.disconnect
  630. assert_equal(true, imap.disconnected?)
  631. ensure
  632. imap.disconnect if imap && !imap.disconnected?
  633. end
  634. end
  635. def test_append
  636. server = create_tcp_server
  637. port = server.addr[1]
  638. mail = <<EOF.gsub(/\n/, "\r\n")
  639. From: shugo@example.com
  640. To: matz@example.com
  641. Subject: hello
  642. hello world
  643. EOF
  644. requests = []
  645. received_mail = nil
  646. start_server do
  647. sock = server.accept
  648. begin
  649. sock.print("* OK test server\r\n")
  650. line = sock.gets
  651. requests.push(line)
  652. size = line.slice(/{(\d+)}\r\n/, 1).to_i
  653. sock.print("+ Ready for literal data\r\n")
  654. received_mail = sock.read(size)
  655. sock.gets
  656. sock.print("RUBY0001 OK APPEND completed\r\n")
  657. requests.push(sock.gets)
  658. sock.print("* BYE terminating connection\r\n")
  659. sock.print("RUBY0002 OK LOGOUT completed\r\n")
  660. ensure
  661. sock.close
  662. server.close
  663. end
  664. end
  665. begin
  666. imap = Net::IMAP.new(server_addr, :port => port)
  667. imap.append("INBOX", mail)
  668. assert_equal(1, requests.length)
  669. assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
  670. assert_equal(mail, received_mail)
  671. imap.logout
  672. assert_equal(2, requests.length)
  673. assert_equal("RUBY0002 LOGOUT\r\n", requests[1])
  674. ensure
  675. imap.disconnect if imap
  676. end
  677. end
  678. def test_append_fail
  679. server = create_tcp_server
  680. port = server.addr[1]
  681. mail = <<EOF.gsub(/\n/, "\r\n")
  682. From: shugo@example.com
  683. To: matz@example.com
  684. Subject: hello
  685. hello world
  686. EOF
  687. requests = []
  688. start_server do
  689. sock = server.accept
  690. begin
  691. sock.print("* OK test server\r\n")
  692. requests.push(sock.gets)
  693. sock.print("RUBY0001 NO Mailbox doesn't exist\r\n")
  694. requests.push(sock.gets)
  695. sock.print("* BYE terminating connection\r\n")
  696. sock.print("RUBY0002 OK LOGOUT completed\r\n")
  697. ensure
  698. sock.close
  699. server.close
  700. end
  701. end
  702. begin
  703. imap = Net::IMAP.new(server_addr, :port => port)
  704. assert_raise(Net::IMAP::NoResponseError) do
  705. imap.append("INBOX", mail)
  706. end
  707. assert_equal(1, requests.length)
  708. assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
  709. imap.logout
  710. assert_equal(2, requests.length)
  711. assert_equal("RUBY0002 LOGOUT\r\n", requests[1])
  712. ensure
  713. imap.disconnect if imap
  714. end
  715. end
  716. private
  717. def imaps_test
  718. server = create_tcp_server
  719. port = server.addr[1]
  720. ctx = OpenSSL::SSL::SSLContext.new
  721. ctx.ca_file = CA_FILE
  722. ctx.key = File.open(SERVER_KEY) { |f|
  723. OpenSSL::PKey::RSA.new(f)
  724. }
  725. ctx.cert = File.open(SERVER_CERT) { |f|
  726. OpenSSL::X509::Certificate.new(f)
  727. }
  728. ssl_server = OpenSSL::SSL::SSLServer.new(server, ctx)
  729. started = false
  730. ths = Thread.start do
  731. Thread.current.report_on_exception = false # always join-ed
  732. begin
  733. started = true
  734. sock = ssl_server.accept
  735. begin
  736. sock.print("* OK test server\r\n")
  737. sock.gets
  738. sock.print("* BYE terminating connection\r\n")
  739. sock.print("RUBY0001 OK LOGOUT completed\r\n")
  740. ensure
  741. sock.close
  742. end
  743. rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
  744. end
  745. end
  746. sleep 0.1 until started
  747. begin
  748. begin
  749. imap = yield(port)
  750. imap.logout
  751. ensure
  752. imap.disconnect if imap
  753. end
  754. ensure
  755. ssl_server.close
  756. ths.join
  757. end
  758. end
  759. def starttls_test
  760. server = create_tcp_server
  761. port = server.addr[1]
  762. start_server do
  763. sock = server.accept
  764. begin
  765. sock.print("* OK test server\r\n")
  766. sock.gets
  767. sock.print("RUBY0001 OK completed\r\n")
  768. ctx = OpenSSL::SSL::SSLContext.new
  769. ctx.ca_file = CA_FILE
  770. ctx.key = File.open(SERVER_KEY) { |f|
  771. OpenSSL::PKey::RSA.new(f)
  772. }
  773. ctx.cert = File.open(SERVER_CERT) { |f|
  774. OpenSSL::X509::Certificate.new(f)
  775. }
  776. sock = OpenSSL::SSL::SSLSocket.new(sock, ctx)
  777. sock.sync_close = true
  778. sock.accept
  779. sock.gets
  780. sock.print("* BYE terminating connection\r\n")
  781. sock.print("RUBY0002 OK LOGOUT completed\r\n")
  782. ensure
  783. sock.close
  784. server.close
  785. end
  786. end
  787. begin
  788. imap = yield(port)
  789. imap.logout if !imap.disconnected?
  790. ensure
  791. imap.disconnect if imap && !imap.disconnected?
  792. end
  793. end
  794. def create_tcp_server
  795. return TCPServer.new(server_addr, 0)
  796. end
  797. def server_addr
  798. Addrinfo.tcp("localhost", 0).ip_address
  799. end
  800. end