http-2 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +0 -2
 - data/lib/http/2/buffer.rb +6 -4
 - data/lib/http/2/client.rb +5 -1
 - data/lib/http/2/compressor.rb +42 -34
 - data/lib/http/2/connection.rb +72 -86
 - data/lib/http/2/emitter.rb +4 -1
 - data/lib/http/2/error.rb +2 -0
 - data/lib/http/2/flow_buffer.rb +8 -3
 - data/lib/http/2/framer.rb +83 -94
 - data/lib/http/2/huffman.rb +19 -17
 - data/lib/http/2/server.rb +9 -7
 - data/lib/http/2/stream.rb +48 -48
 - data/lib/http/2/version.rb +3 -1
 - data/lib/http/2.rb +2 -0
 - metadata +7 -60
 - data/.autotest +0 -20
 - data/.coveralls.yml +0 -1
 - data/.gitignore +0 -20
 - data/.gitmodules +0 -3
 - data/.rspec +0 -5
 - data/.rubocop.yml +0 -93
 - data/.rubocop_todo.yml +0 -131
 - data/.travis.yml +0 -17
 - data/Gemfile +0 -16
 - data/Guardfile +0 -18
 - data/Guardfile.h2spec +0 -12
 - data/Rakefile +0 -49
 - data/example/Gemfile +0 -3
 - data/example/README.md +0 -44
 - data/example/client.rb +0 -122
 - data/example/helper.rb +0 -19
 - data/example/keys/server.crt +0 -20
 - data/example/keys/server.key +0 -27
 - data/example/server.rb +0 -139
 - data/example/upgrade_client.rb +0 -153
 - data/example/upgrade_server.rb +0 -203
 - data/http-2.gemspec +0 -22
 - data/lib/tasks/generate_huffman_table.rb +0 -166
 - data/spec/buffer_spec.rb +0 -28
 - data/spec/client_spec.rb +0 -188
 - data/spec/compressor_spec.rb +0 -666
 - data/spec/connection_spec.rb +0 -681
 - data/spec/emitter_spec.rb +0 -54
 - data/spec/framer_spec.rb +0 -487
 - data/spec/h2spec/h2spec.darwin +0 -0
 - data/spec/h2spec/output/non_secure.txt +0 -317
 - data/spec/helper.rb +0 -147
 - data/spec/hpack_test_spec.rb +0 -84
 - data/spec/huffman_spec.rb +0 -68
 - data/spec/server_spec.rb +0 -52
 - data/spec/stream_spec.rb +0 -878
 - data/spec/support/deep_dup.rb +0 -55
 - data/spec/support/duplicable.rb +0 -98
 
    
        data/Rakefile
    DELETED
    
    | 
         @@ -1,49 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require 'bundler/gem_tasks'
         
     | 
| 
       2 
     | 
    
         
            -
            require 'rspec/core/rake_task'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'rubocop/rake_task'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'yard'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'open3'
         
     | 
| 
       6 
     | 
    
         
            -
            require_relative 'lib/tasks/generate_huffman_table'
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            RSpec::Core::RakeTask.new(:spec) do |t|
         
     | 
| 
       9 
     | 
    
         
            -
              t.exclude_pattern = './spec/hpack_test_spec.rb'
         
     | 
| 
       10 
     | 
    
         
            -
            end
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            RSpec::Core::RakeTask.new(:hpack) do |t|
         
     | 
| 
       13 
     | 
    
         
            -
              t.pattern = './spec/hpack_test_spec.rb'
         
     | 
| 
       14 
     | 
    
         
            -
            end
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            task :h2spec do
         
     | 
| 
       17 
     | 
    
         
            -
              if /darwin/ !~ RUBY_PLATFORM
         
     | 
| 
       18 
     | 
    
         
            -
                abort "h2spec rake task currently only works on OSX.
         
     | 
| 
       19 
     | 
    
         
            -
                       Download other binaries from https://github.com/summerwind/h2spec/releases"
         
     | 
| 
       20 
     | 
    
         
            -
              end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
              system 'ruby example/server.rb -p 9000 &', out: File::NULL
         
     | 
| 
       23 
     | 
    
         
            -
              sleep 1
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
              output = ''
         
     | 
| 
       26 
     | 
    
         
            -
              Open3.popen2e('spec/h2spec/h2spec.darwin -p 9000 -o 1') do |_i, oe, _t|
         
     | 
| 
       27 
     | 
    
         
            -
                oe.each do |l|
         
     | 
