aboutsummaryrefslogtreecommitdiffstats

Plum: An HTTP/2 Library for Ruby

A pure Ruby HTTP/2 server and client implementation.

WARNING: Plum is currently under heavy development. You will encounter bugs when using it.

Circle CI Build Status Code Climate Test Coverage

Requirements

  • Ruby 2.3
  • OpenSSL 1.0.2 or newer (HTTP/2 requires ALPN)
  • Optional:
  • http_parser.rb gem (HTTP/1.x parser; if you use "http" URI scheme)
  • rack gem (if you use Plum as Rack server)

Installation

gem install plum

Usage

  • Documentation: http://www.rubydoc.info/gems/plum
  • Some examples are in examples/

As a Rack-compatible server

Most existing Rack-based applications should work without modification.

# config.ru
App = -> env {
  [
    200,
    { "Content-Type" => "text/plain" },
    ["request: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"]
  ]
}

run App

You can run it:

% plum -e production -p 8080 --https --cert server.crt --key server.key config.ru

NOTE: If --cert and --key are omitted, a temporary dummy certificate will be generated.

As a HTTP/2 (HTTP/1.x) client library

If the server does't support HTTP/2, Plum::Client tries to use HTTP/1.x instead.

   +-----------------+
   |:https option    | false
   |(default: true)  |-------> Try Upgrade from HTTP/1.1
   +-----------------+
            | true
            v
   +-----------------+
   | ALPN            | failed
   | negotiation     |-------> HTTP/1.x
   +-----------------+
            | "h2"
            v
          HTTP/2
Sequential request
client = Plum::Client.start("http2.rhe.jp", user_agent: "nyaan")
res1 = client.get("/", headers: { "accept" => "*/*" }).join
puts res1.body # => "..."
res2 = client.post("/post", "data").join
puts res2.body # => "..."

client.close
Parallel request
res1 = res2 = nil
Plum::Client.start("rhe.jp", 443, http2_settings: { max_frame_size: 32768 }) { |client|
  res1 = client.get("/")
  res2 = client.post("/post", "data")
  # res1.status == nil ; because it's async request
} # wait for response(s) and close

p res1.status # => "200"
Download a large file
Plum::Client.start("http2.rhe.jp", 443, hostname: "assets.rhe.jp") { |client|
  client.get("/large") do |res| # called when received response headers
    p res.status # => "200"
    File.open("/tmp/large.file", "wb") { |file|
      res.on_chunk do |chunk| # called when each chunk of response body arrived
        file << chunk
      end
    }
  end
}

TODO

  • Better API
  • Plum::Client
  • PING frame handling
  • Server Push support
  • Stream Priority support
  • Better HTTP/1.x support

License

MIT License