rhenium/plum

View on GitHub
test/plum/hpack/test_decoder.rb

Summary

Maintainability
B
5 hrs
Test Coverage
require "test_helper"

class HPACKDecoderTest < Minitest::Test
  # C.1.1
  def test_hpack_read_integer_small
    buf = [0b11001010, 0b00001111].pack("C*")
    result, succ = new_decoder.__send__(:read_integer, buf, 0, 5)
    assert_equal(10, result)
    assert_equal(1, succ)
  end

  # C.1.2
  def test_hpack_read_integer_big
    buf = [0b11011111, 0b10011010, 0b00001010, 0b00001111].pack("C*")
    result, succ = new_decoder.__send__(:read_integer, buf, 0, 5)
    assert_equal(1337, result)
    assert_equal(3, succ)
  end

  # C.1.3
  def test_hpack_read_integer_8prefix
    buf = [0b00101010, 0b00001111].pack("C*")
    result, succ = new_decoder.__send__(:read_integer, buf, 0, 8)
    assert_equal(42, result)
    assert_equal(1, succ)
  end

  def test_hpack_read_integer_too_big
    buf = [0b11011111, 0b10011010, 0b10001010, 0b10001111, 0b11111111, 0b00000011].pack("C*")
    assert_raises(HPACKError) {
      new_decoder.__send__(:read_integer, buf, 0, 5)
    }
  end

  def test_hpack_read_integer_incomplete
    buf = [0b11011111, 0b10011010].pack("C*")
    assert_raises(HPACKError) {
      new_decoder.__send__(:read_integer, buf, 0, 5)
    }
  end

  # C.2.1
  def test_hpack_decode_indexing
    encoded = "\x40\x0acustom-key\x0dcustom-header"
    result = new_decoder.decode(encoded)
    assert_equal([["custom-key", "custom-header"]], result)
  end

  def test_hpack_decode_indexing_imcomplete
    encoded = "\x40\x0acus"
    assert_raises(HTTPError) {
      new_decoder.decode(encoded)
    }
  end

  # C.2.2
  def test_hpack_decode_without_indexing
    encoded = "\x04\x0c/sample/path"
    result = new_decoder.decode(encoded)
    assert_equal([[":path", "/sample/path"]], result)
  end

  # C.2.3
  def test_hpack_decode_without_indexing2
    encoded = "\x10\x08password\x06secret"
    result = new_decoder.decode(encoded)
    assert_equal([["password", "secret"]], result)
  end

  # C.2.4
  def test_hpack_decode_index
    encoded = "\x82"
    result = new_decoder.decode(encoded)
    assert_equal([[":method", "GET"]], result)
  end

  # C.3.1
  def test_hpack_decode_headers_without_huffman
    decoder = new_decoder
    encoded = "\x82\x86\x84\x41\x0f\x77\x77\x77\x2e\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d"
    result = decoder.decode(encoded)
    expected = [
      [":method", "GET"],
      [":scheme", "http"],
      [":path", "/"],
      [":authority", "www.example.com"]
    ]
    assert_equal(expected, result)

    decoder # for C.3.2
  end

  # C.3.2
  def test_hpack_decode_headers_without_huffman2
    decoder = test_hpack_decode_headers_without_huffman
    encoded = "\x82\x86\x84\xbe\x58\x08\x6e\x6f\x2d\x63\x61\x63\x68\x65"
    result = decoder.decode(encoded)
    expected = [
      [":method", "GET"],
      [":scheme", "http"],
      [":path", "/"],
      [":authority", "www.example.com"],
      ["cache-control", "no-cache"],
    ]
    assert_equal(expected, result)

    decoder # for C.3.3
  end

  # C.3.3
  def test_hpack_decode_headers_without_huffman3
    decoder = test_hpack_decode_headers_without_huffman2
    encoded = "\x82\x87\x85\xbf\x40\x0a\x63\x75\x73\x74\x6f\x6d\x2d\x6b\x65\x79\x0c\x63\x75\x73\x74\x6f\x6d\x2d\x76\x61\x6c\x75\x65"
    result = decoder.decode(encoded)
    expected = [
      [":method", "GET"],
      [":scheme", "https"],
      [":path", "/index.html"],
      [":authority", "www.example.com"],
      ["custom-key", "custom-value"],
    ]
    assert_equal(expected, result)
  end

  # C.4.1
  def test_hpack_decode_headers_with_huffman
    decoder = new_decoder
    encoded = "\x82\x86\x84\x41\x8c\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff"
    result = decoder.decode(encoded)
    expected = [
      [":method", "GET"],
      [":scheme", "http"],
      [":path", "/"],
      [":authority", "www.example.com"]
    ]
    assert_equal(expected, result)

    decoder # for C.4.2
  end

  # C.4.2
  def test_hpack_decode_headers_with_huffman2
    decoder = test_hpack_decode_headers_with_huffman
    encoded = "\x82\x86\x84\xbe\x58\x86\xa8\xeb\x10\x64\x9c\xbf"
    result = decoder.decode(encoded)
    expected = [
      [":method", "GET"],
      [":scheme", "http"],
      [":path", "/"],
      [":authority", "www.example.com"],
      ["cache-control", "no-cache"],
    ]
    assert_equal(expected, result)

    decoder # for C.4.3
  end

  # C.4.3
  def test_hpack_decode_headers_with_huffman3
    decoder = test_hpack_decode_headers_with_huffman2
    encoded = "\x82\x87\x85\xbf\x40\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f\x89\x25\xa8\x49\xe9\x5b\xb8\xe8\xb4\xbf"
    result = decoder.decode(encoded)
    expected = [
      [":method", "GET"],
      [":scheme", "https"],
      [":path", "/index.html"],
      [":authority", "www.example.com"],
      ["custom-key", "custom-value"],
    ]
    assert_equal(expected, result)
  end

  # C.5.1
  def test_hpack_decode_response_without_huffman
    decoder = new_decoder(256)
    encoded = "\x48\x03\x33\x30\x32\x58\x07\x70\x72\x69\x76\x61\x74\x65\x61\x1d\x4d\x6f\x6e\x2c\x20\x32\x31\x20\x4f\x63\x74\x20\x32\x30\x31\x33\x20\x32\x30\x3a\x31\x33\x3a\x32\x31\x20\x47\x4d\x54\x6e\x17\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d"
    result = decoder.decode(encoded)
    expected = [
      [":status", "302"],
      ["cache-control", "private"],
      ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
      ["location", "https://www.example.com"]
    ]
    assert_equal(expected, result)

    decoder # for C.5.2
  end

  # C.5.2
  def test_hpack_decode_response_without_huffman2
    decoder = test_hpack_decode_response_without_huffman
    encoded = "\x48\x03\x33\x30\x37\xc1\xc0\xbf"
    result = decoder.decode(encoded)
    expected = [
      [":status", "307"],
      ["cache-control", "private"],
      ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
      ["location", "https://www.example.com"]
    ]
    assert_equal(expected, result)
    refute_includes(decoder.dynamic_table, [":status", "302"]) # evicted

    decoder # for C.5.3
  end

  # C.5.3
  def test_hpack_decode_response_without_huffman3
    decoder = test_hpack_decode_response_without_huffman2
    encoded = "\x88\xc1\x61\x1d\x4d\x6f\x6e\x2c\x20\x32\x31\x20\x4f\x63\x74\x20\x32\x30\x31\x33\x20\x32\x30\x3a\x31\x33\x3a\x32\x32\x20\x47\x4d\x54\xc0\x5a\x04\x67\x7a\x69\x70\x77\x38\x66\x6f\x6f\x3d\x41\x53\x44\x4a\x4b\x48\x51\x4b\x42\x5a\x58\x4f\x51\x57\x45\x4f\x50\x49\x55\x41\x58\x51\x57\x45\x4f\x49\x55\x3b\x20\x6d\x61\x78\x2d\x61\x67\x65\x3d\x33\x36\x30\x30\x3b\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x31"
    result = decoder.decode(encoded)
    expected = [
      [":status", "200"],
      ["cache-control", "private"],
      ["date", "Mon, 21 Oct 2013 20:13:22 GMT"],
      ["location", "https://www.example.com"],
      ["content-encoding", "gzip"],
      ["set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"]
    ]
    assert_equal(expected, result)
  end

  # C.6.1
  def test_hpack_decode_response_with_huffman
    decoder = new_decoder(256)
    encoded = "\x48\x82\x64\x02\x58\x85\xae\xc3\x77\x1a\x4b\x61\x96\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66\xe0\x82\xa6\x2d\x1b\xff\x6e\x91\x9d\x29\xad\x17\x18\x63\xc7\x8f\x0b\x97\xc8\xe9\xae\x82\xae\x43\xd3"
    result = decoder.decode(encoded)
    expected = [
      [":status", "302"],
      ["cache-control", "private"],
      ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
      ["location", "https://www.example.com"]
    ]
    assert_equal(expected, result)

    decoder # for C.6.2
  end

  # C.6.2
  def test_hpack_decode_response_with_huffman2
    decoder = test_hpack_decode_response_with_huffman
    encoded = "\x48\x83\x64\x0e\xff\xc1\xc0\xbf"
    result = decoder.decode(encoded)
    expected = [
      [":status", "307"],
      ["cache-control", "private"],
      ["date", "Mon, 21 Oct 2013 20:13:21 GMT"],
      ["location", "https://www.example.com"]
    ]
    assert_equal(expected, result)
    refute_includes(decoder.dynamic_table, [":status", "302"]) # evicted

    decoder # for C.6.3
  end

  # C.6.3
  def test_hpack_decode_response_with_huffman3
    decoder = test_hpack_decode_response_with_huffman2
    encoded = "\x88\xc1\x61\x96\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66\xe0\x84\xa6\x2d\x1b\xff\xc0\x5a\x83\x9b\xd9\xab\x77\xad\x94\xe7\x82\x1d\xd7\xf2\xe6\xc7\xb3\x35\xdf\xdf\xcd\x5b\x39\x60\xd5\xaf\x27\x08\x7f\x36\x72\xc1\xab\x27\x0f\xb5\x29\x1f\x95\x87\x31\x60\x65\xc0\x03\xed\x4e\xe5\xb1\x06\x3d\x50\x07"
    result = decoder.decode(encoded)
    expected = [
      [":status", "200"],
      ["cache-control", "private"],
      ["date", "Mon, 21 Oct 2013 20:13:22 GMT"],
      ["location", "https://www.example.com"],
      ["content-encoding", "gzip"],
      ["set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"]
    ]
    assert_equal(expected, result)
  end

  def test_hpack_decode_index_zero
    decoder = new_decoder(256)
    encoded = "\x80"
    assert_raises(HPACKError) {
      decoder.decode(encoded)
    }
  end

  def test_hpack_decode_changing_limit
    decoder = new_decoder(256)
    encoded = "\x34"
    assert_equal(256, decoder.limit)
    decoder.decode(encoded)
    assert_equal(0b00010100, decoder.limit)
  end

  private
  def new_decoder(settings_header_table_size = 1 << 31)
    Plum::HPACK::Decoder.new(settings_header_table_size)
  end
end