| 
       28 
     | 
    
         
            -
                  l.gsub!(/\e\[(\d+)(;\d+)*m/, '')
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                  output << l
         
     | 
| 
       31 
     | 
    
         
            -
                  if l =~ /passed.*failed/
         
     | 
| 
       32 
     | 
    
         
            -
                    puts "\n#{l}"
         
     | 
| 
       33 
     | 
    
         
            -
                    break # suppress post-summary failure output
         
     | 
| 
       34 
     | 
    
         
            -
                  else
         
     | 
| 
       35 
     | 
    
         
            -
                    print '.'
         
     | 
| 
       36 
     | 
    
         
            -
                  end
         
     | 
| 
       37 
     | 
    
         
            -
                end
         
     | 
| 
       38 
     | 
    
         
            -
              end
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
              File.write 'spec/h2spec/output/non_secure.txt', output
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
              system 'kill `pgrep -f example/server.rb`'
         
     | 
| 
       43 
     | 
    
         
            -
            end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
            RuboCop::RakeTask.new
         
     | 
| 
       46 
     | 
    
         
            -
            YARD::Rake::YardocTask.new
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
            task default: [:spec, :rubocop]
         
     | 
| 
       49 
     | 
    
         
            -
            task all: [:default, :hpack]
         
     | 
    
        data/example/Gemfile
    DELETED
    
    
    
        data/example/README.md
    DELETED
    
    | 
         @@ -1,44 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            ## Interop
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            First, a quick test to ensure that we can talk to ourselves:
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            ```bash
         
     | 
| 
       6 
     | 
    
         
            -
            # Direct connection
         
     | 
| 
       7 
     | 
    
         
            -
            $> ruby server.rb
         
     | 
| 
       8 
     | 
    
         
            -
            $> ruby client.rb http://localhost:8080/                 # GET
         
     | 
| 
       9 
     | 
    
         
            -
            $> ruby client.rb http://localhost:8080/ -d 'some data'  # POST
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            # Server push
         
     | 
| 
       12 
     | 
    
         
            -
            $> ruby server.rb --push
         
     | 
| 
       13 
     | 
    
         
            -
            $> ruby client.rb http://localhost:8080/                 # GET
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            # TLS + NPN negotiation
         
     | 
| 
       16 
     | 
    
         
            -
            $> ruby server.rb --secure
         
     | 
| 
       17 
     | 
    
         
            -
            $> ruby client.rb https://localhost:8080/                # GET
         
     | 
| 
       18 
     | 
    
         
            -
            $> ...
         
     | 
| 
       19 
     | 
    
         
            -
            ```
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
            ### [nghttp2](https://github.com/tatsuhiro-t/nghttp2) (HTTP/2.0 C Library)
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            Public test server: http://106.186.112.116 (Upgrade + Direct)
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
            ```bash
         
     | 
| 
       26 
     | 
    
         
            -
            # Direct request (http-2 > nghttp2)
         
     | 
| 
       27 
     | 
    
         
            -
            $> ruby client.rb http://106.186.112.116/
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            # TLS + NPN request (http-2 > nghttp2)
         
     | 
| 
       30 
     | 
    
         
            -
            $> ruby client.rb https://106.186.112.116/
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
            # Direct request (nghttp2 > http-2)
         
     | 
| 
       33 
     | 
    
         
            -
            $> ruby server.rb
         
     | 
| 
       34 
     | 
    
         
            -
            $> nghttp -vnu http://localhost:8080       # Direct request to Ruby server
         
     | 
| 
       35 
     | 
    
         
            -
            ```
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
            ### Twitter (Java server)
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
            ```bash
         
     | 
| 
       40 
     | 
    
         
            -
            # NPN + GET request (http-2 > twitter)
         
     | 
| 
       41 
     | 
    
         
            -
            $> ruby client.rb https://twitter.com/
         
     | 
| 
       42 
     | 
    
         
            -
            ```
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
            For a complete list of current implementations, see [http2 wiki](https://github.com/http2/http2-spec/wiki/Implementations).
         
     | 
    
        data/example/client.rb
    DELETED
    
    | 
         @@ -1,122 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require_relative 'helper'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            options = {}
         
     | 
| 
       4 
     | 
    
         
            -
            OptionParser.new do |opts|
         
     | 
| 
       5 
     | 
    
         
            -
              opts.banner = 'Usage: client.rb [options]'
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
              opts.on('-d', '--data [String]', 'HTTP payload') do |v|
         
     | 
| 
       8 
     | 
    
         
            -
                options[:payload] = v
         
     | 
| 
       9 
     | 
    
         
            -
              end
         
     | 
| 
       10 
     | 
    
         
            -
            end.parse!
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            uri = URI.parse(ARGV[0] || 'http://localhost:8080/')
         
     | 
| 
       13 
     | 
    
         
            -
            tcp = TCPSocket.new(uri.host, uri.port)
         
     | 
| 
       14 
     | 
    
         
            -
            sock = nil
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            if uri.scheme == 'https'
         
     | 
| 
       17 
     | 
    
         
            -
              ctx = OpenSSL::SSL::SSLContext.new
         
     | 
| 
       18 
     | 
    
         
            -
              ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
              # For ALPN support, Ruby >= 2.3 and OpenSSL >= 1.0.2 are required
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
              ctx.alpn_protocols = [DRAFT]
         
     | 
| 
       23 
     | 
    
         
            -
              ctx.alpn_select_cb = lambda do |protocols|
         
     | 
| 
       24 
     | 
    
         
            -
                puts "ALPN protocols supported by server: #{protocols}"
         
     | 
| 
       25 
     | 
    
         
            -
                DRAFT if protocols.include? DRAFT
         
     | 
| 
       26 
     | 
    
         
            -
              end
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
              sock = OpenSSL::SSL::SSLSocket.new(tcp, ctx)
         
     | 
| 
       29 
     | 
    
         
            -
              sock.sync_close = true
         
     | 
| 
       30 
     | 
    
         
            -
              sock.hostname = uri.hostname
         
     | 
| 
       31 
     | 
    
         
            -
              sock.connect
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
              if sock.alpn_protocol != DRAFT
         
     | 
| 
       34 
     | 
    
         
            -
                puts "Failed to negotiate #{DRAFT} via ALPN"
         
     | 
| 
       35 
     | 
    
         
            -
                exit
         
     | 
| 
       36 
     | 
    
         
            -
              end
         
     | 
| 
       37 
     | 
    
         
            -
            else
         
     | 
| 
       38 
     | 
    
         
            -
              sock = tcp
         
     | 
| 
       39 
     | 
    
         
            -
            end
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
            conn = HTTP2::Client.new
         
     | 
| 
       42 
     | 
    
         
            -
            stream = conn.new_stream
         
     | 
| 
       43 
     | 
    
         
            -
            log = Logger.new(stream.id)
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
            conn.on(:frame) do |bytes|
         
     | 
| 
       46 
     | 
    
         
            -
              # puts "Sending bytes: #{bytes.unpack("H*").first}"
         
     | 
| 
       47 
     | 
    
         
            -
              sock.print bytes
         
     | 
| 
       48 
     | 
    
         
            -
              sock.flush
         
     | 
| 
       49 
     | 
    
         
            -
            end
         
     | 
| 
       50 
     | 
    
         
            -
            conn.on(:frame_sent) do |frame|
         
     | 
| 
       51 
     | 
    
         
            -
              puts "Sent frame: #{frame.inspect}"
         
     | 
| 
       52 
     | 
    
         
            -
            end
         
     | 
| 
       53 
     | 
    
         
            -
            conn.on(:frame_received) do |frame|
         
     | 
| 
       54 
     | 
    
         
            -
              puts "Received frame: #{frame.inspect}"
         
     | 
| 
       55 
     | 
    
         
            -
            end
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
            conn.on(:promise) do |promise|
         
     | 
| 
       58 
     | 
    
         
            -
              promise.on(:promise_headers) do |h|
         
     | 
| 
       59 
     | 
    
         
            -
                log.info "promise request headers: #{h}"
         
     | 
| 
       60 
     | 
    
         
            -
              end
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
              promise.on(:headers) do |h|
         
     | 
| 
       63 
     | 
    
         
            -
                log.info "promise headers: #{h}"
         
     | 
| 
       64 
     | 
    
         
            -
              end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
              promise.on(:data) do |d|
         
     | 
| 
       67 
     | 
    
         
            -
                log.info "promise data chunk: <<#{d.size}>>"
         
     | 
| 
       68 
     | 
    
         
            -
              end
         
     | 
| 
       69 
     | 
    
         
            -
            end
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
            conn.on(:altsvc) do |f|
         
     | 
| 
       72 
     | 
    
         
            -
              log.info "received ALTSVC #{f}"
         
     | 
| 
       73 
     | 
    
         
            -
            end
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
            stream.on(:close) do
         
     | 
| 
       76 
     | 
    
         
            -
              log.info 'stream closed'
         
     | 
| 
       77 
     | 
    
         
            -
            end
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
     | 
    
         
            -
            stream.on(:half_close) do
         
     | 
| 
       80 
     | 
    
         
            -
              log.info 'closing client-end of the stream'
         
     | 
| 
       81 
     | 
    
         
            -
            end
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
            stream.on(:headers) do |h|
         
     | 
| 
       84 
     | 
    
         
            -
              log.info "response headers: #{h}"
         
     | 
| 
       85 
     | 
    
         
            -
            end
         
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
            stream.on(:data) do |d|
         
     | 
| 
       88 
     | 
    
         
            -
              log.info "response data chunk: <<#{d}>>"
         
     | 
| 
       89 
     | 
    
         
            -
            end
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
            stream.on(:altsvc) do |f|
         
     | 
| 
       92 
     | 
    
         
            -
              log.info "received ALTSVC #{f}"
         
     | 
| 
       93 
     | 
    
         
            -
            end
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
            head = {
         
     | 
| 
       96 
     | 
    
         
            -
              ':scheme' => uri.scheme,
         
     | 
| 
       97 
     | 
    
         
            -
              ':method' => (options[:payload].nil? ? 'GET' : 'POST'),
         
     | 
| 
       98 
     | 
    
         
            -
              ':authority' => [uri.host, uri.port].join(':'),
         
     | 
| 
       99 
     | 
    
         
            -
              ':path' => uri.path,
         
     | 
| 
       100 
     | 
    
         
            -
              'accept' => '*/*',
         
     | 
| 
       101 
     | 
    
         
            -
            }
         
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
            puts 'Sending HTTP 2.0 request'
         
     | 
| 
       104 
     | 
    
         
            -
            if head[':method'] == 'GET'
         
     | 
| 
       105 
     | 
    
         
            -
              stream.headers(head, end_stream: true)
         
     | 
| 
       106 
     | 
    
         
            -
            else
         
     | 
| 
       107 
     | 
    
         
            -
              stream.headers(head, end_stream: false)
         
     | 
| 
       108 
     | 
    
         
            -
              stream.data(options[:payload])
         
     | 
| 
       109 
     | 
    
         
            -
            end
         
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
            while !sock.closed? && !sock.eof?
         
     | 
| 
       112 
     | 
    
         
            -
              data = sock.read_nonblock(1024)
         
     | 
| 
       113 
     | 
    
         
            -
              # puts "Received bytes: #{data.unpack("H*").first}"
         
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
              begin
         
     | 
| 
       116 
     | 
    
         
            -
                conn << data
         
     | 
| 
       117 
     | 
    
         
            -
              rescue StandardError => e
         
     | 
| 
       118 
     | 
    
         
            -
                puts "#{e.class} exception: #{e.message} - closing socket."
         
     | 
| 
       119 
     | 
    
         
            -
                e.backtrace.each { |l| puts "\t" + l }
         
     | 
| 
       120 
     | 
    
         
            -
                sock.close
         
     | 
| 
       121 
     | 
    
         
            -
              end
         
     | 
| 
       122 
     | 
    
         
            -
            end
         
     | 
    
        data/example/helper.rb
    DELETED
    
    | 
         @@ -1,19 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            $LOAD_PATH << 'lib' << '../lib'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'optparse'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'socket'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'openssl'
         
     | 
| 
       6 
     | 
    
         
            -
            require 'http/2'
         
     | 
| 
       7 
     | 
    
         
            -
            require 'uri'
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            DRAFT = 'h2'.freeze
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            class Logger
         
     | 
| 
       12 
     | 
    
         
            -
              def initialize(id)
         
     | 
| 
       13 
     | 
    
         
            -
                @id = id
         
     | 
| 
       14 
     | 
    
         
            -
              end
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
              def info(msg)
         
     | 
| 
       17 
     | 
    
         
            -
                puts "[Stream #{@id}]: #{msg}"
         
     | 
| 
       18 
     | 
    
         
            -
              end
         
     | 
| 
       19 
     | 
    
         
            -
            end
         
     | 
    
        data/example/keys/server.crt
    DELETED
    
    | 
         @@ -1,20 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            -----BEGIN CERTIFICATE-----
         
     | 
| 
       2 
     | 
    
         
            -
            MIIDLjCCAhYCCQDIZ/9hq/2pXjANBgkqhkiG9w0BAQUFADBZMQswCQYDVQQGEwJB
         
     | 
| 
       3 
     | 
    
         
            -
            VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
         
     | 
| 
       4 
     | 
    
         
            -
            cyBQdHkgTHRkMRIwEAYDVQQDEwlsb2NhbGhvc3QwHhcNMTYwNjA2MTk0MzI1WhcN
         
     | 
| 
       5 
     | 
    
         
            -
            MTcwNjA2MTk0MzI1WjBZMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0
         
     | 
| 
       6 
     | 
    
         
            -
            ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDEwls
         
     | 
| 
       7 
     | 
    
         
            -
            b2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjFXrWqtRZ
         
     | 
| 
       8 
     | 
    
         
            -
            EMOO/o6AxGbgDYMgg/7uxCFQJM5Z6C4II6D8V94FDyCd+J0LOK2hB+QUdFqpA1S9
         
     | 
| 
       9 
     | 
    
         
            -
            6RW2MvIwdvRt03RJMgbfcUF0+w4ZItv2xrW9waCfCmLSRDZgcSATacEF6u9p2Vs+
         
     | 
| 
       10 
     | 
    
         
            -
            o4J/cHacirSwjy4+m94CgkxtUFGtGcJaFqAZ6Cdj5WvQdJSiAI3x3gNC/UGA+5dL
         
     | 
| 
       11 
     | 
    
         
            -
            sp8+vwWx+/TMc6nDBmoRW3GHeG/NApQSh01w3wDv0FmUaFQlA5WPya/Js+CyuYh1
         
     | 
| 
       12 
     | 
    
         
            -
            miXbQJEjDnGGaJjnoyRAQpPrk72Jj+bnfOu9kxpzkuLJOsbaofRFkM+/Ar5U+bQz
         
     | 
| 
       13 
     | 
    
         
            -
            uU0ErQ8Ih8MPAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBACL8HkKjW8kWLlW4TE5K
         
     | 
| 
       14 
     | 
    
         
            -
            EcfsBad2Ah5ugTocJ/pLnr/YEo8uD91gECDtsuFTXul9n2M7U5jJmzbHZ63cjyC3
         
     | 
| 
       15 
     | 
    
         
            -
            lb1BxJxUL7aIyaL61IMMcIJMWhC9VGnFUshMDNVBhuRkKs/QvaMD5KefKN1E9I2M
         
     | 
| 
       16 
     | 
    
         
            -
            mZ72Yww0VihYwNOu3MTn8gUuy9eU6k/gTYPY7PJVh18QmR+Fs2MaaPp+bDwxiqML
         
     | 
| 
       17 
     | 
    
         
            -
            0o2I6+0ZsqM3vFtcUjxjRASV5s+JkM34pTWFwUOl7TZv1YsxCKSz4f0BXDImZEvU
         
     | 
| 
       18 
     | 
    
         
            -
            rwqFdlELp5WOG9LJsrszDRbf1wbFUsG1XXZpIBiWo3d6pOiIyRKrak1vKViNfYvI
         
     | 
| 
       19 
     | 
    
         
            -
            W30=
         
     | 
| 
       20 
     | 
    
         
            -
            -----END CERTIFICATE-----
         
     | 
    
        data/example/keys/server.key
    DELETED
    
    | 
         @@ -1,27 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            -----BEGIN RSA PRIVATE KEY-----
         
     | 
| 
       2 
     | 
    
         
            -
            MIIEpAIBAAKCAQEAoxV61qrUWRDDjv6OgMRm4A2DIIP+7sQhUCTOWeguCCOg/Ffe
         
     | 
| 
       3 
     | 
    
         
            -
            BQ8gnfidCzitoQfkFHRaqQNUvekVtjLyMHb0bdN0STIG33FBdPsOGSLb9sa1vcGg
         
     | 
| 
       4 
     | 
    
         
            -
            nwpi0kQ2YHEgE2nBBervadlbPqOCf3B2nIq0sI8uPpveAoJMbVBRrRnCWhagGegn
         
     | 
| 
       5 
     | 
    
         
            -
            Y+Vr0HSUogCN8d4DQv1BgPuXS7KfPr8Fsfv0zHOpwwZqEVtxh3hvzQKUEodNcN8A
         
     | 
| 
       6 
     | 
    
         
            -
            79BZlGhUJQOVj8mvybPgsrmIdZol20CRIw5xhmiY56MkQEKT65O9iY/m53zrvZMa
         
     | 
| 
       7 
     | 
    
         
            -
            c5LiyTrG2qH0RZDPvwK+VPm0M7lNBK0PCIfDDwIDAQABAoIBAQCZShphZsccRJ6c
         
     | 
| 
       8 
     | 
    
         
            -
            bPdDX9iW5vyG9qsMgPwTGdWAOrXx3pN2PZ0pwjNVaRcsMgU6JHGlLEz/Kmtf6pQG
         
     | 
| 
       9 
     | 
    
         
            -
            41I0bcuI48Yc+tHs+sadD1IMHHEHP3Yau8KfWyLSI129Pvf4Z2IQjuik5LJYaVbD
         
     | 
| 
       10 
     | 
    
         
            -
            NNG4iMQYZS0Bmn6Oey0dXu62t0ywYa0qvbIDse/RmjTQSTipuvGg8/QEAeRGABv8
         
     | 
| 
       11 
     | 
    
         
            -
            Nd4Esya0zuxk6hGaNp3hkjyRkeoC7RsBVJbFSnp6gSubPdXwrJyHfySKe9jvrDG3
         
     | 
| 
       12 
     | 
    
         
            -
            Q/AzyHUh/6EODd5n66x0p6rq7oo9/PnLvZJY8jIGWG+aEp68RJyEgimrwll0rAWw
         
     | 
| 
       13 
     | 
    
         
            -
            /buqijGRAoGBANimL8407fFirmct7BceavaeJfXPK5yWiOhVX0XlJ0phAFuaAxK3
         
     | 
| 
       14 
     | 
    
         
            -
            5HVT7DD+KKV66g1jtS9FUVZGDiYFHlsdsYuHVYcRmr0h5rZr941obrDwNrM9Nf9C
         
     | 
| 
       15 
     | 
    
         
            -
            0uehN5+n/FaeGoQLR3V4THoP3rlkYTlLpQnI5mKA19JukXnIiJM9ARUZAoGBAMC0
         
     | 
| 
       16 
     | 
    
         
            -
            mcVsVuSKSFwURtQHHIufxL6SqC2kLTwIQ7exqejNYPCqCiif+ZWOmsTqbVGAGbMK
         
     | 
| 
       17 
     | 
    
         
            -
            Ohak4oLwN5IGCl4jNQG+vWagREkx6OXSk5NYcfoNBrOm+0UoFRzoEA85s7Dy6PuD
         
     | 
| 
       18 
     | 
    
         
            -
            tBucNZpt1sGauzkCSx7C8jj4ZlSwkv0XhBFfbTZnAoGBAK2wBjF+U6iq4YFM2rLq
         
     | 
| 
       19 
     | 
    
         
            -
            KvzOa0Z3MdKXCOmiz//cKDTEMaI+heoyzZCWmIvqpzGLqirT3gUowH23Kk6m2eBY
         
     | 
| 
       20 
     | 
    
         
            -
            nOdst0/S+Eha7nkfc9bFe8CUxHXMRAcCTs1ufYadCXtzw3RLCp4NtNpC8N+Wry9d
         
     | 
| 
       21 
     | 
    
         
            -
            CtIeYz1jaCOHi0+kSoIobT65AoGAc6hxWkJp7ITqZQlucTdLdKmRheeztKEC3TMA
         
     | 
| 
       22 
     | 
    
         
            -
            obGqDqWldww3SKarP431ahZhQjcmNYT/1DNmF7xhPe0OL+3llISMXJn4Ig4ogDdg
         
     | 
| 
       23 
     | 
    
         
            -
            h2DgF3nV+eFQkfM6qLzHVrwFE0DXgI1NffzFV0hxSoW5tL+honbStkqv8EiCEBEb
         
     | 
| 
       24 
     | 
    
         
            -
            HOovPCUCgYBpXuPARd2ycInAulVHijJmj2rmK7f41ZhVCWovYjcCWyeJyLIO7j+b
         
     | 
| 
       25 
     | 
    
         
            -
            MBJZbmwpStJhEjW64nE2zZGWg2HCBbvZz5/SXIr3fp7qVXwpn1TvB/TJDf43t0oF
         
     | 
| 
       26 
     | 
    
         
            -
            3caLgyQYoQCsVHKT3cU4s3wuog/DyHKh9FtRkcJrEy7h9Rrc+ModbA==
         
     | 
| 
       27 
     | 
    
         
            -
            -----END RSA PRIVATE KEY-----
         
     | 
    
        data/example/server.rb
    DELETED
    
    | 
         @@ -1,139 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require_relative 'helper'
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            options = { port: 8080 }
         
     | 
| 
       4 
     | 
    
         
            -
            OptionParser.new do |opts|
         
     | 
| 
       5 
     | 
    
         
            -
              opts.banner = 'Usage: server.rb [options]'
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
              opts.on('-s', '--secure', 'HTTPS mode') do |v|
         
     | 
| 
       8 
     | 
    
         
            -
                options[:secure] = v
         
     | 
| 
       9 
     | 
    
         
            -
              end
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
              opts.on('-p', '--port [Integer]', 'listen port') do |v|
         
     | 
| 
       12 
     | 
    
         
            -
                options[:port] = v
         
     | 
| 
       13 
     | 
    
         
            -
              end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
              opts.on('-u', '--push', 'Push message') do |_v|
         
     | 
| 
       16 
     | 
    
         
            -
                options[:push] = true
         
     | 
| 
       17 
     | 
    
         
            -
              end
         
     | 
| 
       18 
     | 
    
         
            -
            end.parse!
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
            puts "Starting server on port #{options[:port]}"
         
     | 
| 
       21 
     | 
    
         
            -
            server = TCPServer.new(options[:port])
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            if options[:secure]
         
     | 
| 
       24 
     | 
    
         
            -
              ctx = OpenSSL::SSL::SSLContext.new
         
     | 
| 
       25 
     | 
    
         
            -
              ctx.cert = OpenSSL::X509::Certificate.new(File.open('keys/server.crt'))
         
     | 
| 
       26 
     | 
    
         
            -
              ctx.key = OpenSSL::PKey::RSA.new(File.open('keys/server.key'))
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
              ctx.ssl_version = :TLSv1_2
         
     | 
| 
       29 
     | 
    
         
            -
              ctx.options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
         
     | 
| 
       30 
     | 
    
         
            -
              ctx.ciphers = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ciphers]
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
              ctx.alpn_protocols = ['h2']
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
              ctx.alpn_select_cb = lambda do |protocols|
         
     | 
| 
       35 
     | 
    
         
            -
                raise "Protocol #{DRAFT} is required" if protocols.index(DRAFT).nil?
         
     | 
| 
       36 
     | 
    
         
            -
                DRAFT
         
     | 
| 
       37 
     | 
    
         
            -
              end
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
              ctx.ecdh_curves = 'P-256'
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
              server = OpenSSL::SSL::SSLServer.new(server, ctx)
         
     | 
| 
       42 
     | 
    
         
            -
            end
         
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
            loop do
         
     | 
| 
       45 
     | 
    
         
            -
              sock = server.accept
         
     | 
| 
       46 
     | 
    
         
            -
              puts 'New TCP connection!'
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
              conn = HTTP2::Server.new
         
     | 
| 
       49 
     | 
    
         
            -
              conn.on(:frame) do |bytes|
         
     | 
| 
       50 
     | 
    
         
            -
                # puts "Writing bytes: #{bytes.unpack("H*").first}"
         
     | 
| 
       51 
     | 
    
         
            -
                sock.is_a?(TCPSocket) ? sock.sendmsg(bytes) : sock.write(bytes)
         
     | 
| 
       52 
     | 
    
         
            -
              end
         
     | 
| 
       53 
     | 
    
         
            -
              conn.on(:frame_sent) do |frame|
         
     | 
| 
       54 
     | 
    
         
            -
                puts "Sent frame: #{frame.inspect}"
         
     | 
| 
       55 
     | 
    
         
            -
              end
         
     | 
| 
       56 
     | 
    
         
            -
              conn.on(:frame_received) do |frame|
         
     | 
| 
       57 
     | 
    
         
            -
                puts "Received frame: #{frame.inspect}"
         
     | 
| 
       58 
     | 
    
         
            -
              end
         
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
              conn.on(:stream) do |stream|
         
     | 
| 
       61 
     | 
    
         
            -
                log = Logger.new(stream.id)
         
     | 
| 
       62 
     | 
    
         
            -
                req, buffer = {}, ''
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                stream.on(:active) { log.info 'client opened new stream' }
         
     | 
| 
       65 
     | 
    
         
            -
                stream.on(:close)  { log.info 'stream closed' }
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                stream.on(:headers) do |h|
         
     | 
| 
       68 
     | 
    
         
            -
                  req = Hash[*h.flatten]
         
     | 
| 
       69 
     | 
    
         
            -
                  log.info "request headers: #{h}"
         
     | 
| 
       70 
     | 
    
         
            -
                end
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
                stream.on(:data) do |d|
         
     | 
| 
       73 
     | 
    
         
            -
                  log.info "payload chunk: <<#{d}>>"
         
     | 
| 
       74 
     | 
    
         
            -
                  buffer << d
         
     | 
| 
       75 
     | 
    
         
            -
                end
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
                stream.on(:half_close) do
         
     | 
| 
       78 
     | 
    
         
            -
                  log.info 'client closed its end of the stream'
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
                  response = nil
         
     | 
| 
       81 
     | 
    
         
            -
                  if req[':method'] == 'POST'
         
     | 
| 
       82 
     | 
    
         
            -
                    log.info "Received POST request, payload: #{buffer}"
         
     | 
| 
       83 
     | 
    
         
            -
                    response = "Hello HTTP 2.0! POST payload: #{buffer}"
         
     | 
| 
       84 
     | 
    
         
            -
                  else
         
     | 
| 
       85 
     | 
    
         
            -
                    log.info 'Received GET request'
         
     | 
| 
       86 
     | 
    
         
            -
                    response = 'Hello HTTP 2.0! GET request'
         
     | 
| 
       87 
     | 
    
         
            -
                  end
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                  stream.headers({
         
     | 
| 
       90 
     | 
    
         
            -
                    ':status' => '200',
         
     | 
| 
       91 
     | 
    
         
            -
                    'content-length' => response.bytesize.to_s,
         
     | 
| 
       92 
     | 
    
         
            -
                    'content-type' => 'text/plain',
         
     | 
| 
       93 
     | 
    
         
            -
                  }, end_stream: false)
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                  if options[:push]
         
     | 
| 
       96 
     | 
    
         
            -
                    push_streams = []
         
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                    # send 10 promises
         
     | 
| 
       99 
     | 
    
         
            -
                    10.times do |i|
         
     | 
| 
       100 
     | 
    
         
            -
                      puts 'sending push'
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
                      head = { ':method' => 'GET',
         
     | 
| 
       103 
     | 
    
         
            -
                               ':authority' => 'localhost',
         
     | 
| 
       104 
     | 
    
         
            -
                               ':scheme' => 'https',
         
     | 
| 
       105 
     | 
    
         
            -
                               ':path' => "/other_resource/#{i}" }
         
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
                      stream.promise(head) do |push|
         
     | 
| 
       108 
     | 
    
         
            -
                        push.headers(':status' => '200', 'content-type' => 'text/plain', 'content-length' => '11')
         
     | 
| 
       109 
     | 
    
         
            -
                        push_streams << push
         
     | 
| 
       110 
     | 
    
         
            -
                      end
         
     | 
| 
       111 
     | 
    
         
            -
                    end
         
     | 
| 
       112 
     | 
    
         
            -
                  end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                  # split response into multiple DATA frames
         
     | 
| 
       115 
     | 
    
         
            -
                  stream.data(response.slice!(0, 5), end_stream: false)
         
     | 
| 
       116 
     | 
    
         
            -
                  stream.data(response)
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
                  if options[:push]
         
     | 
| 
       119 
     | 
    
         
            -
                    push_streams.each_with_index do |push, i|
         
     | 
| 
       120 
     | 
    
         
            -
                      sleep 1
         
     | 
| 
       121 
     | 
    
         
            -
                      push.data("push_data #{i}")
         
     | 
| 
       122 
     | 
    
         
            -
                    end
         
     | 
| 
       123 
     | 
    
         
            -
                  end
         
     | 
| 
       124 
     | 
    
         
            -
                end
         
     | 
| 
       125 
     | 
    
         
            -
              end
         
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
              while !sock.closed? && !(sock.eof? rescue true) # rubocop:disable Style/RescueModifier
         
     | 
| 
       128 
     | 
    
         
            -
                data = sock.readpartial(1024)
         
     | 
| 
       129 
     | 
    
         
            -
                # puts "Received bytes: #{data.unpack("H*").first}"
         
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
                begin
         
     | 
| 
       132 
     | 
    
         
            -
                  conn << data
         
     | 
| 
       133 
     | 
    
         
            -
                rescue StandardError => e
         
     | 
| 
       134 
     | 
    
         
            -
                  puts "#{e.class} exception: #{e.message} - closing socket."
         
     | 
| 
       135 
     | 
    
         
            -
                  e.backtrace.each { |l| puts "\t" + l }
         
     | 
| 
       136 
     | 
    
         
            -
                  sock.close
         
     | 
| 
       137 
     | 
    
         
            -
                end
         
     | 
| 
       138 
     | 
    
         
            -
              end
         
     | 
| 
       139 
     | 
    
         
            -
            end
         
     | 
    
        data/example/upgrade_client.rb
    DELETED
    
    | 
         @@ -1,153 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literals: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require_relative 'helper'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'http_parser'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            OptionParser.new do |opts|
         
     | 
| 
       7 
     | 
    
         
            -
              opts.banner = 'Usage: upgrade_client.rb [options]'
         
     | 
| 
       8 
     | 
    
         
            -
            end.parse!
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            uri = URI.parse(ARGV[0] || 'http://localhost:8080/')
         
     | 
| 
       11 
     | 
    
         
            -
            sock = TCPSocket.new(uri.host, uri.port)
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            conn = HTTP2::Client.new
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            def request_header_hash
         
     | 
| 
       16 
     | 
    
         
            -
              Hash.new do |hash, key|
         
     | 
| 
       17 
     | 
    
         
            -
                k = key.to_s.downcase
         
     | 
| 
       18 
     | 
    
         
            -
                k.tr! '_', '-'
         
     | 
| 
       19 
     | 
    
         
            -
                _, value = hash.find { |header_key, _| header_key.downcase == k }
         
     | 
| 
       20 
     | 
    
         
            -
                hash[key] = value if value
         
     | 
| 
       21 
     | 
    
         
            -
              end
         
     | 
| 
       22 
     | 
    
         
            -
            end
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
            conn.on(:frame) do |bytes|
         
     | 
| 
       25 
     | 
    
         
            -
              sock.print bytes
         
     | 
| 
       26 
     | 
    
         
            -
              sock.flush
         
     | 
| 
       27 
     | 
    
         
            -
            end
         
     | 
| 
       28 
     | 
    
         
            -
            conn.on(:frame_sent) do |frame|
         
     | 
| 
       29 
     | 
    
         
            -
              puts "Sent frame: #{frame.inspect}"
         
     | 
| 
       30 
     | 
    
         
            -
            end
         
     | 
| 
       31 
     | 
    
         
            -
            conn.on(:frame_received) do |frame|
         
     | 
| 
       32 
     | 
    
         
            -
              puts "Received frame: #{frame.inspect}"
         
     | 
| 
       33 
     | 
    
         
            -
            end
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
            # upgrader module
         
     | 
| 
       36 
     | 
    
         
            -
            class UpgradeHandler
         
     | 
| 
       37 
     | 
    
         
            -
              UPGRADE_REQUEST = <<RESP.freeze
         
     | 
| 
       38 
     | 
    
         
            -
            GET %s HTTP/1.1
         
     | 
| 
       39 
     | 
    
         
            -
            Connection: Upgrade, HTTP2-Settings
         
     | 
| 
       40 
     | 
    
         
            -
            HTTP2-Settings: #{HTTP2::Client.settings_header(settings_max_concurrent_streams: 100)}
         
     | 
| 
       41 
     | 
    
         
            -
            Upgrade: h2c
         
     | 
| 
       42 
     | 
    
         
            -
            Host: %s
         
     | 
| 
       43 
     | 
    
         
            -
            User-Agent: http-2 upgrade
         
     | 
| 
       44 
     | 
    
         
            -
            Accept: */*
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            RESP
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
              attr_reader :complete, :parsing
         
     | 
| 
       49 
     | 
    
         
            -
              def initialize(conn, sock)
         
     | 
| 
       50 
     | 
    
         
            -
                @conn = conn
         
     | 
| 
       51 
     | 
    
         
            -
                @sock = sock
         
     | 
| 
       52 
     | 
    
         
            -
                @headers = request_header_hash
         
     | 
| 
       53 
     | 
    
         
            -
                @body = ''.b
         
     | 
| 
       54 
     | 
    
         
            -
                @complete, @parsing = false, false
         
     | 
| 
       55 
     | 
    
         
            -
                @parser = ::HTTP::Parser.new(self)
         
     | 
| 
       56 
     | 
    
         
            -
              end
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
              def request(uri)
         
     | 
| 
       59 
     | 
    
         
            -
                host = "#{uri.hostname}#{":#{uri.port}" if uri.port != uri.default_port}"
         
     | 
| 
       60 
     | 
    
         
            -
                req = format(UPGRADE_REQUEST, uri.request_uri, host)
         
     | 
| 
       61 
     | 
    
         
            -
                puts req
         
     | 
| 
       62 
     | 
    
         
            -
                @sock << req
         
     | 
| 
       63 
     | 
    
         
            -
              end
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
              def <<(data)
         
     | 
| 
       66 
     | 
    
         
            -
                @parsing ||= true
         
     | 
| 
       67 
     | 
    
         
            -
                @parser << data
         
     | 
| 
       68 
     | 
    
         
            -
                return unless complete
         
     | 
| 
       69 
     | 
    
         
            -
                upgrade
         
     | 
| 
       70 
     | 
    
         
            -
              end
         
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
       72 
     | 
    
         
            -
              def complete!
         
     | 
| 
       73 
     | 
    
         
            -
                @complete = true
         
     | 
| 
       74 
     | 
    
         
            -
              end
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
              def on_headers_complete(headers)
         
     | 
| 
       77 
     | 
    
         
            -
                @headers.merge!(headers)
         
     | 
| 
       78 
     | 
    
         
            -
                puts "received headers: #{headers}"
         
     | 
| 
       79 
     | 
    
         
            -
              end
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
              def on_body(chunk)
         
     | 
| 
       82 
     | 
    
         
            -
                puts "received chunk: #{chunk}"
         
     | 
| 
       83 
     | 
    
         
            -
                @body << chunk
         
     | 
| 
       84 
     | 
    
         
            -
              end
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
              def on_message_complete
         
     | 
| 
       87 
     | 
    
         
            -
                fail 'could not upgrade to h2c' unless @parser.status_code == 101
         
     | 
| 
       88 
     | 
    
         
            -
                @parsing = false
         
     | 
| 
       89 
     | 
    
         
            -
                complete!
         
     | 
| 
       90 
     | 
    
         
            -
              end
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
              def upgrade
         
     | 
| 
       93 
     | 
    
         
            -
                stream = @conn.upgrade
         
     | 
| 
       94 
     | 
    
         
            -
                log = Logger.new(stream.id)
         
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
                stream.on(:close) do
         
     | 
| 
       97 
     | 
    
         
            -
                  log.info 'stream closed'
         
     | 
| 
       98 
     | 
    
         
            -
                end
         
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
                stream.on(:half_close) do
         
     | 
| 
       101 
     | 
    
         
            -
                  log.info 'closing client-end of the stream'
         
     | 
| 
       102 
     | 
    
         
            -
                end
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
                stream.on(:headers) do |h|
         
     | 
| 
       105 
     | 
    
         
            -
                  log.info "response headers: #{h}"
         
     | 
| 
       106 
     | 
    
         
            -
                end
         
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
                stream.on(:data) do |d|
         
     | 
| 
       109 
     | 
    
         
            -
                  log.info "response data chunk: <<#{d}>>"
         
     | 
| 
       110 
     | 
    
         
            -
                end
         
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
                stream.on(:altsvc) do |f|
         
     | 
| 
       113 
     | 
    
         
            -
                  log.info "received ALTSVC #{f}"
         
     | 
| 
       114 
     | 
    
         
            -
                end
         
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
                @conn.on(:promise) do |promise|
         
     | 
| 
       117 
     | 
    
         
            -
                  promise.on(:headers) do |h|
         
     | 
| 
       118 
     | 
    
         
            -
                    log.info "promise headers: #{h}"
         
     | 
| 
       119 
     | 
    
         
            -
                  end
         
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
                  promise.on(:data) do |d|
         
     | 
| 
       122 
     | 
    
         
            -
                    log.info "promise data chunk: <<#{d.size}>>"
         
     | 
| 
       123 
     | 
    
         
            -
                  end
         
     | 
| 
       124 
     | 
    
         
            -
                end
         
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
                @conn.on(:altsvc) do |f|
         
     | 
| 
       127 
     | 
    
         
            -
                  log.info "received ALTSVC #{f}"
         
     | 
| 
       128 
     | 
    
         
            -
                end
         
     | 
| 
       129 
     | 
    
         
            -
              end
         
     | 
| 
       130 
     | 
    
         
            -
            end
         
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
            uh = UpgradeHandler.new(conn, sock)
         
     | 
| 
       133 
     | 
    
         
            -
            puts 'Sending HTTP/1.1 upgrade request'
         
     | 
| 
       134 
     | 
    
         
            -
            uh.request(uri)
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
            while !sock.closed? && !sock.eof?
         
     | 
| 
       137 
     | 
    
         
            -
              data = sock.read_nonblock(1024)
         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
              begin
         
     | 
| 
       140 
     | 
    
         
            -
                if !uh.parsing && !uh.complete
         
     | 
| 
       141 
     | 
    
         
            -
                  uh << data
         
     | 
| 
       142 
     | 
    
         
            -
                elsif uh.parsing && !uh.complete
         
     | 
| 
       143 
     | 
    
         
            -
                  uh << data
         
     | 
| 
       144 
     | 
    
         
            -
                elsif uh.complete
         
     | 
| 
       145 
     | 
    
         
            -
                  conn << data
         
     | 
| 
       146 
     | 
    
         
            -
                end
         
     | 
| 
       147 
     | 
    
         
            -
              rescue StandardError => e
         
     | 
| 
       148 
     | 
    
         
            -
                puts "#{e.class} exception: #{e.message} - closing socket."
         
     | 
| 
       149 
     | 
    
         
            -
                e.backtrace.each { |l| puts "\t" + l }
         
     | 
| 
       150 
     | 
    
         
            -
                conn.close
         
     | 
| 
       151 
     | 
    
         
            -
                sock.close
         
     | 
| 
       152 
     | 
    
         
            -
              end
         
     | 
| 
       153 
     | 
    
         
            -
            end
         
     |