diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2015-08-20 19:02:41 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2015-09-01 19:03:18 +0900 |
commit | 53c3791ae6ce6f4c7c9e2ef7148ad5bb25976a5f (patch) | |
tree | 082941d4ba0433e82c5d9c00c79f7f4429e1c393 | |
parent | d084bc143bdf15c396871b3bbbe68ef91e210c69 (diff) | |
download | plum-53c3791ae6ce6f4c7c9e2ef7148ad5bb25976a5f.tar.gz |
README: remove examples/local_server.rb and add link to rhenium/plum-server
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | examples/local_server.rb | 207 |
2 files changed, 6 insertions, 209 deletions
@@ -1,10 +1,14 @@ # Plum [![Build Status](https://travis-ci.org/rhenium/plum.png?branch=master)](https://travis-ci.org/rhenium/plum) [![Code Climate](https://codeclimate.com/github/rhenium/plum/badges/gpa.svg)](https://codeclimate.com/github/rhenium/plum) [![Test Coverage](https://codeclimate.com/github/rhenium/plum/badges/coverage.svg)](https://codeclimate.com/github/rhenium/plum/coverage) A minimal implementation of HTTP/2 server. +## Examples +* examples/ - Minimal usage. +* [rhenium/plum-server](https://github.com/rhenium/plum-server) - A example server for https://rhe.jp and http://rhe.jp. + ## Requirements -* OpenSSL 1.0.2+ * Ruby 2.2 with [ALPN support](https://gist.github.com/rhenium/b1711edcc903e8887a51) and [ECDH support (r51348)](https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/51348/diff?format=diff) or latest Ruby 2.3.0-dev. -* [http-parser.rb gem](https://rubygems.org/gems/http_parser.rb) if you use "http" URI scheme. +* OpenSSL 1.0.2+ (HTTP/2 requires ALPN) +* [http-parser.rb gem](https://rubygems.org/gems/http_parser.rb) (HTTP/1.1 parser; if you use "http" URI scheme). ## TODO * **Better API** diff --git a/examples/local_server.rb b/examples/local_server.rb deleted file mode 100644 index a777174..0000000 --- a/examples/local_server.rb +++ /dev/null @@ -1,207 +0,0 @@ -DEBUG = ENV["DEBUG"] || false -HOST = ENV["HOST"] -PORT = ENV["PORT"] -DOCUMENT_ROOT = ENV["DOCUMENT_ROOT"] || "/srv/http" -TLS_CERT = ENV["TLS_CERT"] -TLS_KEY = ENV["TLS_KEY"] - -CONTENT_TYPES = { - /\.html$/ => "text/html", - /\.png$/ => "image/png", - /\.jpg$/ => "image/jpeg", - /\.css$/ => "text/css", - /\.js$/ => "application/javascript", - /\.atom$/ => "application/atom+xml", -} - -$LOAD_PATH << File.expand_path("../../lib", __FILE__) -require "plum" -require "openssl" -require "socket" -begin - require "oga" - HAVE_OGA = true -rescue LoadError - puts "Oga is needed for parsing HTML" - HAVE_OGA = false -end - -begin - require "sslkeylog/autotrace" # for debug -rescue LoadError -end - -def log(con, stream, s) - prefix = "[%02x;%02x] " % [con, stream] - if s.is_a?(Enumerable) - puts s.map {|a| prefix + a.to_s }.join("\n") - else - puts prefix + s.to_s - end -end - -def content_type(filename) - exp, ct = CONTENT_TYPES.lazy.select {|pat, e| pat =~ filename }.first - ct || "texp/plain" -end - -def assets(file) - if /\.html$/ =~ File.basename(file) - doc = Oga.parse_html(File.read(file)) - assets = [] - doc.xpath("img").each {|img| assets << img.get("src") } - doc.xpath("//html/head/link[@rel='stylesheet']").each {|css| assets << css.get("href") } - doc.xpath("script").each {|js| assets << js.get("src") } - assets.compact.uniq.map {|path| - if path.include?("//") - next nil - end - - if path.start_with?("/") - pa = File.expand_path(DOCUMENT_ROOT + path) - else - pa = File.expand_path(path, file) - end - - if pa.start_with?(DOCUMENT_ROOT) & File.exist?(pa) - pa - else - nil - end - }.compact - else - [] - end -end - -ctx = OpenSSL::SSL::SSLContext.new -ctx.ssl_version = :TLSv1_2 -ctx.alpn_select_cb = -> protocols { - raise "Client does not support HTTP/2: #{protocols}" unless protocols.include?("h2") - "h2" -} -ctx.tmp_ecdh_callback = -> (sock, ise, keyl) { - OpenSSL::PKey::EC.new("prime256v1") -} - -ctx.cert = OpenSSL::X509::Certificate.new File.read(TLS_CERT) -ctx.key = OpenSSL::PKey::RSA.new File.read(TLS_KEY) -tcp_server = TCPServer.new(HOST, PORT) -ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx) - -loop do - begin - sock = ssl_server.accept - id = sock.io.fileno - puts "#{id}: accept!" - rescue => e - puts e - next - end - - plum = Plum::HTTPSConnection.new(sock) - - plum.on(:frame) do |frame| - log(id, frame.stream_id, "recv: #{frame.inspect}") - end if DEBUG - - plum.on(:send_frame) do |frame| - log(id, frame.stream_id, "send: #{frame.inspect}") - end if DEBUG - - plum.on(:remote_settings) do |settings| - log(id, 0, settings.map {|name, value| "#{name}: #{value}" }) if DEBUG - end - - plum.on(:connection_error) do |exception| - puts exception - puts exception.backtrace - end if DEBUG - - plum.on(:stream) do |stream| - log(id, stream.id, "stream open") - stream.on(:stream_error) do |exception| - puts exception - puts exception.backtrace - end if DEBUG - - headers = data = nil - - stream.on(:open) do - headers = nil - data = "" - end - - stream.on(:headers) do |headers_| - log(id, stream.id, headers_.map {|name, value| "#{name}: #{value}" }) if DEBUG - headers = headers_.to_h - end - - stream.on(:data) do |data_| - log(id, stream.id, data_) if DEBUG - data << data_ - end - - stream.on(:end_stream) do - if headers[":method"] == "GET" - file = File.expand_path(DOCUMENT_ROOT + headers[":path"]) - file << "/index.html" if Dir.exist?(file) - if file.start_with?(DOCUMENT_ROOT) && File.exist?(file) - io = File.open(file) - size = File.stat(file).size - i_sts = assets(file).map {|asset| - i_st = stream.promise({ - ":authority": headers[":authority"], - ":method": "GET", - ":scheme": "https", - ":path": asset[DOCUMENT_ROOT.size..-1] - }) - [i_st, asset] - } - stream.respond({ - ":status": "200", - "server": "plum/#{Plum::VERSION}", - "content-type": content_type(file), - "content-length": size - }, io) - i_sts.each do |i_st, asset| - aio = File.open(asset) - asize = File.stat(asset).size - i_st.respond({ - ":status": "200", - "server": "plum/#{Plum::VERSION}", - "content-type": content_type(asset), - "content-length": asize - }, aio) - end - else - body = headers.map {|name, value| "#{name}: #{value}" }.join("\n") + "\n" + data - stream.respond({ - ":status": "404", - "server": "plum/#{Plum::VERSION}", - "content-type": "text/plain", - "content-length": body.bytesize - }, body) - end - else - # Not implemented - body = headers.map {|name, value| "#{name}: #{value}" }.join("\n") << "\n" << data - stream.respond({ - ":status": "501", - "server": "plum/#{Plum::VERSION}", - "content-type": "text/plain", - "content-length": body.bytesize - }, body) - end - end - end - - Thread.new { - begin - plum.run - rescue - puts $! - puts $!.backtrace - end - } -end |