http-2 1.0.1 → 1.0.2
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/lib/http/2/connection.rb +2 -3
- data/lib/http/2/extensions.rb +13 -15
- data/lib/http/2/framer.rb +26 -27
- data/lib/http/2/header/decompressor.rb +6 -6
- data/lib/http/2/header/encoding_context.rb +8 -6
- data/lib/http/2/header/huffman.rb +0 -2
- data/lib/http/2/header/huffman_statemachine.rb +1 -1
- data/lib/http/2/version.rb +1 -1
- data/sig/connection.rbs +1 -0
- data/sig/extensions.rbs +8 -0
- data/sig/framer.rbs +1 -0
- data/sig/header/decompressor.rbs +2 -0
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c96822381e28e32127984c2dbb7b25b3ad5dd87d69283a752378a9f8778c72ae
         | 
| 4 | 
            +
              data.tar.gz: beb68a1eb2670d1d0b742224b5ad65bd2bc299656433b120ff31299a481297ce
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 173e0163e2b05ff3eefdfcc420f8c3913c97702873964ef6c653f0329726443c4c10d73d7ffff31583b06567ef12c8f6545eae0f3d32c52d9b13d98322c09e32
         | 
| 7 | 
            +
              data.tar.gz: 43b38b2bdd3ed6ac90382b98c96b03fd76edefbbf4a385c67c3c8db67e6f755382f09c8a3af848a1d8ed55335ad2925d05793ad71c16c5bb831b07f86e0228be
         | 
    
        data/lib/http/2/connection.rb
    CHANGED
    
    | @@ -52,8 +52,7 @@ module HTTP2 | |
| 52 52 | 
             
                include FlowBuffer
         | 
| 53 53 | 
             
                include Emitter
         | 
| 54 54 | 
             
                include Error
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                using StringExtensions
         | 
| 55 | 
            +
                include BufferUtils
         | 
| 57 56 |  | 
| 58 57 | 
             
                # Connection state (:new, :closed).
         | 
| 59 58 | 
             
                attr_reader :state
         | 
| @@ -202,7 +201,7 @@ module HTTP2 | |
| 202 201 | 
             
                      raise HandshakeError unless CONNECTION_PREFACE_MAGIC.start_with? @recv_buffer
         | 
| 203 202 |  | 
| 204 203 | 
             
                      return # maybe next time
         | 
| 205 | 
            -
                    elsif @recv_buffer | 
| 204 | 
            +
                    elsif read_str(@recv_buffer, 24) == CONNECTION_PREFACE_MAGIC
         | 
| 206 205 | 
             
                      # MAGIC is OK.  Send our settings
         | 
| 207 206 | 
             
                      @state = :waiting_connection_preface
         | 
| 208 207 | 
             
                      payload = @local_settings.reject { |k, v| v == SPEC_DEFAULT_CONNECTION_SETTINGS[k] }
         | 
    
        data/lib/http/2/extensions.rb
    CHANGED
    
    | @@ -1,24 +1,22 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module HTTP2
         | 
| 4 | 
            -
              module  | 
| 5 | 
            -
                 | 
| 6 | 
            -
                   | 
| 7 | 
            -
                    return "".b if n == 0
         | 
| 4 | 
            +
              module BufferUtils
         | 
| 5 | 
            +
                def read_str(str, n)
         | 
| 6 | 
            +
                  return "".b if n == 0
         | 
| 8 7 |  | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 8 | 
            +
                  chunk = str.byteslice(0..n - 1)
         | 
| 9 | 
            +
                  remaining = str.byteslice(n..-1)
         | 
| 10 | 
            +
                  remaining ? str.replace(remaining) : str.clear
         | 
| 11 | 
            +
                  chunk
         | 
| 12 | 
            +
                end
         | 
| 14 13 |  | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 14 | 
            +
                def read_uint32(str)
         | 
| 15 | 
            +
                  read_str(str, 4).unpack1("N")
         | 
| 16 | 
            +
                end
         | 
| 18 17 |  | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
                  end
         | 
| 18 | 
            +
                def shift_byte(str)
         | 
| 19 | 
            +
                  read_str(str, 1).ord
         | 
| 22 20 | 
             
                end
         | 
| 23 21 | 
             
              end
         | 
