diff options
-rw-r--r-- | sample/rss/tdiary_plugin/rss-recent.rb | 211 | ||||
-rw-r--r-- | test/openssl/ssl_server.rb | 77 | ||||
-rw-r--r-- | test/openssl/test_ssl.rb | 192 |
3 files changed, 480 insertions, 0 deletions
diff --git a/sample/rss/tdiary_plugin/rss-recent.rb b/sample/rss/tdiary_plugin/rss-recent.rb new file mode 100644 index 0000000000..8ba8ed0b52 --- /dev/null +++ b/sample/rss/tdiary_plugin/rss-recent.rb @@ -0,0 +1,211 @@ +# rss-recent.rb: RSS recent plugin +# +# rss_recnet: show recnet list from RSS +# parameters (default): +# url: URL of RSS +# max: max of list itmes(5) +# cache_time: cache time(second) of RSS(60*60) +# +# +# Copyright (c) 2003-2004 Kouhei Sutou <kou@cozmixng.org> +# Distributed under the GPL +# + +require "rss/rss" + +RSS_RECENT_FIELD_SEPARATOR = "\0" +RSS_RECENT_ENTRY_SEPARATOR = "\1" +RSS_RECENT_VERSION = "0.0.4" +RSS_RECENT_HTTP_HEADER = { + "User-Agent" => "tDiary RSS recent plugin version #{RSS_RECENT_VERSION}. " << + "Using RSS parser version is #{::RSS::VERSION}.", +} + +def rss_recent(url, max=5, cache_time=3600) + cache_file = "#{@cache_path}/rss-recent.#{CGI.escape(url)}" + + rss_recent_cache_rss(url, cache_file, cache_time.to_i) + + return '' unless test(?r, cache_file) + + rv = "<ul>\n" + + i = 0 + rss_recent_read_from_cache(cache_file).each do |title, url, time| + break if i >= max + next if title.nil? + rv << '<li>' + rv << %Q[<span class="#{rss_recent_modified_class(time)}">] + unless url.nil? + rv << %Q[<a href="#{CGI.escapeHTML(url)}" title="#{CGI.escapeHTML(title)}] + rv << %Q[ (#{CGI.escapeHTML(time.localtime.to_s)})] unless time.nil? + rv << %Q[">] + end + rv << CGI::escapeHTML(title) + rv << '</a>' unless url.nil? + rv << "(#{rss_recent_modified(time)})" + rv << %Q[</span>] + rv << "</li>\n" + i += 1 + end + + rv << "</ul>\n" + + rv +end + +class InvalidResourceError < StandardError; end + +def rss_recent_cache_rss(url, cache_file, cache_time) + + cached_time = nil + cached_time = File.mtime(cache_file) if File.exist?(cache_file) + + if cached_time.nil? or Time.now > cached_time + cache_time + require 'time' + require 'open-uri' + require 'net/http' + require 'uri/generic' + require 'rss/parser' + require 'rss/1.0' + require 'rss/2.0' + require 'rss/dublincore' + + begin + uri = URI.parse(url) + + raise URI::InvalidURIError if uri.scheme != "http" + + rss_source = rss_recent_fetch_rss(uri, cached_time) + + raise InvalidResourceError if rss_source.nil? + + # parse RSS + rss = ::RSS::Parser.parse(rss_source, false) + raise ::RSS::Error if rss.nil? + + # pre processing + begin + rss.output_encoding = charset + rescue ::RSS::UnknownConversionMethodError + end + + rss_infos = rss.items.collect do |item| + rss_recent_pubDate_to_dc_date(item) + [item.title, item.link, item.dc_date] + end + rss_recent_write_to_cache(cache_file, rss_infos) + + rescue URI::InvalidURIError + rss_recent_write_to_cache(cache_file, [['Invalid URI', url]]) + rescue InvalidResourceError, ::RSS::Error + rss_recent_write_to_cache(cache_file, [['Invalid Resource', url]]) + end + end + +end + +def rss_recent_fetch_rss(uri, cache_time) + rss = nil + begin + uri.open(rss_recent_http_header(cache_time)) do |f| + case f.status.first + when "200" + rss = f.read + # STDERR.puts "Got RSS of #{uri}" + when "304" + # not modified + # STDERR.puts "#{uri} does not modified" + else + raise InvalidResourceError + end + end + rescue TimeoutError, SocketError, StandardError, + SecurityError # occured in redirect + raise InvalidResourceError + end + rss +end + +def rss_recent_http_header(cache_time) + header = RSS_RECENT_HTTP_HEADER.dup + if cache_time.respond_to?(:rfc2822) + header["If-Modified-Since"] = cache_time.rfc2822 + end + header +end + +def rss_recent_write_to_cache(cache_file, rss_infos) + File.open(cache_file, 'w') do |f| + f.flock(File::LOCK_EX) + rss_infos.each do |info| + f << info.join(RSS_RECENT_FIELD_SEPARATOR) + f << RSS_RECENT_ENTRY_SEPARATOR + end + f.flock(File::LOCK_UN) + end +end + +def rss_recent_read_from_cache(cache_file) + require 'time' + infos = [] + File.open(cache_file) do |f| + while info = f.gets(RSS_RECENT_ENTRY_SEPARATOR) + info = info.chomp(RSS_RECENT_ENTRY_SEPARATOR) + infos << info.split(RSS_RECENT_FIELD_SEPARATOR) + end + end + infos.collect do |title, url, time| + [ + rss_recent_convert(title), + rss_recent_convert(url), + rss_recent_convert(time) {|time| Time.parse(time)}, + ] + end +end + +def rss_recent_convert(str) + if str.nil? or str.empty? + nil + else + if block_given? + yield str + else + str + end + end +end + +# from RWiki +def rss_recent_modified(t) + return '-' unless t + dif = (Time.now - t).to_i + dif = dif / 60 + return "#{dif}m" if dif <= 60 + dif = dif / 60 + return "#{dif}h" if dif <= 24 + dif = dif / 24 + return "#{dif}d" +end + +# from RWiki +def rss_recent_modified_class(t) + return 'dangling' unless t + dif = (Time.now - t).to_i + dif = dif / 60 + return "modified-hour" if dif <= 60 + dif = dif / 60 + return "modified-today" if dif <= 24 + dif = dif / 24 + return "modified-month" if dif <= 30 + return "modified-year" if dif <= 365 + return "modified-old" +end + +def rss_recent_pubDate_to_dc_date(target) + if target.respond_to?(:pubDate) + class << target + alias_method(:dc_date, :pubDate) + end + end +end diff --git a/test/openssl/ssl_server.rb b/test/openssl/ssl_server.rb new file mode 100644 index 0000000000..ce3c6132cd --- /dev/null +++ b/test/openssl/ssl_server.rb @@ -0,0 +1,77 @@ +require "socket" +require "thread" +require "openssl" +require File.join(File.dirname(__FILE__), "utils.rb") + +def get_pem(io=$stdin) + buf = "" + while line = io.gets + if /^-----BEGIN / =~ line + buf << line + break + end + end + while line = io.gets + buf << line + if /^-----END / =~ line + break + end + end + return buf +end + +def make_key(pem) + begin + return OpenSSL::PKey::RSA.new(pem) + rescue + return OpenSSL::PKey::DSA.new(pem) + end +end + +ca_cert = OpenSSL::X509::Certificate.new(get_pem) +ssl_cert = OpenSSL::X509::Certificate.new(get_pem) +ssl_key = make_key(get_pem) +port = Integer(ARGV.shift) +verify_mode = Integer(ARGV.shift) +start_immediately = (/yes/ =~ ARGV.shift) + +store = OpenSSL::X509::Store.new +store.add_cert(ca_cert) +store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT +ctx = OpenSSL::SSL::SSLContext.new +ctx.cert_store = store +#ctx.extra_chain_cert = [ ca_cert ] +ctx.cert = ssl_cert +ctx.key = ssl_key +ctx.verify_mode = verify_mode + +Socket.do_not_reverse_lookup = true +tcps = TCPServer.new("0.0.0.0", port) +ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx) +ssls.start_immediately = start_immediately + +Thread.start{ + while true + $stdin.gets || exit + end +} + +$stdout.sync = true +$stdout.puts Process.pid + +loop do + ssl = ssls.accept + Thread.start{ + q = Queue.new + th = Thread.start{ ssl.write(q.shift) while true } + while line = ssl.gets + if line =~ /^STARTTLS$/ + ssl.accept + next + end + q.push(line) + end + th.kill if q.empty? + ssl.close + } +end diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb new file mode 100644 index 0000000000..3ca25cbfe1 --- /dev/null +++ b/test/openssl/test_ssl.rb @@ -0,0 +1,192 @@ +begin + require "openssl" + require File.join(File.dirname(__FILE__), "utils.rb") +rescue LoadError +end +require "rbconfig" +require "socket" +require "test/unit" + +if defined?(OpenSSL) + +class OpenSSL::TestSSL < Test::Unit::TestCase + RUBY = ENV["RUBY"] || File.join( + ::Config::CONFIG["bindir"], + ::Config::CONFIG["ruby_install_name"] + ::Config::CONFIG["EXEEXT"] + ) + SSL_SERVER = File.join(File.dirname(__FILE__), "ssl_server.rb") + PORT = 20443 + ITERATIONS = ($0 == __FILE__) ? 100 : 10 + + def setup + @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA2048 + @svr_key = OpenSSL::TestUtils::TEST_KEY_RSA1024 + @cli_key = OpenSSL::TestUtils::TEST_KEY_DSA256 + @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA") + @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost") + + now = Time.at(Time.now.to_i) + ca_exts = [ + ["basicConstraints","CA:TRUE",true], + ["keyUsage","cRLSign,keyCertSign",true], + ] + ee_exts = [ + ["keyUsage","keyEncipherment,digitalSignature",true], + ] + @ca_cert = issue_cert(@ca, @ca_key, 1, now, now+3600, ca_exts, + nil, nil, OpenSSL::Digest::SHA1.new) + @svr_cert = issue_cert(@svr, @svr_key, 2, now, now+1800, ee_exts, + @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + @cli_cert = issue_cert(@cli, @cli_key, 3, now, now+1800, ee_exts, + @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new) + @server = nil + end + + def teardown + end + + def issue_cert(*arg) + OpenSSL::TestUtils.issue_cert(*arg) + end + + def issue_crl(*arg) + OpenSSL::TestUtils.issue_crl(*arg) + end + + def start_server(port, verify_mode, start_immediately, &block) + server = nil + begin + cmd = [RUBY] + cmd << "-d" if $DEBUG + cmd << SSL_SERVER << port.to_s << verify_mode.to_s + cmd << (start_immediately ? "yes" : "no") + server = IO.popen(cmd, "w+") + server.write(@ca_cert.to_pem) + server.write(@svr_cert.to_pem) + server.write(@svr_key.to_pem) + pid = Integer(server.gets) + $stderr.printf("%s started: pid=%d\n", SSL_SERVER, pid) if $DEBUG + block.call(server) + ensure + if server + server.close_write + Process.kill(:TERM, pid) rescue nil + Process.waitpid(pid) + end + end + end + + def starttls(ssl) + ssl.puts("STARTTLS") + ssl.connect + end + + def test_connect_and_close + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){ + sock = TCPSocket.new("127.0.0.1", PORT) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + assert(ssl.connect) + ssl.close + assert(!sock.closed?) + sock.close + + sock = TCPSocket.new("127.0.0.1", PORT) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true # !! + assert(ssl.connect) + ssl.close + assert(sock.closed?) + } + end + + def test_read_and_write + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){ + sock = TCPSocket.new("127.0.0.1", PORT) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + ssl.connect + + # syswrite and sysread + ITERATIONS.times{|i| + str = "x" * 100 + "\n" + ssl.syswrite(str) + assert_equal(str, ssl.sysread(str.size)) + + str = "x" * i * 100 + "\n" + buf = "" + ssl.syswrite(str) + assert_equal(buf.object_id, ssl.sysread(str.size, buf).object_id) + assert_equal(str, buf) + } + + # puts and gets + ITERATIONS.times{ + str = "x" * 100 + "\n" + ssl.puts(str) + assert_equal(str, ssl.gets) + } + + # read and write + ITERATIONS.times{|i| + str = "x" * 100 + "\n" + ssl.write(str) + assert_equal(str, ssl.read(str.size)) + + str = "x" * i * 100 + "\n" + buf = "" + ssl.write(str) + assert_equal(buf.object_id, ssl.read(str.size, buf).object_id) + assert_equal(str, buf) + } + + ssl.close + } + end + + def test_starttls + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, false){|s| + sock = TCPSocket.new("127.0.0.1", PORT) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.sync_close = true + str = "x" * 1000 + "\n" + + ITERATIONS.times{ + ssl.puts(str) + assert_equal(str, ssl.gets) + } + + starttls(ssl) + + ITERATIONS.times{ + ssl.puts(str) + assert_equal(str, ssl.gets) + } + + ssl.close + } + end + + def test_parallel + start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){ + ssls = [] + 10.times{ + sock = TCPSocket.new("127.0.0.1", PORT) + ssl = OpenSSL::SSL::SSLSocket.new(sock) + ssl.connect + ssl.sync_close = true + ssls << ssl + } + str = "x" * 1000 + "\n" + ITERATIONS.times{ + ssls.each{|ssl| + ssl.puts(str) + assert_equal(str, ssl.gets) + } + } + ssls.each{|ssl| ssl.close } + } + end +end + +end |