| 24 22 |  | 
    
        data/lib/http/2/framer.rb
    CHANGED
    
    | @@ -4,10 +4,9 @@ module HTTP2 | |
| 4 4 | 
             
              # Performs encoding, decoding, and validation of binary HTTP/2 frames.
         | 
| 5 5 | 
             
              #
         | 
| 6 6 | 
             
              class Framer
         | 
| 7 | 
            -
                using StringExtensions
         | 
| 8 | 
            -
             | 
| 9 7 | 
             
                include Error
         | 
| 10 8 | 
             
                include PackingExtensions
         | 
| 9 | 
            +
                include BufferUtils
         | 
| 11 10 |  | 
| 12 11 | 
             
                # Default value of max frame size (16384 bytes)
         | 
| 13 12 | 
             
                DEFAULT_MAX_FRAME_SIZE = 2 << 13
         | 
| @@ -165,7 +164,7 @@ module HTTP2 | |
| 165 164 | 
             
                  frame[:type], = FRAME_TYPES.find { |_t, pos| type == pos }
         | 
| 166 165 | 
             
                  if frame[:type]
         | 
| 167 166 | 
             
                    frame[:flags] = FRAME_FLAGS[frame[:type]].each_with_object([]) do |(name, pos), acc|
         | 
| 168 | 
            -
                      acc << name if  | 
| 167 | 
            +
                      acc << name if flags.anybits?((1 << pos))
         | 
| 169 168 | 
             
                    end
         | 
| 170 169 | 
             
                  end
         | 
| 171 170 |  | 
| @@ -344,8 +343,8 @@ module HTTP2 | |
| 344 343 |  | 
| 345 344 | 
             
                  raise ProtocolError, "payload too large" if frame[:length] > @local_max_frame_size
         | 
| 346 345 |  | 
| 347 | 
            -
                  buf | 
| 348 | 
            -
                  payload = buf | 
| 346 | 
            +
                  read_str(buf, 9)
         | 
| 347 | 
            +
                  payload = read_str(buf, frame[:length])
         | 
| 349 348 |  | 
| 350 349 | 
             
                  # Implementations MUST discard frames
         | 
| 351 350 | 
             
                  # that have unknown or unsupported types.
         | 
| @@ -357,7 +356,7 @@ module HTTP2 | |
| 357 356 | 
             
                  if FRAME_TYPES_WITH_PADDING.include?(frame[:type])
         | 
| 358 357 | 
             
                    padded = frame[:flags].include?(:padded)
         | 
| 359 358 | 
             
                    if padded
         | 
| 360 | 
            -
                      padlen = payload | 
| 359 | 
            +
                      padlen = read_str(payload, 1).unpack1(UINT8)
         | 
| 361 360 | 
             
                      frame[:padding] = padlen + 1
         | 
| 362 361 | 
             
                      raise ProtocolError, "padding too long" if padlen > payload.bytesize
         | 
| 363 362 |  | 
| @@ -369,30 +368,30 @@ module HTTP2 | |
| 369 368 |  | 
| 370 369 | 
             
                  case frame[:type]
         | 
| 371 370 | 
             
                  when :data, :ping, :continuation
         | 
| 372 | 
            -
                    frame[:payload] = payload | 
| 371 | 
            +
                    frame[:payload] = read_str(payload, frame[:length])
         | 
| 373 372 | 
             
                  when :headers
         | 
| 374 373 | 
             
                    if frame[:flags].include? :priority
         | 
| 375 | 
            -
                      e_sd = payload | 
| 374 | 
            +
                      e_sd = read_uint32(payload)
         | 
| 376 375 | 
             
                      frame[:dependency] = e_sd & RBIT
         | 
| 377 | 
            -
                      frame[:exclusive] = ( | 
| 376 | 
            +
                      frame[:exclusive] = e_sd.anybits?(EBIT)
         | 
| 378 377 | 
             
                      weight = payload.byteslice(0, 1).ord + 1
         | 
| 379 378 | 
             
                      frame[:weight] = weight
         | 
| 380 379 | 
             
                      payload = payload.byteslice(1..-1)
         | 
| 381 380 | 
             
                    end
         | 
| 382 | 
            -
                    frame[:payload] = payload | 
| 381 | 
            +
                    frame[:payload] = read_str(payload, frame[:length])
         | 
| 383 382 | 
             
                  when :priority
         | 
| 384 383 | 
             
                    raise FrameSizeError, "Invalid length for PRIORITY_STREAM (#{frame[:length]} != 5)" if frame[:length] != 5
         | 
| 385 384 |  | 
| 386 | 
            -
                    e_sd = payload | 
| 385 | 
            +
                    e_sd = read_uint32(payload)
         | 
| 387 386 | 
             
                    frame[:dependency] = e_sd & RBIT
         | 
| 388 | 
            -
                    frame[:exclusive] = ( | 
| 387 | 
            +
                    frame[:exclusive] = e_sd.anybits?(EBIT)
         | 
| 389 388 | 
             
                    weight = payload.byteslice(0, 1).ord + 1
         | 
| 390 389 | 
             
                    frame[:weight] = weight
         | 
| 391 390 | 
             
                    payload = payload.byteslice(1..-1)
         | 
| 392 391 | 
             
                  when :rst_stream
         | 
| 393 392 | 
             
                    raise FrameSizeError, "Invalid length for RST_STREAM (#{frame[:length]} != 4)" if frame[:length] != 4
         | 
| 394 393 |  | 
| 395 | 
            -
                    frame[:error] = unpack_error payload | 
| 394 | 
            +
                    frame[:error] = unpack_error read_uint32(payload)
         | 
| 396 395 |  | 
| 397 396 | 
             
                  when :settings
         | 
| 398 397 | 
             
                    # NOTE: frame[:length] might not match the number of frame[:payload]
         | 
| @@ -403,8 +402,8 @@ module HTTP2 | |
| 403 402 | 
             
                    raise ProtocolError, "Invalid stream ID (#{frame[:stream]})" if (frame[:stream]).nonzero?
         | 
| 404 403 |  | 
| 405 404 | 
             
                    (frame[:length] / 6).times do
         | 
| 406 | 
            -
                      id  = payload | 
| 407 | 
            -
                      val = payload | 
| 405 | 
            +
                      id  = read_str(payload, 2).unpack1(UINT16)
         | 
| 406 | 
            +
                      val = read_uint32(payload)
         | 
| 408 407 |  | 
| 409 408 | 
             
                      # Unsupported or unrecognized settings MUST be ignored.
         | 
| 410 409 | 
             
                      # Here we send it along.
         | 
| @@ -412,39 +411,39 @@ module HTTP2 | |
| 412 411 | 
             
                      frame[:payload] << [name, val] if name
         | 
| 413 412 | 
             
                    end
         | 
| 414 413 | 
             
                  when :push_promise
         | 
| 415 | 
            -
                    frame[:promise_stream] = payload | 
| 416 | 
            -
                    frame[:payload] = payload | 
| 414 | 
            +
                    frame[:promise_stream] = read_uint32(payload) & RBIT
         | 
| 415 | 
            +
                    frame[:payload] = read_str(payload, frame[:length])
         | 
| 417 416 | 
             
                  when :goaway
         | 
| 418 | 
            -
                    frame[:last_stream] = payload | 
| 419 | 
            -
                    frame[:error] = unpack_error payload | 
| 417 | 
            +
                    frame[:last_stream] = read_uint32(payload) & RBIT
         | 
| 418 | 
            +
                    frame[:error] = unpack_error read_uint32(payload)
         | 
| 420 419 |  | 
| 421 420 | 
             
                    size = frame[:length] - 8 # for last_stream and error
         | 
| 422 | 
            -
                    frame[:payload] = payload | 
| 421 | 
            +
                    frame[:payload] = read_str(payload, size) if size > 0
         | 
| 423 422 | 
             
                  when :window_update
         | 
| 424 423 | 
             
                    if frame[:length] % 4 != 0
         | 
| 425 424 | 
             
                      raise FrameSizeError, "Invalid length for WINDOW_UPDATE (#{frame[:length]} not multiple of 4)"
         | 
| 426 425 | 
             
                    end
         | 
| 427 426 |  | 
| 428 | 
            -
                    frame[:increment] = payload | 
| 427 | 
            +
                    frame[:increment] = read_uint32(payload) & RBIT
         | 
| 429 428 | 
             
                  when :altsvc
         | 
| 430 | 
            -
                    frame[:max_age], frame[:port] = payload | 
| 429 | 
            +
                    frame[:max_age], frame[:port] = read_str(payload, 6).unpack(UINT32 + UINT16)
         | 
| 431 430 |  | 
| 432 431 | 
             
                    len = payload.byteslice(0, 1).ord
         | 
| 433 432 | 
             
                    payload = payload.byteslice(1..-1)
         | 
| 434 | 
            -
                    frame[:proto] = payload | 
| 433 | 
            +
                    frame[:proto] = read_str(payload, len) if len > 0
         | 
| 435 434 |  | 
| 436 435 | 
             
                    len = payload.byteslice(0, 1).ord
         | 
| 437 436 | 
             
                    payload = payload.byteslice(1..-1)
         | 
| 438 | 
            -
                    frame[:host] = payload | 
| 437 | 
            +
                    frame[:host] = read_str(payload, len) if len > 0
         | 
| 439 438 |  | 
| 440 | 
            -
                    frame[:origin] =  | 
| 439 | 
            +
                    frame[:origin] = read_str(payload, payload.size) unless payload.empty?
         | 
| 441 440 |  | 
| 442 441 | 
             
                  when :origin
         | 
| 443 442 | 
             
                    origins = []
         | 
| 444 443 |  | 
| 445 444 | 
             
                    until payload.empty?
         | 
| 446 | 
            -
                      len = payload | 
| 447 | 
            -
                      origins << payload | 
| 445 | 
            +
                      len = read_str(payload, 2).unpack1(UINT16)
         | 
| 446 | 
            +
                      origins << read_str(payload, len)
         | 
| 448 447 | 
             
                    end
         | 
| 449 448 |  | 
| 450 449 | 
             
                    frame[:payload] = origins
         | 
| @@ -2,7 +2,6 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module HTTP2
         | 
| 4 4 | 
             
              module Header
         | 
| 5 | 
            -
                using StringExtensions
         | 
| 6 5 | 
             
                # Responsible for decoding received headers and maintaining compression
         | 
| 7 6 | 
             
                # context of the opposing peer. Decompressor must be initialized with
         | 
| 8 7 | 
             
                # appropriate starting context based on local role: client or server.
         | 
| @@ -12,6 +11,7 @@ module HTTP2 | |
| 12 11 | 
             
                #   client_role = Decompressor.new(:response)
         | 
| 13 12 | 
             
                class Decompressor
         | 
| 14 13 | 
             
                  include Error
         | 
| 14 | 
            +
                  include BufferUtils
         | 
| 15 15 |  | 
| 16 16 | 
             
                  # @param options [Hash] decoding options.  Only :table_size is effective.
         | 
| 17 17 | 
             
                  def initialize(options = {})
         | 
| @@ -31,15 +31,15 @@ module HTTP2 | |
| 31 31 | 
             
                  # @return [Integer]
         | 
| 32 32 | 
             
                  def integer(buf, n)
         | 
| 33 33 | 
             
                    limit = (2**n) - 1
         | 
| 34 | 
            -
                    i = n.zero? ? 0 : (buf | 
| 34 | 
            +
                    i = n.zero? ? 0 : (shift_byte(buf) & limit)
         | 
| 35 35 |  | 
| 36 36 | 
             
                    m = 0
         | 
| 37 37 | 
             
                    if i == limit
         | 
| 38 | 
            -
                      while (byte = buf | 
| 38 | 
            +
                      while (byte = shift_byte(buf))
         | 
| 39 39 | 
             
                        i += ((byte & 127) << m)
         | 
| 40 40 | 
             
                        m += 7
         | 
| 41 41 |  | 
| 42 | 
            -
                        break if ( | 
| 42 | 
            +
                        break if byte.nobits?(128)
         | 
| 43 43 | 
             
                      end
         | 
| 44 44 | 
             
                    end
         | 
| 45 45 |  | 
| @@ -54,9 +54,9 @@ module HTTP2 | |
| 54 54 | 
             
                  def string(buf)
         | 
| 55 55 | 
             
                    raise CompressionError, "invalid header block fragment" if buf.empty?
         | 
| 56 56 |  | 
| 57 | 
            -
                    huffman =  | 
| 57 | 
            +
                    huffman = buf.getbyte(0).allbits?(0x80)
         | 
| 58 58 | 
             
                    len = integer(buf, 7)
         | 
| 59 | 
            -
                    str = buf | 
| 59 | 
            +
                    str = read_str(buf, len)
         | 
| 60 60 | 
             
                    raise CompressionError, "string too short" unless str.bytesize == len
         | 
| 61 61 |  | 
| 62 62 | 
             
                    str = Huffman.new.decode(str) if huffman
         | 
| @@ -75,12 +75,14 @@ module HTTP2 | |
| 75 75 | 
             
                    ["vary",                        ""],
         | 
| 76 76 | 
             
                    ["via",                         ""],
         | 
| 77 77 | 
             
                    ["www-authenticate",            ""]
         | 
| 78 | 
            -
                  ].each | 
| 79 | 
            -
             | 
| 80 | 
            -
                  STATIC_TABLE_BY_FIELD = | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 78 | 
            +
                  ].each(&:freeze).freeze
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  STATIC_TABLE_BY_FIELD =
         | 
| 81 | 
            +
                    STATIC_TABLE
         | 
| 82 | 
            +
                    .each_with_object({})
         | 
| 83 | 
            +
                    .with_index { |((field, value), hs), idx| (hs[field] ||= []) << [idx, value].freeze }
         | 
| 84 | 
            +
                    .each_value(&:freeze)
         | 
| 85 | 
            +
                    .freeze
         | 
| 84 86 |  | 
| 85 87 | 
             
                  STATIC_TABLE_SIZE = STATIC_TABLE.size
         | 
| 86 88 |  | 
| @@ -268,7 +268,7 @@ module HTTP2 | |
| 268 268 | 
             
                    [[28, 29], [28, 5], [29, 29], [29, 5], [30, 29], [30, 5], [31, 29], [31, 5], [127, 29], [127, 5], [220, 29], [220, 5], [249, 29], [249, 5], [nil, 254], [nil, 255]],
         | 
| 269 269 | 
             
                    [[10, 17], [10, 18], [10, 19], [10, 20], [10, 21], [10, 22], [10, 23], [10, 7], [13, 17], [13, 18], [13, 19], [13, 20], [13, 21], [13, 22], [13, 23], [13, 7]],
         | 
| 270 270 | 
             
                    [[22, 17], [22, 18], [22, 19], [22, 20], [22, 21], [22, 22], [22, 23], [22, 7], [256, 17], [256, 18], [256, 19], [256, 20], [256, 21], [256, 22], [256, 23], [256, 7]],
         | 
| 271 | 
            -
                  ].each { |arr| arr.each { |subarr| subarr. | 
| 271 | 
            +
                  ].each { |arr| arr.each { |subarr| subarr.freeze }.freeze }.freeze
         | 
| 272 272 | 
             
                end
         | 
| 273 273 | 
             
              end
         | 
| 274 274 | 
             
            end
         | 
    
        data/lib/http/2/version.rb
    CHANGED
    
    
    
        data/sig/connection.rbs
    CHANGED
    
    
    
        data/sig/extensions.rbs
    CHANGED
    
    | @@ -1,4 +1,12 @@ | |
| 1 1 | 
             
            module HTTP2
         | 
| 2 | 
            +
              module BufferUtils
         | 
| 3 | 
            +
                def read_str: (String str, Integer n) -> String
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def read_uint32: (String str) -> Integer
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def shift_byte: (String str) -> Integer
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 2 10 | 
             
              module PackingExtensions
         | 
| 3 11 | 
             
                def pack: (Array[Integer] array_to_pack, String template, buffer: String, ?offset: Integer) -> String
         | 
| 4 12 | 
             
              end
         | 
    
        data/sig/framer.rbs
    CHANGED
    
    
    
        data/sig/header/decompressor.rbs
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: http-2
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.0. | 
| 4 | 
            +
              version: 1.0.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Tiago Cardoso
         | 
| @@ -10,7 +10,7 @@ authors: | |
| 10 10 | 
             
            autorequire:
         | 
| 11 11 | 
             
            bindir: bin
         | 
| 12 12 | 
             
            cert_chain: []
         | 
| 13 | 
            -
            date: 2024- | 
| 13 | 
            +
            date: 2024-11-05 00:00:00.000000000 Z
         | 
| 14 14 | 
             
            dependencies: []
         | 
| 15 15 | 
             
            description: Pure-ruby HTTP 2.0 protocol implementation
         | 
| 16 16 | 
             
            email:
         |