pax_global_header00006660000000000000000000000064136152764770014534gustar00rootroot0000000000000052 comment=031b055eeea20f42facd65e1b57e6d8af93292f3 ruby-protocol-hpack-1.4.2/000077500000000000000000000000001361527647700154445ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/.editorconfig000066400000000000000000000000651361527647700201220ustar00rootroot00000000000000root = true [*] indent_style = tab indent_size = 2 ruby-protocol-hpack-1.4.2/.gitignore000066400000000000000000000001751361527647700174370ustar00rootroot00000000000000/.bundle/ /.yardoc /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ # rspec failure tracking .rspec_status Gemfile.lockruby-protocol-hpack-1.4.2/.gitmodules000066400000000000000000000002061361527647700176170ustar00rootroot00000000000000[submodule "spec/protocol/hpack/fixtures"] path = spec/protocol/hpack/fixtures url = https://github.com/http2jp/hpack-test-case.git ruby-protocol-hpack-1.4.2/.rspec000066400000000000000000000000671361527647700165640ustar00rootroot00000000000000--format documentation --warnings --require spec_helperruby-protocol-hpack-1.4.2/.travis.yml000066400000000000000000000005621361527647700175600ustar00rootroot00000000000000language: ruby dist: xenial cache: bundler matrix: include: - rvm: 2.4 - rvm: 2.5 - rvm: 2.6 - rvm: 2.7 - rvm: 2.6 env: COVERAGE=PartialSummary,Coveralls - rvm: truffleruby - rvm: jruby-head env: JRUBY_OPTS="--debug -X+O" - rvm: ruby-head allow_failures: - rvm: truffleruby - rvm: ruby-head - rvm: jruby-head ruby-protocol-hpack-1.4.2/Gemfile000066400000000000000000000002021361527647700167310ustar00rootroot00000000000000# frozen_string_literal: true source "https://rubygems.org" # Specify your gem's dependencies in protocol-hpack.gemspec gemspec ruby-protocol-hpack-1.4.2/README.md000066400000000000000000000047251361527647700167330ustar00rootroot00000000000000# Protocol::HPACK Provides a compressor and decompressor for HTTP 2.0 headers, HPACK, as defined by [RFC7541](https://tools.ietf.org/html/rfc7541). [![Build Status](https://secure.travis-ci.com/socketry/protocol-hpack.svg)](http://travis-ci.com/socketry/protocol-hpack) [![Coverage Status](https://coveralls.io/repos/github/socketry/protocol-hpack/badge.svg?branch=master)](https://coveralls.io/github/socketry/protocol-hpack?branch=master) ## Installation Add this line to your application's Gemfile: ```ruby gem 'protocol-hpack' ``` And then execute: $ bundle Or install it yourself as: $ gem install protocol-hpack ## Usage ### Compressing Headers ```ruby require 'protocol/hpack' buffer = String.new.b compressor = Protocol::HPACK::Compressor.new(buffer) compressor.encode([['content-length', '5']]) => "\\\x015" ``` ### Decompressing Headers Reusing `buffer` from above: ```ruby require 'protocol/hpack' # Buffer from above... buffer = "\\\x015" decompressor = Protocol::HPACK::Decompressor.new(buffer) decompressor.decode => [["content-length", "5"]] ``` ## Contributing 1. Fork it 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request ## License Released under the MIT license. Copyright, 2019, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams). Copyright, 2013, by Ilya Grigorik. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ruby-protocol-hpack-1.4.2/Rakefile000066400000000000000000000002571361527647700171150ustar00rootroot00000000000000# frozen_string_literal: true require "bundler/gem_tasks" require "rspec/core/rake_task" RSpec::Core::RakeTask.new(:spec) task :default => :spec load *Dir["tasks/*.rake"] ruby-protocol-hpack-1.4.2/http-hpack.gemspec000066400000000000000000000014101361527647700210500ustar00rootroot00000000000000 require_relative "lib/protocol/hpack/version" Gem::Specification.new do |spec| spec.name = "protocol-hpack" spec.version = Protocol::HPACK::VERSION spec.licenses = ["MIT"] spec.authors = ["Samuel Williams"] spec.email = ["samuel.williams@oriontransfer.co.nz"] spec.summary = "A compresssor and decompressor for HTTP 2.0 HPACK." spec.homepage = "https://github.com/socketry/http-hpack" spec.files = `git ls-files -z`.split("\x0").reject do |f| f.match(%r{^(test|spec|features)/}) end spec.require_paths = ["lib"] spec.add_development_dependency "covered" spec.add_development_dependency "bundler" spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.0" end ruby-protocol-hpack-1.4.2/lib/000077500000000000000000000000001361527647700162125ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/lib/protocol/000077500000000000000000000000001361527647700200535ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/lib/protocol/hpack.rb000066400000000000000000000023701361527647700214700ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require_relative "hpack/version" require_relative 'hpack/compressor' require_relative 'hpack/decompressor' ruby-protocol-hpack-1.4.2/lib/protocol/hpack/000077500000000000000000000000001361527647700211415ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/lib/protocol/hpack/compressor.rb000066400000000000000000000142211361527647700236620ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require_relative 'context' require_relative 'huffman' module Protocol module HPACK # Predefined options set for Compressor # http://mew.org/~kazu/material/2014-hpack.pdf NAIVE = {index: :never, huffman: :never} LINEAR = {index: :all, huffman: :never} STATIC = {index: :static, huffman: :never} SHORTER = {index: :all, huffman: :never} NAIVE_HUFFMAN = {index: :never, huffman: :always} LINEAR_HUFFMAN = {index: :all, huffman: :always} STATIC_HUFFMAN = {index: :static, huffman: :always} SHORTER_HUFFMAN = {index: :all, huffman: :shorter} MODES = { naive: NAIVE, linear: LINEAR, static: STATIC, shorter: SHORTER, naive_huffman: NAIVE_HUFFMAN, linear_huffman: NAIVE_HUFFMAN, static_huffman: NAIVE_HUFFMAN, shorter_huffman: NAIVE_HUFFMAN, } # Responsible for encoding header key-value pairs using HPACK algorithm. class Compressor def initialize(buffer, context = Context.new, table_size_limit: nil) @buffer = buffer @context = context @table_size_limit = table_size_limit end attr :table_size_limit attr :buffer attr :context attr :offset def write_byte(byte) @buffer << byte.chr end def write_bytes(bytes) @buffer << bytes end # Encodes provided value via integer representation. # - http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-10#section-5.1 # # If I < 2^N - 1, encode I on N bits # Else # encode 2^N - 1 on N bits # I = I - (2^N - 1) # While I >= 128 # Encode (I % 128 + 128) on 8 bits # I = I / 128 # encode (I) on 8 bits # # @param value [Integer] value to encode # @param bits [Integer] number of available bits # @return [String] binary string def write_integer(value, bits) limit = 2**bits - 1 return write_bytes([value].pack('C')) if value < limit bytes = [] bytes.push(limit) unless bits.zero? value -= limit while value >= 128 bytes.push((value % 128) + 128) value /= 128 end bytes.push(value) write_bytes(bytes.pack('C*')) end def huffman @context.huffman end # Encodes provided value via string literal representation. # - http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-10#section-5.2 # # * The string length, defined as the number of bytes needed to store # its UTF-8 representation, is represented as an integer with a seven # bits prefix. If the string length is strictly less than 127, it is # represented as one byte. # * If the bit 7 of the first byte is 1, the string value is represented # as a list of Huffman encoded octets # (padded with bit 1's until next octet boundary). # * If the bit 7 of the first byte is 0, the string value is # represented as a list of UTF-8 encoded octets. # # +@options [:huffman]+ controls whether to use Huffman encoding: # :never Do not use Huffman encoding # :always Always use Huffman encoding # :shorter Use Huffman when the result is strictly shorter # # @param string [String] # @return [String] binary string def write_string(string, huffman = self.huffman) if huffman != :never encoded = Huffman.new.encode(string) if huffman == :shorter and encoded.bytesize >= string.bytesize encoded = nil end end if encoded first = @buffer.bytesize write_integer(encoded.bytesize, 7) write_bytes(encoded.b) @buffer.setbyte(first, @buffer.getbyte(first).ord | 0x80) else write_integer(string.bytesize, 7) write_bytes(string.b) end end # Encodes header command with appropriate header representation. # # @param h [Hash] header command # @param buffer [String] # @return [Buffer] def write_header(command) representation = HEADER_REPRESENTATION[command[:type]] first = @buffer.bytesize case command[:type] when :indexed write_integer(command[:name] + 1, representation[:prefix]) when :change_table_size write_integer(command[:value], representation[:prefix]) else if command[:name].is_a? Integer write_integer(command[:name] + 1, representation[:prefix]) else write_integer(0, representation[:prefix]) write_string(command[:name]) end write_string(command[:value]) end # set header representation pattern on first byte @buffer.setbyte(first, @buffer.getbyte(first) | representation[:pattern]) end # Encodes provided list of HTTP headers. # # @param headers [Array] +[[name, value], ...]+ # @return [Buffer] def encode(headers, table_size = @table_size_limit) if table_size and table_size != @context.table_size command = @context.change_table_size(table_size) write_header(command) end commands = @context.encode(headers) commands.each do |command| write_header(command) end return @buffer end end end end ruby-protocol-hpack-1.4.2/lib/protocol/hpack/context.rb000066400000000000000000000240631361527647700231570ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require_relative 'huffman' module Protocol # Implementation of header compression for HTTP 2.0 (HPACK) format adapted # to efficiently represent HTTP headers in the context of HTTP 2.0. # # - http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-10 module HPACK # Header representation as defined by the spec. HEADER_REPRESENTATION = { indexed: {prefix: 7, pattern: 0x80}, incremental: {prefix: 6, pattern: 0x40}, no_index: {prefix: 4, pattern: 0x00}, never_indexed: {prefix: 4, pattern: 0x10}, change_table_size: {prefix: 5, pattern: 0x20}, } # To decompress header blocks, a decoder only needs to maintain a # dynamic table as a decoding context. # No other state information is needed. class Context # Static header table. # https://tools.ietf.org/html/rfc7541#appendix-A STATIC_TABLE = [ [":authority", ""], [":method", "GET"], [":method", "POST"], [":path", "/"], [":path", "/index.html"], [":scheme", "http"], [":scheme", "https"], [":status", "200"], [":status", "204"], [":status", "206"], [":status", "304"], [":status", "400"], [":status", "404"], [":status", "500"], ["accept-charset", ""], ["accept-encoding", "gzip, deflate"], ["accept-language", ""], ["accept-ranges", ""], ["accept", ""], ["access-control-allow-origin", ""], ["age", ""], ["allow", ""], ["authorization", ""], ["cache-control", ""], ["content-disposition", ""], ["content-encoding", ""], ["content-language", ""], ["content-length", ""], ["content-location", ""], ["content-range", ""], ["content-type", ""], ["cookie", ""], ["date", ""], ["etag", ""], ["expect", ""], ["expires", ""], ["from", ""], ["host", ""], ["if-match", ""], ["if-modified-since", ""], ["if-none-match", ""], ["if-range", ""], ["if-unmodified-since", ""], ["last-modified", ""], ["link", ""], ["location", ""], ["max-forwards", ""], ["proxy-authenticate", ""], ["proxy-authorization", ""], ["range", ""], ["referer", ""], ["refresh", ""], ["retry-after", ""], ["server", ""], ["set-cookie", ""], ["strict-transport-security", ""], ["transfer-encoding", ""], ["user-agent", ""], ["vary", ""], ["via", ""], ["www-authenticate", ""], ].each(&:freeze).freeze # Initializes compression context with appropriate client/server defaults and maximum size of the dynamic table. # # @param table [Array] Table of header key-value pairs. # @option huffman [Symbol] One of `:always`, `:never`, `:shorter`. Controls use of compression. # @option index [Symbol] One of `:all`, `:static`, `:never`. Controls use of static/dynamic tables. # @option table_size [Integer] The current maximum dynamic table size. def initialize(table = nil, huffman: :shorter, index: :all, table_size: 4096) @huffman = huffman @index = index @table_size = table_size @table = (table&.dup) || [] end def initialize_copy(other) super # This is the only mutable state: @table = @table.dup end # Current table of header key-value pairs. attr :table attr :huffman attr :index attr :table_size # Finds an entry in current dynamic table by index. # Note that index is zero-based in this module. # # If the index is greater than the last index in the static table, # an entry in the dynamic table is dereferenced. # # If the index is greater than the last header index, an error is raised. # # @param index [Integer] zero-based index in the dynamic table. # @return [Array] +[key, value]+ def dereference(index) # NOTE: index is zero-based in this module. value = STATIC_TABLE[index] || @table[index - STATIC_TABLE.size] if value.nil? raise CompressionError, "Index #{index} too large!" end return value end # Header Block Processing # - http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-10#section-4.1 # # @param command [Hash] {type:, name:, value:, index:} # @return [Array] +[name, value]+ header field that is added to the decoded header list def decode(command) emit = nil case command[:type] when :change_table_size self.table_size = command[:value] when :indexed # Indexed Representation # An _indexed representation_ entails the following actions: # o The header field corresponding to the referenced entry in either # the static table or dynamic table is added to the decoded header # list. idx = command[:name] k, v = dereference(idx) emit = [k, v] when :incremental, :no_index, :never_indexed # A _literal representation_ that is _not added_ to the dynamic table # entails the following action: # o The header field is added to the decoded header list. # A _literal representation_ that is _added_ to the dynamic table # entails the following actions: # o The header field is added to the decoded header list. # o The header field is inserted at the beginning of the dynamic table. if command[:name].is_a? Integer k, v = dereference(command[:name]) command = command.dup command[:index] ||= command[:name] command[:value] ||= v command[:name] = k end emit = [command[:name], command[:value]] add_to_table(emit) if command[:type] == :incremental else raise CompressionError, "Invalid type: #{command[:type]}" end return emit end # Plan header compression according to +@index+ # :never Do not use dynamic table or static table reference at all. # :static Use static table only. # :all Use all of them. # # @param headers [Array] +[[name, value], ...]+ # @return [Array] array of commands def encode(headers) commands = [] # Literals commands are marked with :no_index when index is not used no_index = [:static, :never].include?(@index) headers.each do |field, value| command = add_command(field, value) command[:type] = :no_index if no_index && command[:type] == :incremental commands << command decode(command) end return commands end # Emits command for a header. # Prefer static table over dynamic table. # Prefer exact match over name-only match. # # +@index+ controls whether to use the dynamic table, # static table, or both. # :never Do not use dynamic table or static table reference at all. # :static Use static table only. # :all Use all of them. # # @param header [Array] +[name, value]+ # @return [Hash] command def add_command(*header) exact = nil name_only = nil if [:all, :static].include?(@index) STATIC_TABLE.each_index do |i| if STATIC_TABLE[i] == header exact ||= i break elsif STATIC_TABLE[i].first == header.first name_only ||= i end end end if [:all].include?(@index) && !exact @table.each_index do |i| if @table[i] == header exact ||= i + STATIC_TABLE.size break elsif @table[i].first == header.first name_only ||= i + STATIC_TABLE.size end end end if exact {name: exact, type: :indexed} elsif name_only {name: name_only, value: header.last, type: :incremental} else {name: header.first, value: header.last, type: :incremental} end end # Alter dynamic table size. # When the size is reduced, some headers might be evicted. def table_size= size @table_size = size size_check(nil) end def change_table_size(size) self.table_size = size # The command to resize the table: return {type: :change_table_size, value: size} end # Returns current table size in octets # @return [Integer] def current_table_size @table.inject(0) {|r, (k, v)| r + k.bytesize + v.bytesize + 32} end private # Add a name-value pair to the dynamic table. Older entries might have been evicted so that the new entry fits in the dynamic table. The command and the component strings will be frozen. # # @param command [Array] +[name, value]+ def add_to_table(command) return unless size_check(command) command.each(&:freeze) command.freeze @table.unshift(command) end # To keep the dynamic table size lower than or equal to @table_size, # remove one or more entries at the end of the dynamic table. # # @param command [Hash] # @return [Boolean] whether +command+ fits in the dynamic table. def size_check(command) cursize = current_table_size cmdsize = command.nil? ? 0 : command[0].bytesize + command[1].bytesize + 32 while cursize + cmdsize > @table_size break if @table.empty? e = @table.pop cursize -= e[0].bytesize + e[1].bytesize + 32 end cmdsize <= @table_size end end end end ruby-protocol-hpack-1.4.2/lib/protocol/hpack/decompressor.rb000066400000000000000000000110211361527647700241660ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require_relative 'context' require_relative 'huffman' module Protocol module HPACK # Responsible for decoding received headers and maintaining compression # context of the opposing peer. Decompressor must be initialized with # appropriate starting context based on local role: client or server. class Decompressor def initialize(buffer, context = Context.new, table_size_limit: nil) @buffer = buffer @context = context @offset = 0 @table_size_limit = table_size_limit end attr :buffer attr :context attr :offset attr :table_size_limit def end? @offset >= @buffer.bytesize end def read_byte if byte = @buffer.getbyte(@offset) @offset += 1 end return byte end def peek_byte @buffer.getbyte(@offset) end def read_bytes(length) slice = @buffer.byteslice(@offset, length) @offset += length return slice end # Decodes integer value from provided buffer. # # @param bits [Integer] number of available bits # @return [Integer] def read_integer(bits) limit = 2**bits - 1 value = bits.zero? ? 0 : (read_byte & limit) shift = 0 while byte = read_byte value += ((byte & 127) << shift) shift += 7 break if (byte & 128).zero? end if (value == limit) return value end # Decodes string value from provided buffer. # # @return [String] UTF-8 encoded string # @raise [CompressionError] when input is malformed def read_string huffman = (peek_byte & 0x80) == 0x80 length = read_integer(7) raise CompressionError, "Invalid string length!" unless length string = read_bytes(length) raise CompressionError, "Invalid string length, got #{string.bytesize}, expecting #{length}!" unless string.bytesize == length string = Huffman.new.decode(string) if huffman return string.force_encoding(Encoding::UTF_8) end # Decodes header command from provided buffer. # # @param buffer [Buffer] # @return [Hash] command def read_header pattern = peek_byte header = {} header[:type], type = HEADER_REPRESENTATION.find do |_t, desc| mask = (pattern >> desc[:prefix]) << desc[:prefix] mask == desc[:pattern] end raise CompressionError unless header[:type] header[:name] = read_integer(type[:prefix]) case header[:type] when :indexed raise CompressionError if header[:name].zero? header[:name] -= 1 when :change_table_size header[:value] = header[:name] if @table_size_limit and header[:value] > @table_size_limit raise CompressionError, "Table size #{header[:value]} exceeds limit #{@table_size_limit}!" end else if (header[:name]).zero? header[:name] = read_string else header[:name] -= 1 end header[:value] = read_string end return header end # Decodes and processes header commands within provided buffer. # # @param buffer [Buffer] # @return [Array] +[[name, value], ...]+ def decode(list = []) while !end? command = read_header if pair = @context.decode(command) list << pair end end if command and command[:type] == :change_table_size raise CompressionError, "Trailing table size update!" end return list end end end end ruby-protocol-hpack-1.4.2/lib/protocol/hpack/error.rb000066400000000000000000000025211361527647700226170ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. module Protocol module HPACK class Error < StandardError end class CompressionError < Error end class DecompressionError < Error end end end ruby-protocol-hpack-1.4.2/lib/protocol/hpack/huffman.rb000066400000000000000000000172251361527647700231210ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require_relative 'huffman/machine' require_relative 'error' module Protocol module HPACK # Implementation of huffman encoding for HPACK. class Huffman BITS_AT_ONCE = 4 EOS = 256 # Encodes provided value via huffman encoding. # Length is not encoded in this method. # # @param str [String] # @return [String] binary string def encode(str) bitstring = str.each_byte.map {|chr| ENCODE_TABLE[chr]}.join bitstring << '1' * ((8 - bitstring.size) % 8) [bitstring].pack('B*') end # Decodes provided Huffman coded string. # # @param buf [Buffer] # @return [String] binary string # @raise [CompressionError] when Huffman coded string is malformed def decode(buffer) emit = String.new.b state = 0 # start state mask = (1 << BITS_AT_ONCE) - 1 buffer.each_byte do |c| (8 / BITS_AT_ONCE - 1).downto(0) do |shift| branch = (c >> (shift * BITS_AT_ONCE)) & mask # MACHINE[state] = [final, [transitions]] # [final] unfinished bits so far are prefix of the EOS code. # Each transition is [emit, next] # [emit] character to be emitted on this transition, empty string, or EOS. # [next] next state number. value, state = MACHINE[state][branch] raise CompressionError, 'Huffman decode error (EOS found)' if value == EOS emit << value.chr if value end end # Check whether partial input is correctly filled unless state <= MAX_FINAL_STATE raise CompressionError, 'Huffman decode error (EOS invalid)' end emit.force_encoding(Encoding::BINARY) end # Huffman table as specified in https://tools.ietf.org/html/rfc7541#appendix-B CODES = [ [0x1ff8, 13], [0x7fffd8, 23], [0xfffffe2, 28], [0xfffffe3, 28], [0xfffffe4, 28], [0xfffffe5, 28], [0xfffffe6, 28], [0xfffffe7, 28], [0xfffffe8, 28], [0xffffea, 24], [0x3ffffffc, 30], [0xfffffe9, 28], [0xfffffea, 28], [0x3ffffffd, 30], [0xfffffeb, 28], [0xfffffec, 28], [0xfffffed, 28], [0xfffffee, 28], [0xfffffef, 28], [0xffffff0, 28], [0xffffff1, 28], [0xffffff2, 28], [0x3ffffffe, 30], [0xffffff3, 28], [0xffffff4, 28], [0xffffff5, 28], [0xffffff6, 28], [0xffffff7, 28], [0xffffff8, 28], [0xffffff9, 28], [0xffffffa, 28], [0xffffffb, 28], [0x14, 6], [0x3f8, 10], [0x3f9, 10], [0xffa, 12], [0x1ff9, 13], [0x15, 6], [0xf8, 8], [0x7fa, 11], [0x3fa, 10], [0x3fb, 10], [0xf9, 8], [0x7fb, 11], [0xfa, 8], [0x16, 6], [0x17, 6], [0x18, 6], [0x0, 5], [0x1, 5], [0x2, 5], [0x19, 6], [0x1a, 6], [0x1b, 6], [0x1c, 6], [0x1d, 6], [0x1e, 6], [0x1f, 6], [0x5c, 7], [0xfb, 8], [0x7ffc, 15], [0x20, 6], [0xffb, 12], [0x3fc, 10], [0x1ffa, 13], [0x21, 6], [0x5d, 7], [0x5e, 7], [0x5f, 7], [0x60, 7], [0x61, 7], [0x62, 7], [0x63, 7], [0x64, 7], [0x65, 7], [0x66, 7], [0x67, 7], [0x68, 7], [0x69, 7], [0x6a, 7], [0x6b, 7], [0x6c, 7], [0x6d, 7], [0x6e, 7], [0x6f, 7], [0x70, 7], [0x71, 7], [0x72, 7], [0xfc, 8], [0x73, 7], [0xfd, 8], [0x1ffb, 13], [0x7fff0, 19], [0x1ffc, 13], [0x3ffc, 14], [0x22, 6], [0x7ffd, 15], [0x3, 5], [0x23, 6], [0x4, 5], [0x24, 6], [0x5, 5], [0x25, 6], [0x26, 6], [0x27, 6], [0x6, 5], [0x74, 7], [0x75, 7], [0x28, 6], [0x29, 6], [0x2a, 6], [0x7, 5], [0x2b, 6], [0x76, 7], [0x2c, 6], [0x8, 5], [0x9, 5], [0x2d, 6], [0x77, 7], [0x78, 7], [0x79, 7], [0x7a, 7], [0x7b, 7], [0x7ffe, 15], [0x7fc, 11], [0x3ffd, 14], [0x1ffd, 13], [0xffffffc, 28], [0xfffe6, 20], [0x3fffd2, 22], [0xfffe7, 20], [0xfffe8, 20], [0x3fffd3, 22], [0x3fffd4, 22], [0x3fffd5, 22], [0x7fffd9, 23], [0x3fffd6, 22], [0x7fffda, 23], [0x7fffdb, 23], [0x7fffdc, 23], [0x7fffdd, 23], [0x7fffde, 23], [0xffffeb, 24], [0x7fffdf, 23], [0xffffec, 24], [0xffffed, 24], [0x3fffd7, 22], [0x7fffe0, 23], [0xffffee, 24], [0x7fffe1, 23], [0x7fffe2, 23], [0x7fffe3, 23], [0x7fffe4, 23], [0x1fffdc, 21], [0x3fffd8, 22], [0x7fffe5, 23], [0x3fffd9, 22], [0x7fffe6, 23], [0x7fffe7, 23], [0xffffef, 24], [0x3fffda, 22], [0x1fffdd, 21], [0xfffe9, 20], [0x3fffdb, 22], [0x3fffdc, 22], [0x7fffe8, 23], [0x7fffe9, 23], [0x1fffde, 21], [0x7fffea, 23], [0x3fffdd, 22], [0x3fffde, 22], [0xfffff0, 24], [0x1fffdf, 21], [0x3fffdf, 22], [0x7fffeb, 23], [0x7fffec, 23], [0x1fffe0, 21], [0x1fffe1, 21], [0x3fffe0, 22], [0x1fffe2, 21], [0x7fffed, 23], [0x3fffe1, 22], [0x7fffee, 23], [0x7fffef, 23], [0xfffea, 20], [0x3fffe2, 22], [0x3fffe3, 22], [0x3fffe4, 22], [0x7ffff0, 23], [0x3fffe5, 22], [0x3fffe6, 22], [0x7ffff1, 23], [0x3ffffe0, 26], [0x3ffffe1, 26], [0xfffeb, 20], [0x7fff1, 19], [0x3fffe7, 22], [0x7ffff2, 23], [0x3fffe8, 22], [0x1ffffec, 25], [0x3ffffe2, 26], [0x3ffffe3, 26], [0x3ffffe4, 26], [0x7ffffde, 27], [0x7ffffdf, 27], [0x3ffffe5, 26], [0xfffff1, 24], [0x1ffffed, 25], [0x7fff2, 19], [0x1fffe3, 21], [0x3ffffe6, 26], [0x7ffffe0, 27], [0x7ffffe1, 27], [0x3ffffe7, 26], [0x7ffffe2, 27], [0xfffff2, 24], [0x1fffe4, 21], [0x1fffe5, 21], [0x3ffffe8, 26], [0x3ffffe9, 26], [0xffffffd, 28], [0x7ffffe3, 27], [0x7ffffe4, 27], [0x7ffffe5, 27], [0xfffec, 20], [0xfffff3, 24], [0xfffed, 20], [0x1fffe6, 21], [0x3fffe9, 22], [0x1fffe7, 21], [0x1fffe8, 21], [0x7ffff3, 23], [0x3fffea, 22], [0x3fffeb, 22], [0x1ffffee, 25], [0x1ffffef, 25], [0xfffff4, 24], [0xfffff5, 24], [0x3ffffea, 26], [0x7ffff4, 23], [0x3ffffeb, 26], [0x7ffffe6, 27], [0x3ffffec, 26], [0x3ffffed, 26], [0x7ffffe7, 27], [0x7ffffe8, 27], [0x7ffffe9, 27], [0x7ffffea, 27], [0x7ffffeb, 27], [0xffffffe, 28], [0x7ffffec, 27], [0x7ffffed, 27], [0x7ffffee, 27], [0x7ffffef, 27], [0x7fffff0, 27], [0x3ffffee, 26], [0x3fffffff, 30], ].each(&:freeze).freeze ENCODE_TABLE = CODES.map {|c, l| [c].pack('N').unpack1('B*')[-l..-1]}.each(&:freeze).freeze end end end ruby-protocol-hpack-1.4.2/lib/protocol/hpack/huffman/000077500000000000000000000000001361527647700225655ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/lib/protocol/hpack/huffman/machine.rb000066400000000000000000001307271361527647700245300ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # Machine generated Huffman decoder state machine. # DO NOT EDIT THIS FILE. module Protocol module HPACK class Huffman # :nodoc: MAX_FINAL_STATE = 7 MACHINE = [ [[nil, 248], [nil, 250], [nil, 251], [nil, 252], [nil, 253], [nil, 254], [nil, 255], [nil, 8], [nil, 9], [nil, 10], [nil, 11], [nil, 12], [nil, 13], [nil, 14], [nil, 15], [nil, 1]], [[119, 26], [119, 7], [120, 26], [120, 7], [121, 26], [121, 7], [122, 26], [122, 7], [38, 0], [42, 0], [44, 0], [59, 0], [88, 0], [90, 0], [nil, 27], [nil, 28]], [[33, 26], [33, 7], [34, 26], [34, 7], [40, 26], [40, 7], [41, 26], [41, 7], [63, 26], [63, 7], [39, 0], [43, 0], [124, 0], [nil, 74], [nil, 75], [nil, 76]], [[38, 26], [38, 7], [42, 26], [42, 7], [44, 26], [44, 7], [59, 26], [59, 7], [88, 26], [88, 7], [90, 26], [90, 7], [nil, 80], [nil, 81], [nil, 82], [nil, 83]], [[nil, 34], [nil, 35], [nil, 36], [nil, 37], [nil, 38], [nil, 39], [nil, 40], [nil, 41], [nil, 42], [nil, 43], [nil, 44], [nil, 45], [nil, 46], [nil, 47], [nil, 48], [nil, 6]], [[85, 0], [86, 0], [87, 0], [89, 0], [106, 0], [107, 0], [113, 0], [118, 0], [119, 0], [120, 0], [121, 0], [122, 0], [nil, 29], [nil, 30], [nil, 31], [nil, 2]], [[88, 23], [88, 24], [88, 25], [88, 4], [90, 23], [90, 24], [90, 25], [90, 4], [33, 0], [34, 0], [40, 0], [41, 0], [63, 0], [nil, 77], [nil, 78], [nil, 79]], [[nil, 55], [nil, 56], [nil, 57], [nil, 58], [nil, 59], [nil, 60], [nil, 61], [nil, 62], [nil, 63], [nil, 64], [nil, 65], [nil, 66], [nil, 67], [nil, 68], [nil, 69], [nil, 3]], [[54, 23], [54, 24], [54, 25], [54, 4], [55, 23], [55, 24], [55, 25], [55, 4], [56, 23], [56, 24], [56, 25], [56, 4], [57, 23], [57, 24], [57, 25], [57, 4]], [[61, 23], [61, 24], [61, 25], [61, 4], [65, 23], [65, 24], [65, 25], [65, 4], [95, 23], [95, 24], [95, 25], [95, 4], [98, 23], [98, 24], [98, 25], [98, 4]], [[100, 23], [100, 24], [100, 25], [100, 4], [102, 23], [102, 24], [102, 25], [102, 4], [103, 23], [103, 24], [103, 25], [103, 4], [104, 23], [104, 24], [104, 25], [104, 4]], [[108, 23], [108, 24], [108, 25], [108, 4], [109, 23], [109, 24], [109, 25], [109, 4], [110, 23], [110, 24], [110, 25], [110, 4], [112, 23], [112, 24], [112, 25], [112, 4]], [[114, 23], [114, 24], [114, 25], [114, 4], [117, 23], [117, 24], [117, 25], [117, 4], [58, 26], [58, 7], [66, 26], [66, 7], [67, 26], [67, 7], [68, 26], [68, 7]], [[69, 26], [69, 7], [70, 26], [70, 7], [71, 26], [71, 7], [72, 26], [72, 7], [73, 26], [73, 7], [74, 26], [74, 7], [75, 26], [75, 7], [76, 26], [76, 7]], [[77, 26], [77, 7], [78, 26], [78, 7], [79, 26], [79, 7], [80, 26], [80, 7], [81, 26], [81, 7], [82, 26], [82, 7], [83, 26], [83, 7], [84, 26], [84, 7]], [[85, 26], [85, 7], [86, 26], [86, 7], [87, 26], [87, 7], [89, 26], [89, 7], [106, 26], [106, 7], [107, 26], [107, 7], [113, 26], [113, 7], [118, 26], [118, 7]], [[48, 23], [48, 24], [48, 25], [48, 4], [49, 23], [49, 24], [49, 25], [49, 4], [50, 23], [50, 24], [50, 25], [50, 4], [97, 23], [97, 24], [97, 25], [97, 4]], [[99, 23], [99, 24], [99, 25], [99, 4], [101, 23], [101, 24], [101, 25], [101, 4], [105, 23], [105, 24], [105, 25], [105, 4], [111, 23], [111, 24], [111, 25], [111, 4]], [[115, 23], [115, 24], [115, 25], [115, 4], [116, 23], [116, 24], [116, 25], [116, 4], [32, 26], [32, 7], [37, 26], [37, 7], [45, 26], [45, 7], [46, 26], [46, 7]], [[47, 26], [47, 7], [51, 26], [51, 7], [52, 26], [52, 7], [53, 26], [53, 7], [54, 26], [54, 7], [55, 26], [55, 7], [56, 26], [56, 7], [57, 26], [57, 7]], [[61, 26], [61, 7], [65, 26], [65, 7], [95, 26], [95, 7], [98, 26], [98, 7], [100, 26], [100, 7], [102, 26], [102, 7], [103, 26], [103, 7], [104, 26], [104, 7]], [[108, 26], [108, 7], [109, 26], [109, 7], [110, 26], [110, 7], [112, 26], [112, 7], [114, 26], [114, 7], [117, 26], [117, 7], [58, 0], [66, 0], [67, 0], [68, 0]], [[69, 0], [70, 0], [71, 0], [72, 0], [73, 0], [74, 0], [75, 0], [76, 0], [77, 0], [78, 0], [79, 0], [80, 0], [81, 0], [82, 0], [83, 0], [84, 0]], [[48, 26], [48, 7], [49, 26], [49, 7], [50, 26], [50, 7], [97, 26], [97, 7], [99, 26], [99, 7], [101, 26], [101, 7], [105, 26], [105, 7], [111, 26], [111, 7]], [[115, 26], [115, 7], [116, 26], [116, 7], [32, 0], [37, 0], [45, 0], [46, 0], [47, 0], [51, 0], [52, 0], [53, 0], [54, 0], [55, 0], [56, 0], [57, 0]], [[61, 0], [65, 0], [95, 0], [98, 0], [100, 0], [102, 0], [103, 0], [104, 0], [108, 0], [109, 0], [110, 0], [112, 0], [114, 0], [117, 0], [nil, 32], [nil, 33]], [[48, 0], [49, 0], [50, 0], [97, 0], [99, 0], [101, 0], [105, 0], [111, 0], [115, 0], [116, 0], [nil, 49], [nil, 50], [nil, 51], [nil, 52], [nil, 53], [nil, 54]], [[33, 23], [33, 24], [33, 25], [33, 4], [34, 23], [34, 24], [34, 25], [34, 4], [40, 23], [40, 24], [40, 25], [40, 4], [41, 23], [41, 24], [41, 25], [41, 4]], [[63, 23], [63, 24], [63, 25], [63, 4], [39, 26], [39, 7], [43, 26], [43, 7], [124, 26], [124, 7], [35, 0], [62, 0], [nil, 70], [nil, 71], [nil, 72], [nil, 73]], [[38, 16], [38, 17], [38, 18], [38, 19], [38, 20], [38, 21], [38, 22], [38, 5], [42, 16], [42, 17], [42, 18], [42, 19], [42, 20], [42, 21], [42, 22], [42, 5]], [[44, 16], [44, 17], [44, 18], [44, 19], [44, 20], [44, 21], [44, 22], [44, 5], [59, 16], [59, 17], [59, 18], [59, 19], [59, 20], [59, 21], [59, 22], [59, 5]], [[88, 16], [88, 17], [88, 18], [88, 19], [88, 20], [88, 21], [88, 22], [88, 5], [90, 16], [90, 17], [90, 18], [90, 19], [90, 20], [90, 21], [90, 22], [90, 5]], [[58, 16], [58, 17], [58, 18], [58, 19], [58, 20], [58, 21], [58, 22], [58, 5], [66, 16], [66, 17], [66, 18], [66, 19], [66, 20], [66, 21], [66, 22], [66, 5]], [[67, 16], [67, 17], [67, 18], [67, 19], [67, 20], [67, 21], [67, 22], [67, 5], [68, 16], [68, 17], [68, 18], [68, 19], [68, 20], [68, 21], [68, 22], [68, 5]], [[69, 16], [69, 17], [69, 18], [69, 19], [69, 20], [69, 21], [69, 22], [69, 5], [70, 16], [70, 17], [70, 18], [70, 19], [70, 20], [70, 21], [70, 22], [70, 5]], [[71, 16], [71, 17], [71, 18], [71, 19], [71, 20], [71, 21], [71, 22], [71, 5], [72, 16], [72, 17], [72, 18], [72, 19], [72, 20], [72, 21], [72, 22], [72, 5]], [[73, 16], [73, 17], [73, 18], [73, 19], [73, 20], [73, 21], [73, 22], [73, 5], [74, 16], [74, 17], [74, 18], [74, 19], [74, 20], [74, 21], [74, 22], [74, 5]], [[75, 16], [75, 17], [75, 18], [75, 19], [75, 20], [75, 21], [75, 22], [75, 5], [76, 16], [76, 17], [76, 18], [76, 19], [76, 20], [76, 21], [76, 22], [76, 5]], [[77, 16], [77, 17], [77, 18], [77, 19], [77, 20], [77, 21], [77, 22], [77, 5], [78, 16], [78, 17], [78, 18], [78, 19], [78, 20], [78, 21], [78, 22], [78, 5]], [[79, 16], [79, 17], [79, 18], [79, 19], [79, 20], [79, 21], [79, 22], [79, 5], [80, 16], [80, 17], [80, 18], [80, 19], [80, 20], [80, 21], [80, 22], [80, 5]], [[81, 16], [81, 17], [81, 18], [81, 19], [81, 20], [81, 21], [81, 22], [81, 5], [82, 16], [82, 17], [82, 18], [82, 19], [82, 20], [82, 21], [82, 22], [82, 5]], [[83, 16], [83, 17], [83, 18], [83, 19], [83, 20], [83, 21], [83, 22], [83, 5], [84, 16], [84, 17], [84, 18], [84, 19], [84, 20], [84, 21], [84, 22], [84, 5]], [[85, 16], [85, 17], [85, 18], [85, 19], [85, 20], [85, 21], [85, 22], [85, 5], [86, 16], [86, 17], [86, 18], [86, 19], [86, 20], [86, 21], [86, 22], [86, 5]], [[87, 16], [87, 17], [87, 18], [87, 19], [87, 20], [87, 21], [87, 22], [87, 5], [89, 16], [89, 17], [89, 18], [89, 19], [89, 20], [89, 21], [89, 22], [89, 5]], [[106, 16], [106, 17], [106, 18], [106, 19], [106, 20], [106, 21], [106, 22], [106, 5], [107, 16], [107, 17], [107, 18], [107, 19], [107, 20], [107, 21], [107, 22], [107, 5]], [[113, 16], [113, 17], [113, 18], [113, 19], [113, 20], [113, 21], [113, 22], [113, 5], [118, 16], [118, 17], [118, 18], [118, 19], [118, 20], [118, 21], [118, 22], [118, 5]], [[119, 16], [119, 17], [119, 18], [119, 19], [119, 20], [119, 21], [119, 22], [119, 5], [120, 16], [120, 17], [120, 18], [120, 19], [120, 20], [120, 21], [120, 22], [120, 5]], [[121, 16], [121, 17], [121, 18], [121, 19], [121, 20], [121, 21], [121, 22], [121, 5], [122, 16], [122, 17], [122, 18], [122, 19], [122, 20], [122, 21], [122, 22], [122, 5]], [[38, 23], [38, 24], [38, 25], [38, 4], [42, 23], [42, 24], [42, 25], [42, 4], [44, 23], [44, 24], [44, 25], [44, 4], [59, 23], [59, 24], [59, 25], [59, 4]], [[32, 16], [32, 17], [32, 18], [32, 19], [32, 20], [32, 21], [32, 22], [32, 5], [37, 16], [37, 17], [37, 18], [37, 19], [37, 20], [37, 21], [37, 22], [37, 5]], [[45, 16], [45, 17], [45, 18], [45, 19], [45, 20], [45, 21], [45, 22], [45, 5], [46, 16], [46, 17], [46, 18], [46, 19], [46, 20], [46, 21], [46, 22], [46, 5]], [[47, 16], [47, 17], [47, 18], [47, 19], [47, 20], [47, 21], [47, 22], [47, 5], [51, 16], [51, 17], [51, 18], [51, 19], [51, 20], [51, 21], [51, 22], [51, 5]], [[52, 16], [52, 17], [52, 18], [52, 19], [52, 20], [52, 21], [52, 22], [52, 5], [53, 16], [53, 17], [53, 18], [53, 19], [53, 20], [53, 21], [53, 22], [53, 5]], [[54, 16], [54, 17], [54, 18], [54, 19], [54, 20], [54, 21], [54, 22], [54, 5], [55, 16], [55, 17], [55, 18], [55, 19], [55, 20], [55, 21], [55, 22], [55, 5]], [[56, 16], [56, 17], [56, 18], [56, 19], [56, 20], [56, 21], [56, 22], [56, 5], [57, 16], [57, 17], [57, 18], [57, 19], [57, 20], [57, 21], [57, 22], [57, 5]], [[61, 16], [61, 17], [61, 18], [61, 19], [61, 20], [61, 21], [61, 22], [61, 5], [65, 16], [65, 17], [65, 18], [65, 19], [65, 20], [65, 21], [65, 22], [65, 5]], [[95, 16], [95, 17], [95, 18], [95, 19], [95, 20], [95, 21], [95, 22], [95, 5], [98, 16], [98, 17], [98, 18], [98, 19], [98, 20], [98, 21], [98, 22], [98, 5]], [[100, 16], [100, 17], [100, 18], [100, 19], [100, 20], [100, 21], [100, 22], [100, 5], [102, 16], [102, 17], [102, 18], [102, 19], [102, 20], [102, 21], [102, 22], [102, 5]], [[103, 16], [103, 17], [103, 18], [103, 19], [103, 20], [103, 21], [103, 22], [103, 5], [104, 16], [104, 17], [104, 18], [104, 19], [104, 20], [104, 21], [104, 22], [104, 5]], [[108, 16], [108, 17], [108, 18], [108, 19], [108, 20], [108, 21], [108, 22], [108, 5], [109, 16], [109, 17], [109, 18], [109, 19], [109, 20], [109, 21], [109, 22], [109, 5]], [[110, 16], [110, 17], [110, 18], [110, 19], [110, 20], [110, 21], [110, 22], [110, 5], [112, 16], [112, 17], [112, 18], [112, 19], [112, 20], [112, 21], [112, 22], [112, 5]], [[114, 16], [114, 17], [114, 18], [114, 19], [114, 20], [114, 21], [114, 22], [114, 5], [117, 16], [117, 17], [117, 18], [117, 19], [117, 20], [117, 21], [117, 22], [117, 5]], [[58, 23], [58, 24], [58, 25], [58, 4], [66, 23], [66, 24], [66, 25], [66, 4], [67, 23], [67, 24], [67, 25], [67, 4], [68, 23], [68, 24], [68, 25], [68, 4]], [[69, 23], [69, 24], [69, 25], [69, 4], [70, 23], [70, 24], [70, 25], [70, 4], [71, 23], [71, 24], [71, 25], [71, 4], [72, 23], [72, 24], [72, 25], [72, 4]], [[73, 23], [73, 24], [73, 25], [73, 4], [74, 23], [74, 24], [74, 25], [74, 4], [75, 23], [75, 24], [75, 25], [75, 4], [76, 23], [76, 24], [76, 25], [76, 4]], [[77, 23], [77, 24], [77, 25], [77, 4], [78, 23], [78, 24], [78, 25], [78, 4], [79, 23], [79, 24], [79, 25], [79, 4], [80, 23], [80, 24], [80, 25], [80, 4]], [[81, 23], [81, 24], [81, 25], [81, 4], [82, 23], [82, 24], [82, 25], [82, 4], [83, 23], [83, 24], [83, 25], [83, 4], [84, 23], [84, 24], [84, 25], [84, 4]], [[85, 23], [85, 24], [85, 25], [85, 4], [86, 23], [86, 24], [86, 25], [86, 4], [87, 23], [87, 24], [87, 25], [87, 4], [89, 23], [89, 24], [89, 25], [89, 4]], [[106, 23], [106, 24], [106, 25], [106, 4], [107, 23], [107, 24], [107, 25], [107, 4], [113, 23], [113, 24], [113, 25], [113, 4], [118, 23], [118, 24], [118, 25], [118, 4]], [[119, 23], [119, 24], [119, 25], [119, 4], [120, 23], [120, 24], [120, 25], [120, 4], [121, 23], [121, 24], [121, 25], [121, 4], [122, 23], [122, 24], [122, 25], [122, 4]], [[0, 16], [0, 17], [0, 18], [0, 19], [0, 20], [0, 21], [0, 22], [0, 5], [36, 16], [36, 17], [36, 18], [36, 19], [36, 20], [36, 21], [36, 22], [36, 5]], [[64, 16], [64, 17], [64, 18], [64, 19], [64, 20], [64, 21], [64, 22], [64, 5], [91, 16], [91, 17], [91, 18], [91, 19], [91, 20], [91, 21], [91, 22], [91, 5]], [[93, 16], [93, 17], [93, 18], [93, 19], [93, 20], [93, 21], [93, 22], [93, 5], [126, 16], [126, 17], [126, 18], [126, 19], [126, 20], [126, 21], [126, 22], [126, 5]], [[94, 23], [94, 24], [94, 25], [94, 4], [125, 23], [125, 24], [125, 25], [125, 4], [60, 26], [60, 7], [96, 26], [96, 7], [123, 26], [123, 7], [nil, 84], [nil, 85]], [[35, 16], [35, 17], [35, 18], [35, 19], [35, 20], [35, 21], [35, 22], [35, 5], [62, 16], [62, 17], [62, 18], [62, 19], [62, 20], [62, 21], [62, 22], [62, 5]], [[0, 23], [0, 24], [0, 25], [0, 4], [36, 23], [36, 24], [36, 25], [36, 4], [64, 23], [64, 24], [64, 25], [64, 4], [91, 23], [91, 24], [91, 25], [91, 4]], [[93, 23], [93, 24], [93, 25], [93, 4], [126, 23], [126, 24], [126, 25], [126, 4], [94, 26], [94, 7], [125, 26], [125, 7], [60, 0], [96, 0], [123, 0], [nil, 86]], [[39, 16], [39, 17], [39, 18], [39, 19], [39, 20], [39, 21], [39, 22], [39, 5], [43, 16], [43, 17], [43, 18], [43, 19], [43, 20], [43, 21], [43, 22], [43, 5]], [[124, 16], [124, 17], [124, 18], [124, 19], [124, 20], [124, 21], [124, 22], [124, 5], [35, 23], [35, 24], [35, 25], [35, 4], [62, 23], [62, 24], [62, 25], [62, 4]], [[0, 26], [0, 7], [36, 26], [36, 7], [64, 26], [64, 7], [91, 26], [91, 7], [93, 26], [93, 7], [126, 26], [126, 7], [94, 0], [125, 0], [nil, 87], [nil, 88]], [[33, 16], [33, 17], [33, 18], [33, 19], [33, 20], [33, 21], [33, 22], [33, 5], [34, 16], [34, 17], [34, 18], [34, 19], [34, 20], [34, 21], [34, 22], [34, 5]], [[40, 16], [40, 17], [40, 18], [40, 19], [40, 20], [40, 21], [40, 22], [40, 5], [41, 16], [41, 17], [41, 18], [41, 19], [41, 20], [41, 21], [41, 22], [41, 5]], [[63, 16], [63, 17], [63, 18], [63, 19], [63, 20], [63, 21], [63, 22], [63, 5], [39, 23], [39, 24], [39, 25], [39, 4], [43, 23], [43, 24], [43, 25], [43, 4]], [[124, 23], [124, 24], [124, 25], [124, 4], [35, 26], [35, 7], [62, 26], [62, 7], [0, 0], [36, 0], [64, 0], [91, 0], [93, 0], [126, 0], [nil, 89], [nil, 90]], [[92, 26], [92, 7], [195, 26], [195, 7], [208, 26], [208, 7], [128, 0], [130, 0], [131, 0], [162, 0], [184, 0], [194, 0], [224, 0], [226, 0], [nil, 91], [nil, 92]], [[nil, 93], [nil, 94], [nil, 95], [nil, 96], [nil, 97], [nil, 98], [nil, 99], [nil, 100], [nil, 101], [nil, 102], [nil, 103], [nil, 104], [nil, 105], [nil, 106], [nil, 107], [nil, 108]], [[92, 0], [195, 0], [208, 0], [nil, 109], [nil, 110], [nil, 111], [nil, 112], [nil, 113], [nil, 114], [nil, 115], [nil, 116], [nil, 117], [nil, 118], [nil, 119], [nil, 120], [nil, 121]], [[60, 16], [60, 17], [60, 18], [60, 19], [60, 20], [60, 21], [60, 22], [60, 5], [96, 16], [96, 17], [96, 18], [96, 19], [96, 20], [96, 21], [96, 22], [96, 5]], [[123, 16], [123, 17], [123, 18], [123, 19], [123, 20], [123, 21], [123, 22], [123, 5], [nil, 122], [nil, 123], [nil, 124], [nil, 125], [nil, 126], [nil, 127], [nil, 128], [nil, 129]], [[94, 16], [94, 17], [94, 18], [94, 19], [94, 20], [94, 21], [94, 22], [94, 5], [125, 16], [125, 17], [125, 18], [125, 19], [125, 20], [125, 21], [125, 22], [125, 5]], [[60, 23], [60, 24], [60, 25], [60, 4], [96, 23], [96, 24], [96, 25], [96, 4], [123, 23], [123, 24], [123, 25], [123, 4], [nil, 130], [nil, 131], [nil, 132], [nil, 133]], [[153, 16], [153, 17], [153, 18], [153, 19], [153, 20], [153, 21], [153, 22], [153, 5], [161, 16], [161, 17], [161, 18], [161, 19], [161, 20], [161, 21], [161, 22], [161, 5]], [[167, 16], [167, 17], [167, 18], [167, 19], [167, 20], [167, 21], [167, 22], [167, 5], [172, 16], [172, 17], [172, 18], [172, 19], [172, 20], [172, 21], [172, 22], [172, 5]], [[176, 16], [176, 17], [176, 18], [176, 19], [176, 20], [176, 21], [176, 22], [176, 5], [177, 16], [177, 17], [177, 18], [177, 19], [177, 20], [177, 21], [177, 22], [177, 5]], [[179, 16], [179, 17], [179, 18], [179, 19], [179, 20], [179, 21], [179, 22], [179, 5], [209, 16], [209, 17], [209, 18], [209, 19], [209, 20], [209, 21], [209, 22], [209, 5]], [[216, 16], [216, 17], [216, 18], [216, 19], [216, 20], [216, 21], [216, 22], [216, 5], [217, 16], [217, 17], [217, 18], [217, 19], [217, 20], [217, 21], [217, 22], [217, 5]], [[227, 16], [227, 17], [227, 18], [227, 19], [227, 20], [227, 21], [227, 22], [227, 5], [229, 16], [229, 17], [229, 18], [229, 19], [229, 20], [229, 21], [229, 22], [229, 5]], [[230, 16], [230, 17], [230, 18], [230, 19], [230, 20], [230, 21], [230, 22], [230, 5], [129, 23], [129, 24], [129, 25], [129, 4], [132, 23], [132, 24], [132, 25], [132, 4]], [[133, 23], [133, 24], [133, 25], [133, 4], [134, 23], [134, 24], [134, 25], [134, 4], [136, 23], [136, 24], [136, 25], [136, 4], [146, 23], [146, 24], [146, 25], [146, 4]], [[154, 23], [154, 24], [154, 25], [154, 4], [156, 23], [156, 24], [156, 25], [156, 4], [160, 23], [160, 24], [160, 25], [160, 4], [163, 23], [163, 24], [163, 25], [163, 4]], [[164, 23], [164, 24], [164, 25], [164, 4], [169, 23], [169, 24], [169, 25], [169, 4], [170, 23], [170, 24], [170, 25], [170, 4], [173, 23], [173, 24], [173, 25], [173, 4]], [[178, 23], [178, 24], [178, 25], [178, 4], [181, 23], [181, 24], [181, 25], [181, 4], [185, 23], [185, 24], [185, 25], [185, 4], [186, 23], [186, 24], [186, 25], [186, 4]], [[187, 23], [187, 24], [187, 25], [187, 4], [189, 23], [189, 24], [189, 25], [189, 4], [190, 23], [190, 24], [190, 25], [190, 4], [196, 23], [196, 24], [196, 25], [196, 4]], [[198, 23], [198, 24], [198, 25], [198, 4], [228, 23], [228, 24], [228, 25], [228, 4], [232, 23], [232, 24], [232, 25], [232, 4], [233, 23], [233, 24], [233, 25], [233, 4]], [[1, 26], [1, 7], [135, 26], [135, 7], [137, 26], [137, 7], [138, 26], [138, 7], [139, 26], [139, 7], [140, 26], [140, 7], [141, 26], [141, 7], [143, 26], [143, 7]], [[147, 26], [147, 7], [149, 26], [149, 7], [150, 26], [150, 7], [151, 26], [151, 7], [152, 26], [152, 7], [155, 26], [155, 7], [157, 26], [157, 7], [158, 26], [158, 7]], [[165, 26], [165, 7], [166, 26], [166, 7], [168, 26], [168, 7], [174, 26], [174, 7], [175, 26], [175, 7], [180, 26], [180, 7], [182, 26], [182, 7], [183, 26], [183, 7]], [[188, 26], [188, 7], [191, 26], [191, 7], [197, 26], [197, 7], [231, 26], [231, 7], [239, 26], [239, 7], [9, 0], [142, 0], [144, 0], [145, 0], [148, 0], [159, 0]], [[171, 0], [206, 0], [215, 0], [225, 0], [236, 0], [237, 0], [nil, 134], [nil, 135], [nil, 136], [nil, 137], [nil, 138], [nil, 139], [nil, 140], [nil, 141], [nil, 142], [nil, 143]], [[128, 16], [128, 17], [128, 18], [128, 19], [128, 20], [128, 21], [128, 22], [128, 5], [130, 16], [130, 17], [130, 18], [130, 19], [130, 20], [130, 21], [130, 22], [130, 5]], [[131, 16], [131, 17], [131, 18], [131, 19], [131, 20], [131, 21], [131, 22], [131, 5], [162, 16], [162, 17], [162, 18], [162, 19], [162, 20], [162, 21], [162, 22], [162, 5]], [[184, 16], [184, 17], [184, 18], [184, 19], [184, 20], [184, 21], [184, 22], [184, 5], [194, 16], [194, 17], [194, 18], [194, 19], [194, 20], [194, 21], [194, 22], [194, 5]], [[224, 16], [224, 17], [224, 18], [224, 19], [224, 20], [224, 21], [224, 22], [224, 5], [226, 16], [226, 17], [226, 18], [226, 19], [226, 20], [226, 21], [226, 22], [226, 5]], [[153, 23], [153, 24], [153, 25], [153, 4], [161, 23], [161, 24], [161, 25], [161, 4], [167, 23], [167, 24], [167, 25], [167, 4], [172, 23], [172, 24], [172, 25], [172, 4]], [[176, 23], [176, 24], [176, 25], [176, 4], [177, 23], [177, 24], [177, 25], [177, 4], [179, 23], [179, 24], [179, 25], [179, 4], [209, 23], [209, 24], [209, 25], [209, 4]], [[216, 23], [216, 24], [216, 25], [216, 4], [217, 23], [217, 24], [217, 25], [217, 4], [227, 23], [227, 24], [227, 25], [227, 4], [229, 23], [229, 24], [229, 25], [229, 4]], [[230, 23], [230, 24], [230, 25], [230, 4], [129, 26], [129, 7], [132, 26], [132, 7], [133, 26], [133, 7], [134, 26], [134, 7], [136, 26], [136, 7], [146, 26], [146, 7]], [[154, 26], [154, 7], [156, 26], [156, 7], [160, 26], [160, 7], [163, 26], [163, 7], [164, 26], [164, 7], [169, 26], [169, 7], [170, 26], [170, 7], [173, 26], [173, 7]], [[178, 26], [178, 7], [181, 26], [181, 7], [185, 26], [185, 7], [186, 26], [186, 7], [187, 26], [187, 7], [189, 26], [189, 7], [190, 26], [190, 7], [196, 26], [196, 7]], [[198, 26], [198, 7], [228, 26], [228, 7], [232, 26], [232, 7], [233, 26], [233, 7], [1, 0], [135, 0], [137, 0], [138, 0], [139, 0], [140, 0], [141, 0], [143, 0]], [[147, 0], [149, 0], [150, 0], [151, 0], [152, 0], [155, 0], [157, 0], [158, 0], [165, 0], [166, 0], [168, 0], [174, 0], [175, 0], [180, 0], [182, 0], [183, 0]], [[188, 0], [191, 0], [197, 0], [231, 0], [239, 0], [nil, 144], [nil, 145], [nil, 146], [nil, 147], [nil, 148], [nil, 149], [nil, 150], [nil, 151], [nil, 152], [nil, 153], [nil, 154]], [[92, 16], [92, 17], [92, 18], [92, 19], [92, 20], [92, 21], [92, 22], [92, 5], [195, 16], [195, 17], [195, 18], [195, 19], [195, 20], [195, 21], [195, 22], [195, 5]], [[208, 16], [208, 17], [208, 18], [208, 19], [208, 20], [208, 21], [208, 22], [208, 5], [128, 23], [128, 24], [128, 25], [128, 4], [130, 23], [130, 24], [130, 25], [130, 4]], [[131, 23], [131, 24], [131, 25], [131, 4], [162, 23], [162, 24], [162, 25], [162, 4], [184, 23], [184, 24], [184, 25], [184, 4], [194, 23], [194, 24], [194, 25], [194, 4]], [[224, 23], [224, 24], [224, 25], [224, 4], [226, 23], [226, 24], [226, 25], [226, 4], [153, 26], [153, 7], [161, 26], [161, 7], [167, 26], [167, 7], [172, 26], [172, 7]], [[176, 26], [176, 7], [177, 26], [177, 7], [179, 26], [179, 7], [209, 26], [209, 7], [216, 26], [216, 7], [217, 26], [217, 7], [227, 26], [227, 7], [229, 26], [229, 7]], [[230, 26], [230, 7], [129, 0], [132, 0], [133, 0], [134, 0], [136, 0], [146, 0], [154, 0], [156, 0], [160, 0], [163, 0], [164, 0], [169, 0], [170, 0], [173, 0]], [[178, 0], [181, 0], [185, 0], [186, 0], [187, 0], [189, 0], [190, 0], [196, 0], [198, 0], [228, 0], [232, 0], [233, 0], [nil, 155], [nil, 156], [nil, 157], [nil, 158]], [[nil, 159], [nil, 160], [nil, 161], [nil, 162], [nil, 163], [nil, 164], [nil, 165], [nil, 166], [nil, 167], [nil, 168], [nil, 169], [nil, 170], [nil, 171], [nil, 172], [nil, 173], [nil, 174]], [[92, 23], [92, 24], [92, 25], [92, 4], [195, 23], [195, 24], [195, 25], [195, 4], [208, 23], [208, 24], [208, 25], [208, 4], [128, 26], [128, 7], [130, 26], [130, 7]], [[131, 26], [131, 7], [162, 26], [162, 7], [184, 26], [184, 7], [194, 26], [194, 7], [224, 26], [224, 7], [226, 26], [226, 7], [153, 0], [161, 0], [167, 0], [172, 0]], [[176, 0], [177, 0], [179, 0], [209, 0], [216, 0], [217, 0], [227, 0], [229, 0], [230, 0], [nil, 175], [nil, 176], [nil, 177], [nil, 178], [nil, 179], [nil, 180], [nil, 181]], [[nil, 182], [nil, 183], [nil, 184], [nil, 185], [nil, 186], [nil, 187], [nil, 188], [nil, 189], [nil, 190], [nil, 191], [nil, 192], [nil, 193], [nil, 194], [nil, 195], [nil, 196], [nil, 197]], [[199, 16], [199, 17], [199, 18], [199, 19], [199, 20], [199, 21], [199, 22], [199, 5], [207, 16], [207, 17], [207, 18], [207, 19], [207, 20], [207, 21], [207, 22], [207, 5]], [[234, 16], [234, 17], [234, 18], [234, 19], [234, 20], [234, 21], [234, 22], [234, 5], [235, 16], [235, 17], [235, 18], [235, 19], [235, 20], [235, 21], [235, 22], [235, 5]], [[192, 23], [192, 24], [192, 25], [192, 4], [193, 23], [193, 24], [193, 25], [193, 4], [200, 23], [200, 24], [200, 25], [200, 4], [201, 23], [201, 24], [201, 25], [201, 4]], [[202, 23], [202, 24], [202, 25], [202, 4], [205, 23], [205, 24], [205, 25], [205, 4], [210, 23], [210, 24], [210, 25], [210, 4], [213, 23], [213, 24], [213, 25], [213, 4]], [[218, 23], [218, 24], [218, 25], [218, 4], [219, 23], [219, 24], [219, 25], [219, 4], [238, 23], [238, 24], [238, 25], [238, 4], [240, 23], [240, 24], [240, 25], [240, 4]], [[242, 23], [242, 24], [242, 25], [242, 4], [243, 23], [243, 24], [243, 25], [243, 4], [255, 23], [255, 24], [255, 25], [255, 4], [203, 26], [203, 7], [204, 26], [204, 7]], [[211, 26], [211, 7], [212, 26], [212, 7], [214, 26], [214, 7], [221, 26], [221, 7], [222, 26], [222, 7], [223, 26], [223, 7], [241, 26], [241, 7], [244, 26], [244, 7]], [[245, 26], [245, 7], [246, 26], [246, 7], [247, 26], [247, 7], [248, 26], [248, 7], [250, 26], [250, 7], [251, 26], [251, 7], [252, 26], [252, 7], [253, 26], [253, 7]], [[254, 26], [254, 7], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [11, 0], [12, 0], [14, 0], [15, 0], [16, 0], [17, 0], [18, 0]], [[19, 0], [20, 0], [21, 0], [23, 0], [24, 0], [25, 0], [26, 0], [27, 0], [28, 0], [29, 0], [30, 0], [31, 0], [127, 0], [220, 0], [249, 0], [nil, 198]], [[9, 16], [9, 17], [9, 18], [9, 19], [9, 20], [9, 21], [9, 22], [9, 5], [142, 16], [142, 17], [142, 18], [142, 19], [142, 20], [142, 21], [142, 22], [142, 5]], [[144, 16], [144, 17], [144, 18], [144, 19], [144, 20], [144, 21], [144, 22], [144, 5], [145, 16], [145, 17], [145, 18], [145, 19], [145, 20], [145, 21], [145, 22], [145, 5]], [[148, 16], [148, 17], [148, 18], [148, 19], [148, 20], [148, 21], [148, 22], [148, 5], [159, 16], [159, 17], [159, 18], [159, 19], [159, 20], [159, 21], [159, 22], [159, 5]], [[171, 16], [171, 17], [171, 18], [171, 19], [171, 20], [171, 21], [171, 22], [171, 5], [206, 16], [206, 17], [206, 18], [206, 19], [206, 20], [206, 21], [206, 22], [206, 5]], [[215, 16], [215, 17], [215, 18], [215, 19], [215, 20], [215, 21], [215, 22], [215, 5], [225, 16], [225, 17], [225, 18], [225, 19], [225, 20], [225, 21], [225, 22], [225, 5]], [[236, 16], [236, 17], [236, 18], [236, 19], [236, 20], [236, 21], [236, 22], [236, 5], [237, 16], [237, 17], [237, 18], [237, 19], [237, 20], [237, 21], [237, 22], [237, 5]], [[199, 23], [199, 24], [199, 25], [199, 4], [207, 23], [207, 24], [207, 25], [207, 4], [234, 23], [234, 24], [234, 25], [234, 4], [235, 23], [235, 24], [235, 25], [235, 4]], [[192, 26], [192, 7], [193, 26], [193, 7], [200, 26], [200, 7], [201, 26], [201, 7], [202, 26], [202, 7], [205, 26], [205, 7], [210, 26], [210, 7], [213, 26], [213, 7]], [[218, 26], [218, 7], [219, 26], [219, 7], [238, 26], [238, 7], [240, 26], [240, 7], [242, 26], [242, 7], [243, 26], [243, 7], [255, 26], [255, 7], [203, 0], [204, 0]], [[211, 0], [212, 0], [214, 0], [221, 0], [222, 0], [223, 0], [241, 0], [244, 0], [245, 0], [246, 0], [247, 0], [248, 0], [250, 0], [251, 0], [252, 0], [253, 0]], [[254, 0], [nil, 199], [nil, 200], [nil, 201], [nil, 202], [nil, 203], [nil, 204], [nil, 205], [nil, 206], [nil, 207], [nil, 208], [nil, 209], [nil, 210], [nil, 211], [nil, 212], [nil, 213]], [[1, 16], [1, 17], [1, 18], [1, 19], [1, 20], [1, 21], [1, 22], [1, 5], [135, 16], [135, 17], [135, 18], [135, 19], [135, 20], [135, 21], [135, 22], [135, 5]], [[137, 16], [137, 17], [137, 18], [137, 19], [137, 20], [137, 21], [137, 22], [137, 5], [138, 16], [138, 17], [138, 18], [138, 19], [138, 20], [138, 21], [138, 22], [138, 5]], [[139, 16], [139, 17], [139, 18], [139, 19], [139, 20], [139, 21], [139, 22], [139, 5], [140, 16], [140, 17], [140, 18], [140, 19], [140, 20], [140, 21], [140, 22], [140, 5]], [[141, 16], [141, 17], [141, 18], [141, 19], [141, 20], [141, 21], [141, 22], [141, 5], [143, 16], [143, 17], [143, 18], [143, 19], [143, 20], [143, 21], [143, 22], [143, 5]], [[147, 16], [147, 17], [147, 18], [147, 19], [147, 20], [147, 21], [147, 22], [147, 5], [149, 16], [149, 17], [149, 18], [149, 19], [149, 20], [149, 21], [149, 22], [149, 5]], [[150, 16], [150, 17], [150, 18], [150, 19], [150, 20], [150, 21], [150, 22], [150, 5], [151, 16], [151, 17], [151, 18], [151, 19], [151, 20], [151, 21], [151, 22], [151, 5]], [[152, 16], [152, 17], [152, 18], [152, 19], [152, 20], [152, 21], [152, 22], [152, 5], [155, 16], [155, 17], [155, 18], [155, 19], [155, 20], [155, 21], [155, 22], [155, 5]], [[157, 16], [157, 17], [157, 18], [157, 19], [157, 20], [157, 21], [157, 22], [157, 5], [158, 16], [158, 17], [158, 18], [158, 19], [158, 20], [158, 21], [158, 22], [158, 5]], [[165, 16], [165, 17], [165, 18], [165, 19], [165, 20], [165, 21], [165, 22], [165, 5], [166, 16], [166, 17], [166, 18], [166, 19], [166, 20], [166, 21], [166, 22], [166, 5]], [[168, 16], [168, 17], [168, 18], [168, 19], [168, 20], [168, 21], [168, 22], [168, 5], [174, 16], [174, 17], [174, 18], [174, 19], [174, 20], [174, 21], [174, 22], [174, 5]], [[175, 16], [175, 17], [175, 18], [175, 19], [175, 20], [175, 21], [175, 22], [175, 5], [180, 16], [180, 17], [180, 18], [180, 19], [180, 20], [180, 21], [180, 22], [180, 5]], [[182, 16], [182, 17], [182, 18], [182, 19], [182, 20], [182, 21], [182, 22], [182, 5], [183, 16], [183, 17], [183, 18], [183, 19], [183, 20], [183, 21], [183, 22], [183, 5]], [[188, 16], [188, 17], [188, 18], [188, 19], [188, 20], [188, 21], [188, 22], [188, 5], [191, 16], [191, 17], [191, 18], [191, 19], [191, 20], [191, 21], [191, 22], [191, 5]], [[197, 16], [197, 17], [197, 18], [197, 19], [197, 20], [197, 21], [197, 22], [197, 5], [231, 16], [231, 17], [231, 18], [231, 19], [231, 20], [231, 21], [231, 22], [231, 5]], [[239, 16], [239, 17], [239, 18], [239, 19], [239, 20], [239, 21], [239, 22], [239, 5], [9, 23], [9, 24], [9, 25], [9, 4], [142, 23], [142, 24], [142, 25], [142, 4]], [[144, 23], [144, 24], [144, 25], [144, 4], [145, 23], [145, 24], [145, 25], [145, 4], [148, 23], [148, 24], [148, 25], [148, 4], [159, 23], [159, 24], [159, 25], [159, 4]], [[171, 23], [171, 24], [171, 25], [171, 4], [206, 23], [206, 24], [206, 25], [206, 4], [215, 23], [215, 24], [215, 25], [215, 4], [225, 23], [225, 24], [225, 25], [225, 4]], [[236, 23], [236, 24], [236, 25], [236, 4], [237, 23], [237, 24], [237, 25], [237, 4], [199, 26], [199, 7], [207, 26], [207, 7], [234, 26], [234, 7], [235, 26], [235, 7]], [[192, 0], [193, 0], [200, 0], [201, 0], [202, 0], [205, 0], [210, 0], [213, 0], [218, 0], [219, 0], [238, 0], [240, 0], [242, 0], [243, 0], [255, 0], [nil, 214]], [[nil, 215], [nil, 216], [nil, 217], [nil, 218], [nil, 219], [nil, 220], [nil, 221], [nil, 222], [nil, 223], [nil, 224], [nil, 225], [nil, 226], [nil, 227], [nil, 228], [nil, 229], [nil, 230]], [[129, 16], [129, 17], [129, 18], [129, 19], [129, 20], [129, 21], [129, 22], [129, 5], [132, 16], [132, 17], [132, 18], [132, 19], [132, 20], [132, 21], [132, 22], [132, 5]], [[133, 16], [133, 17], [133, 18], [133, 19], [133, 20], [133, 21], [133, 22], [133, 5], [134, 16], [134, 17], [134, 18], [134, 19], [134, 20], [134, 21], [134, 22], [134, 5]], [[136, 16], [136, 17], [136, 18], [136, 19], [136, 20], [136, 21], [136, 22], [136, 5], [146, 16], [146, 17], [146, 18], [146, 19], [146, 20], [146, 21], [146, 22], [146, 5]], [[154, 16], [154, 17], [154, 18], [154, 19], [154, 20], [154, 21], [154, 22], [154, 5], [156, 16], [156, 17], [156, 18], [156, 19], [156, 20], [156, 21], [156, 22], [156, 5]], [[160, 16], [160, 17], [160, 18], [160, 19], [160, 20], [160, 21], [160, 22], [160, 5], [163, 16], [163, 17], [163, 18], [163, 19], [163, 20], [163, 21], [163, 22], [163, 5]], [[164, 16], [164, 17], [164, 18], [164, 19], [164, 20], [164, 21], [164, 22], [164, 5], [169, 16], [169, 17], [169, 18], [169, 19], [169, 20], [169, 21], [169, 22], [169, 5]], [[170, 16], [170, 17], [170, 18], [170, 19], [170, 20], [170, 21], [170, 22], [170, 5], [173, 16], [173, 17], [173, 18], [173, 19], [173, 20], [173, 21], [173, 22], [173, 5]], [[178, 16], [178, 17], [178, 18], [178, 19], [178, 20], [178, 21], [178, 22], [178, 5], [181, 16], [181, 17], [181, 18], [181, 19], [181, 20], [181, 21], [181, 22], [181, 5]], [[185, 16], [185, 17], [185, 18], [185, 19], [185, 20], [185, 21], [185, 22], [185, 5], [186, 16], [186, 17], [186, 18], [186, 19], [186, 20], [186, 21], [186, 22], [186, 5]], [[187, 16], [187, 17], [187, 18], [187, 19], [187, 20], [187, 21], [187, 22], [187, 5], [189, 16], [189, 17], [189, 18], [189, 19], [189, 20], [189, 21], [189, 22], [189, 5]], [[190, 16], [190, 17], [190, 18], [190, 19], [190, 20], [190, 21], [190, 22], [190, 5], [196, 16], [196, 17], [196, 18], [196, 19], [196, 20], [196, 21], [196, 22], [196, 5]], [[198, 16], [198, 17], [198, 18], [198, 19], [198, 20], [198, 21], [198, 22], [198, 5], [228, 16], [228, 17], [228, 18], [228, 19], [228, 20], [228, 21], [228, 22], [228, 5]], [[232, 16], [232, 17], [232, 18], [232, 19], [232, 20], [232, 21], [232, 22], [232, 5], [233, 16], [233, 17], [233, 18], [233, 19], [233, 20], [233, 21], [233, 22], [233, 5]], [[1, 23], [1, 24], [1, 25], [1, 4], [135, 23], [135, 24], [135, 25], [135, 4], [137, 23], [137, 24], [137, 25], [137, 4], [138, 23], [138, 24], [138, 25], [138, 4]], [[139, 23], [139, 24], [139, 25], [139, 4], [140, 23], [140, 24], [140, 25], [140, 4], [141, 23], [141, 24], [141, 25], [141, 4], [143, 23], [143, 24], [143, 25], [143, 4]], [[147, 23], [147, 24], [147, 25], [147, 4], [149, 23], [149, 24], [149, 25], [149, 4], [150, 23], [150, 24], [150, 25], [150, 4], [151, 23], [151, 24], [151, 25], [151, 4]], [[152, 23], [152, 24], [152, 25], [152, 4], [155, 23], [155, 24], [155, 25], [155, 4], [157, 23], [157, 24], [157, 25], [157, 4], [158, 23], [158, 24], [158, 25], [158, 4]], [[165, 23], [165, 24], [165, 25], [165, 4], [166, 23], [166, 24], [166, 25], [166, 4], [168, 23], [168, 24], [168, 25], [168, 4], [174, 23], [174, 24], [174, 25], [174, 4]], [[175, 23], [175, 24], [175, 25], [175, 4], [180, 23], [180, 24], [180, 25], [180, 4], [182, 23], [182, 24], [182, 25], [182, 4], [183, 23], [183, 24], [183, 25], [183, 4]], [[188, 23], [188, 24], [188, 25], [188, 4], [191, 23], [191, 24], [191, 25], [191, 4], [197, 23], [197, 24], [197, 25], [197, 4], [231, 23], [231, 24], [231, 25], [231, 4]], [[239, 23], [239, 24], [239, 25], [239, 4], [9, 26], [9, 7], [142, 26], [142, 7], [144, 26], [144, 7], [145, 26], [145, 7], [148, 26], [148, 7], [159, 26], [159, 7]], [[171, 26], [171, 7], [206, 26], [206, 7], [215, 26], [215, 7], [225, 26], [225, 7], [236, 26], [236, 7], [237, 26], [237, 7], [199, 0], [207, 0], [234, 0], [235, 0]], [[nil, 231], [nil, 232], [nil, 233], [nil, 234], [nil, 235], [nil, 236], [nil, 237], [nil, 238], [nil, 239], [nil, 240], [nil, 241], [nil, 242], [nil, 243], [nil, 244], [nil, 245], [nil, 246]], [[10, 23], [10, 24], [10, 25], [10, 4], [13, 23], [13, 24], [13, 25], [13, 4], [22, 23], [22, 24], [22, 25], [22, 4], [256, 23], [256, 24], [256, 25], [256, 4]], [[2, 16], [2, 17], [2, 18], [2, 19], [2, 20], [2, 21], [2, 22], [2, 5], [3, 16], [3, 17], [3, 18], [3, 19], [3, 20], [3, 21], [3, 22], [3, 5]], [[4, 16], [4, 17], [4, 18], [4, 19], [4, 20], [4, 21], [4, 22], [4, 5], [5, 16], [5, 17], [5, 18], [5, 19], [5, 20], [5, 21], [5, 22], [5, 5]], [[6, 16], [6, 17], [6, 18], [6, 19], [6, 20], [6, 21], [6, 22], [6, 5], [7, 16], [7, 17], [7, 18], [7, 19], [7, 20], [7, 21], [7, 22], [7, 5]], [[8, 16], [8, 17], [8, 18], [8, 19], [8, 20], [8, 21], [8, 22], [8, 5], [11, 16], [11, 17], [11, 18], [11, 19], [11, 20], [11, 21], [11, 22], [11, 5]], [[12, 16], [12, 17], [12, 18], [12, 19], [12, 20], [12, 21], [12, 22], [12, 5], [14, 16], [14, 17], [14, 18], [14, 19], [14, 20], [14, 21], [14, 22], [14, 5]], [[15, 16], [15, 17], [15, 18], [15, 19], [15, 20], [15, 21], [15, 22], [15, 5], [16, 16], [16, 17], [16, 18], [16, 19], [16, 20], [16, 21], [16, 22], [16, 5]], [[17, 16], [17, 17], [17, 18], [17, 19], [17, 20], [17, 21], [17, 22], [17, 5], [18, 16], [18, 17], [18, 18], [18, 19], [18, 20], [18, 21], [18, 22], [18, 5]], [[19, 16], [19, 17], [19, 18], [19, 19], [19, 20], [19, 21], [19, 22], [19, 5], [20, 16], [20, 17], [20, 18], [20, 19], [20, 20], [20, 21], [20, 22], [20, 5]], [[21, 16], [21, 17], [21, 18], [21, 19], [21, 20], [21, 21], [21, 22], [21, 5], [23, 16], [23, 17], [23, 18], [23, 19], [23, 20], [23, 21], [23, 22], [23, 5]], [[24, 16], [24, 17], [24, 18], [24, 19], [24, 20], [24, 21], [24, 22], [24, 5], [25, 16], [25, 17], [25, 18], [25, 19], [25, 20], [25, 21], [25, 22], [25, 5]], [[26, 16], [26, 17], [26, 18], [26, 19], [26, 20], [26, 21], [26, 22], [26, 5], [27, 16], [27, 17], [27, 18], [27, 19], [27, 20], [27, 21], [27, 22], [27, 5]], [[28, 16], [28, 17], [28, 18], [28, 19], [28, 20], [28, 21], [28, 22], [28, 5], [29, 16], [29, 17], [29, 18], [29, 19], [29, 20], [29, 21], [29, 22], [29, 5]], [[30, 16], [30, 17], [30, 18], [30, 19], [30, 20], [30, 21], [30, 22], [30, 5], [31, 16], [31, 17], [31, 18], [31, 19], [31, 20], [31, 21], [31, 22], [31, 5]], [[127, 16], [127, 17], [127, 18], [127, 19], [127, 20], [127, 21], [127, 22], [127, 5], [220, 16], [220, 17], [220, 18], [220, 19], [220, 20], [220, 21], [220, 22], [220, 5]], [[249, 16], [249, 17], [249, 18], [249, 19], [249, 20], [249, 21], [249, 22], [249, 5], [10, 26], [10, 7], [13, 26], [13, 7], [22, 26], [22, 7], [256, 26], [256, 7]], [[203, 16], [203, 17], [203, 18], [203, 19], [203, 20], [203, 21], [203, 22], [203, 5], [204, 16], [204, 17], [204, 18], [204, 19], [204, 20], [204, 21], [204, 22], [204, 5]], [[211, 16], [211, 17], [211, 18], [211, 19], [211, 20], [211, 21], [211, 22], [211, 5], [212, 16], [212, 17], [212, 18], [212, 19], [212, 20], [212, 21], [212, 22], [212, 5]], [[214, 16], [214, 17], [214, 18], [214, 19], [214, 20], [214, 21], [214, 22], [214, 5], [221, 16], [221, 17], [221, 18], [221, 19], [221, 20], [221, 21], [221, 22], [221, 5]], [[222, 16], [222, 17], [222, 18], [222, 19], [222, 20], [222, 21], [222, 22], [222, 5], [223, 16], [223, 17], [223, 18], [223, 19], [223, 20], [223, 21], [223, 22], [223, 5]], [[241, 16], [241, 17], [241, 18], [241, 19], [241, 20], [241, 21], [241, 22], [241, 5], [244, 16], [244, 17], [244, 18], [244, 19], [244, 20], [244, 21], [244, 22], [244, 5]], [[245, 16], [245, 17], [245, 18], [245, 19], [245, 20], [245, 21], [245, 22], [245, 5], [246, 16], [246, 17], [246, 18], [246, 19], [246, 20], [246, 21], [246, 22], [246, 5]], [[247, 16], [247, 17], [247, 18], [247, 19], [247, 20], [247, 21], [247, 22], [247, 5], [248, 16], [248, 17], [248, 18], [248, 19], [248, 20], [248, 21], [248, 22], [248, 5]], [[250, 16], [250, 17], [250, 18], [250, 19], [250, 20], [250, 21], [250, 22], [250, 5], [251, 16], [251, 17], [251, 18], [251, 19], [251, 20], [251, 21], [251, 22], [251, 5]], [[252, 16], [252, 17], [252, 18], [252, 19], [252, 20], [252, 21], [252, 22], [252, 5], [253, 16], [253, 17], [253, 18], [253, 19], [253, 20], [253, 21], [253, 22], [253, 5]], [[254, 16], [254, 17], [254, 18], [254, 19], [254, 20], [254, 21], [254, 22], [254, 5], [2, 23], [2, 24], [2, 25], [2, 4], [3, 23], [3, 24], [3, 25], [3, 4]], [[4, 23], [4, 24], [4, 25], [4, 4], [5, 23], [5, 24], [5, 25], [5, 4], [6, 23], [6, 24], [6, 25], [6, 4], [7, 23], [7, 24], [7, 25], [7, 4]], [[8, 23], [8, 24], [8, 25], [8, 4], [11, 23], [11, 24], [11, 25], [11, 4], [12, 23], [12, 24], [12, 25], [12, 4], [14, 23], [14, 24], [14, 25], [14, 4]], [[15, 23], [15, 24], [15, 25], [15, 4], [16, 23], [16, 24], [16, 25], [16, 4], [17, 23], [17, 24], [17, 25], [17, 4], [18, 23], [18, 24], [18, 25], [18, 4]], [[19, 23], [19, 24], [19, 25], [19, 4], [20, 23], [20, 24], [20, 25], [20, 4], [21, 23], [21, 24], [21, 25], [21, 4], [23, 23], [23, 24], [23, 25], [23, 4]], [[24, 23], [24, 24], [24, 25], [24, 4], [25, 23], [25, 24], [25, 25], [25, 4], [26, 23], [26, 24], [26, 25], [26, 4], [27, 23], [27, 24], [27, 25], [27, 4]], [[28, 23], [28, 24], [28, 25], [28, 4], [29, 23], [29, 24], [29, 25], [29, 4], [30, 23], [30, 24], [30, 25], [30, 4], [31, 23], [31, 24], [31, 25], [31, 4]], [[127, 23], [127, 24], [127, 25], [127, 4], [220, 23], [220, 24], [220, 25], [220, 4], [249, 23], [249, 24], [249, 25], [249, 4], [10, 0], [13, 0], [22, 0], [256, 0]], [[192, 16], [192, 17], [192, 18], [192, 19], [192, 20], [192, 21], [192, 22], [192, 5], [193, 16], [193, 17], [193, 18], [193, 19], [193, 20], [193, 21], [193, 22], [193, 5]], [[200, 16], [200, 17], [200, 18], [200, 19], [200, 20], [200, 21], [200, 22], [200, 5], [201, 16], [201, 17], [201, 18], [201, 19], [201, 20], [201, 21], [201, 22], [201, 5]], [[202, 16], [202, 17], [202, 18], [202, 19], [202, 20], [202, 21], [202, 22], [202, 5], [205, 16], [205, 17], [205, 18], [205, 19], [205, 20], [205, 21], [205, 22], [205, 5]], [[210, 16], [210, 17], [210, 18], [210, 19], [210, 20], [210, 21], [210, 22], [210, 5], [213, 16], [213, 17], [213, 18], [213, 19], [213, 20], [213, 21], [213, 22], [213, 5]], [[218, 16], [218, 17], [218, 18], [218, 19], [218, 20], [218, 21], [218, 22], [218, 5], [219, 16], [219, 17], [219, 18], [219, 19], [219, 20], [219, 21], [219, 22], [219, 5]], [[238, 16], [238, 17], [238, 18], [238, 19], [238, 20], [238, 21], [238, 22], [238, 5], [240, 16], [240, 17], [240, 18], [240, 19], [240, 20], [240, 21], [240, 22], [240, 5]], [[242, 16], [242, 17], [242, 18], [242, 19], [242, 20], [242, 21], [242, 22], [242, 5], [243, 16], [243, 17], [243, 18], [243, 19], [243, 20], [243, 21], [243, 22], [243, 5]], [[255, 16], [255, 17], [255, 18], [255, 19], [255, 20], [255, 21], [255, 22], [255, 5], [203, 23], [203, 24], [203, 25], [203, 4], [204, 23], [204, 24], [204, 25], [204, 4]], [[211, 23], [211, 24], [211, 25], [211, 4], [212, 23], [212, 24], [212, 25], [212, 4], [214, 23], [214, 24], [214, 25], [214, 4], [221, 23], [221, 24], [221, 25], [221, 4]], [[222, 23], [222, 24], [222, 25], [222, 4], [223, 23], [223, 24], [223, 25], [223, 4], [241, 23], [241, 24], [241, 25], [241, 4], [244, 23], [244, 24], [244, 25], [244, 4]], [[245, 23], [245, 24], [245, 25], [245, 4], [246, 23], [246, 24], [246, 25], [246, 4], [247, 23], [247, 24], [247, 25], [247, 4], [248, 23], [248, 24], [248, 25], [248, 4]], [[250, 23], [250, 24], [250, 25], [250, 4], [251, 23], [251, 24], [251, 25], [251, 4], [252, 23], [252, 24], [252, 25], [252, 4], [253, 23], [253, 24], [253, 25], [253, 4]], [[254, 23], [254, 24], [254, 25], [254, 4], [2, 26], [2, 7], [3, 26], [3, 7], [4, 26], [4, 7], [5, 26], [5, 7], [6, 26], [6, 7], [7, 26], [7, 7]], [[8, 26], [8, 7], [11, 26], [11, 7], [12, 26], [12, 7], [14, 26], [14, 7], [15, 26], [15, 7], [16, 26], [16, 7], [17, 26], [17, 7], [18, 26], [18, 7]], [[19, 26], [19, 7], [20, 26], [20, 7], [21, 26], [21, 7], [23, 26], [23, 7], [24, 26], [24, 7], [25, 26], [25, 7], [26, 26], [26, 7], [27, 26], [27, 7]], [[28, 26], [28, 7], [29, 26], [29, 7], [30, 26], [30, 7], [31, 26], [31, 7], [127, 26], [127, 7], [220, 26], [220, 7], [249, 26], [249, 7], [nil, 247], [nil, 249]], [[10, 16], [10, 17], [10, 18], [10, 19], [10, 20], [10, 21], [10, 22], [10, 5], [13, 16], [13, 17], [13, 18], [13, 19], [13, 20], [13, 21], [13, 22], [13, 5]], [[48, 16], [48, 17], [48, 18], [48, 19], [48, 20], [48, 21], [48, 22], [48, 5], [49, 16], [49, 17], [49, 18], [49, 19], [49, 20], [49, 21], [49, 22], [49, 5]], [[22, 16], [22, 17], [22, 18], [22, 19], [22, 20], [22, 21], [22, 22], [22, 5], [256, 16], [256, 17], [256, 18], [256, 19], [256, 20], [256, 21], [256, 22], [256, 5]], [[50, 16], [50, 17], [50, 18], [50, 19], [50, 20], [50, 21], [50, 22], [50, 5], [97, 16], [97, 17], [97, 18], [97, 19], [97, 20], [97, 21], [97, 22], [97, 5]], [[99, 16], [99, 17], [99, 18], [99, 19], [99, 20], [99, 21], [99, 22], [99, 5], [101, 16], [101, 17], [101, 18], [101, 19], [101, 20], [101, 21], [101, 22], [101, 5]], [[105, 16], [105, 17], [105, 18], [105, 19], [105, 20], [105, 21], [105, 22], [105, 5], [111, 16], [111, 17], [111, 18], [111, 19], [111, 20], [111, 21], [111, 22], [111, 5]], [[115, 16], [115, 17], [115, 18], [115, 19], [115, 20], [115, 21], [115, 22], [115, 5], [116, 16], [116, 17], [116, 18], [116, 19], [116, 20], [116, 21], [116, 22], [116, 5]], [[32, 23], [32, 24], [32, 25], [32, 4], [37, 23], [37, 24], [37, 25], [37, 4], [45, 23], [45, 24], [45, 25], [45, 4], [46, 23], [46, 24], [46, 25], [46, 4]], [[47, 23], [47, 24], [47, 25], [47, 4], [51, 23], [51, 24], [51, 25], [51, 4], [52, 23], [52, 24], [52, 25], [52, 4], [53, 23], [53, 24], [53, 25], [53, 4]], ].each {|arr| arr.each {|subarr| subarr.each(&:freeze)}.freeze}.freeze end end end ruby-protocol-hpack-1.4.2/lib/protocol/hpack/version.rb000066400000000000000000000023071361527647700231550ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. module Protocol module HPACK VERSION = "1.4.2" end end ruby-protocol-hpack-1.4.2/spec/000077500000000000000000000000001361527647700163765ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/spec/protocol/000077500000000000000000000000001361527647700202375ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/spec/protocol/hpack/000077500000000000000000000000001361527647700213255ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/spec/protocol/hpack/compressor/000077500000000000000000000000001361527647700235215ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/spec/protocol/hpack/compressor/header_spec.rb000066400000000000000000000076451361527647700263240ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigheaders, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publisheaders, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'protocol/hpack/compressor' require 'protocol/hpack/decompressor' RSpec.describe Protocol::HPACK::Compressor do let(:buffer) {String.new.b} subject(:compressor) {described_class.new(buffer)} let(:decompressor) {Protocol::HPACK::Decompressor.new(buffer)} it 'should handle indexed representation' do headers = {name: 10, type: :indexed} compressor.write_header(headers) expect(buffer.getbyte(0) & 0x80).to eq 0x80 expect(buffer.getbyte(0) & 0x7f).to eq headers[:name] + 1 expect(decompressor.read_header).to eq headers end it 'should raise when decoding indexed representation witheaders index zero' do headers = {name: 10, type: :indexed} compressor.write_header(headers) buffer[0] = 0x80.chr(Encoding::BINARY) expect do decompressor.read_header end.to raise_error Protocol::HPACK::CompressionError end context 'literal w/o indexing representation' do it 'should handle indexed header' do headers = {name: 10, value: 'my-value', type: :no_index} compressor.write_header(headers) expect(buffer.getbyte(0) & 0xf0).to eq 0x0 expect(buffer.getbyte(0) & 0x0f).to eq headers[:name] + 1 expect(decompressor.read_header).to eq headers end it 'should handle literal header' do headers = {name: 'x-custom', value: 'my-value', type: :no_index} compressor.write_header(headers) expect(buffer.getbyte(0) & 0xf0).to eq 0x0 expect(buffer.getbyte(0) & 0x0f).to eq 0 expect(decompressor.read_header).to eq headers end end context 'literal w/ incremental indexing' do it 'should handle indexed header' do headers = {name: 10, value: 'my-value', type: :incremental} compressor.write_header(headers) expect(buffer.getbyte(0) & 0xc0).to eq 0x40 expect(buffer.getbyte(0) & 0x3f).to eq headers[:name] + 1 expect(decompressor.read_header).to eq headers end it 'should handle literal header' do headers = {name: 'x-custom', value: 'my-value', type: :incremental} compressor.write_header(headers) expect(buffer.getbyte(0) & 0xc0).to eq 0x40 expect(buffer.getbyte(0) & 0x3f).to eq 0 expect(decompressor.read_header).to eq headers end end context 'literal never indexed' do it 'should handle indexed header' do headers = {name: 10, value: 'my-value', type: :never_indexed} compressor.write_header(headers) expect(buffer.getbyte(0) & 0xf0).to eq 0x10 expect(buffer.getbyte(0) & 0x0f).to eq headers[:name] + 1 expect(decompressor.read_header).to eq headers end it 'should handle literal header' do headers = {name: 'x-custom', value: 'my-value', type: :never_indexed} compressor.write_header(headers) expect(buffer.getbyte(0) & 0xf0).to eq 0x10 expect(buffer.getbyte(0) & 0x0f).to eq 0 expect(decompressor.read_header).to eq headers end end end ruby-protocol-hpack-1.4.2/spec/protocol/hpack/compressor_spec.rb000066400000000000000000000117721361527647700250700ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'protocol/hpack/compressor' require 'protocol/hpack/decompressor' require 'json' RSpec.describe Protocol::HPACK::Compressor do describe '#write_integer' do let(:buffer) {String.new.b} subject {described_class.new(buffer)} context '0-bit prefix' do it "can encode the value 10" do subject.write_integer(10, 0) expect(buffer).to be == [10].pack('C') end it "can encode the value 1337" do subject.write_integer(1337, 0) expect(buffer).to be == [128 + 57, 10].pack('C*') end end context '5-bit prefix' do it "can encode the value 10" do subject.write_integer(10, 5) expect(buffer).to be == [10].pack('C') end it "can encode the value 1337" do subject.write_integer(1337, 5) expect(buffer).to be == [31, 128 + 26, 10].pack('C*') end end end describe '#write_string' do [ ['with huffman', :always, 0x80], ['without huffman', :never, 0], ].each do |description, huffman, msb| context description do let(:context) {Protocol::HPACK::Context.new(huffman: huffman)} let(:buffer) {String.new.b} subject {Protocol::HPACK::Compressor.new(buffer, context)} let(:decompressor) {Protocol::HPACK::Decompressor.new(buffer, context)} [ ['ascii codepoints', 'abcdefghij'], ['utf-8 codepoints', 'éáűőúöüó€'], ['long utf-8 strings', 'éáűőúöüó€' * 100], ].each do |datatype, plain| it "should handle #{datatype} #{description}" do subject.write_string(plain) expect(buffer.getbyte(0) & 0x80).to eq msb expect(decompressor.read_string).to eq plain end end end end context 'choosing shorter representation' do let(:context) {Protocol::HPACK::Context.new(huffman: :shorter)} let(:buffer) {String.new.b} subject {Protocol::HPACK::Compressor.new(buffer, context)} [ ['日本語', :plain], ['200', :huffman], ['xq', :plain], # prefer plain if equal size ].each do |string, choice| it "should return #{choice} representation" do subject.write_string(string) expect(buffer.getbyte(0) & 0x80).to eq(choice == :plain ? 0 : 0x80) end end end end describe '#encode' do let(:path) {File.expand_path("sequence1.json", __dir__)} let(:sequence) {JSON.parse(File.read(path))} let(:encoder) {Protocol::HPACK::Context.new} let(:decoder) {Protocol::HPACK::Context.new} it "can encode with small table size" do sequence.each do |headers| data = Protocol::HPACK::Compressor.new(String.new.b, encoder, table_size_limit: 512).encode(headers) expect(Protocol::HPACK::Decompressor.new(data, decoder).decode).to be == headers expect(encoder.table).to be == decoder.table end expect(decoder.table_size).to be == 512 end it "can encode with default table size" do sequence.each do |headers| data = Protocol::HPACK::Compressor.new(String.new.b, encoder).encode(headers) expect(Protocol::HPACK::Decompressor.new(data, decoder).decode).to be == headers expect(encoder.table).to be == decoder.table end end it "can encode with large table size" do sequence.each do |headers| data = Protocol::HPACK::Compressor.new(String.new.b, encoder, table_size_limit: 65536).encode(headers) expect(Protocol::HPACK::Decompressor.new(data, decoder).decode).to be == headers expect(encoder.table).to be == decoder.table end expect(decoder.table_size).to be == 65536 end it "can encode with random table sizes" do sequence.each do |headers| table_size = rand(128..65536) data = Protocol::HPACK::Compressor.new(String.new.b, encoder, table_size_limit: table_size).encode(headers) expect(Protocol::HPACK::Decompressor.new(data, decoder).decode).to be == headers expect(encoder.table).to be == decoder.table end end end end ruby-protocol-hpack-1.4.2/spec/protocol/hpack/context_spec.rb000066400000000000000000000076731361527647700243650ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'protocol/hpack/context' RSpec.describe Protocol::HPACK::Context do let(:context) {Protocol::HPACK::Context.new(table_size: 2048)} it 'should be initialized with empty headers' do expect(context.table).to be_empty end context 'processing' do [ ['no indexing', :no_index], ['never indexed', :never_indexed], ].each do |desc, type| context "#{desc}" do it 'should process indexed header with literal value' do original_table = context.table.dup emit = context.decode(name: 4, value: '/path', type: type) expect(emit).to eq [':path', '/path'] expect(context.table).to eq original_table end it 'should process literal header with literal value' do original_table = context.table.dup emit = context.decode(name: 'x-custom', value: 'random', type: type) expect(emit).to eq ['x-custom', 'random'] expect(context.table).to eq original_table end end end context 'incremental indexing' do it 'should process indexed header with literal value' do original_table = context.table.dup emit = context.decode(name: 4, value: '/path', type: :incremental) expect(emit).to eq [':path', '/path'] expect(context.table - original_table).to eq [[':path', '/path']] end it 'should process literal header with literal value' do original_table = context.table.dup context.decode(name: 'x-custom', value: 'random', type: :incremental) expect(context.table - original_table).to eq [['x-custom', 'random']] end end context 'size bounds' do it 'should drop headers from end of table' do context.instance_eval do add_to_table(['test1', '1' * 1024]) add_to_table(['test2', '2' * 500]) end original_table = context.table.dup original_size = original_table.join.bytesize + original_table.size * 32 context.decode( name: 'x-custom', value: 'a' * (2048 - original_size), type: :incremental ) expect(context.table.first[0]).to eq 'x-custom' expect(context.table.size).to eq original_table.size # number of entries end end it 'should clear table if entry exceeds table size' do context.instance_eval do add_to_table(['test1', '1' * 1024]) add_to_table(['test2', '2' * 500]) end h = {name: 'x-custom', value: 'a', index: 0, type: :incremental} e = {name: 'large', value: 'a' * 2048, index: 0} context.decode(h) context.decode(e.merge(type: :incremental)) expect(context.table).to be_empty end it 'should shrink table if set smaller size' do context.instance_eval do add_to_table(['test1', '1' * 1024]) add_to_table(['test2', '2' * 500]) end context.decode(type: :change_table_size, value: 1500) expect(context.table.size).to be 1 expect(context.table.first[0]).to eq 'test2' end end end ruby-protocol-hpack-1.4.2/spec/protocol/hpack/decompressor_spec.rb000066400000000000000000000046611361527647700254000ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'protocol/hpack/decompressor' require 'protocol/hpack/compressor' RSpec.describe Protocol::HPACK::Decompressor do let(:buffer) {String.new.b} let(:compressor) {Protocol::HPACK::Compressor.new(buffer)} context "limited table size" do subject {described_class.new(buffer, table_size_limit: 256)} it 'should reject table size update if exceed limit' do expect(subject.table_size_limit).to be == 256 compressor.write_header({type: :change_table_size, value: 512}) expect do subject.read_header end.to raise_error(Protocol::HPACK::CompressionError, /limit/) end end describe '#read_integer' do subject {described_class.new(buffer)} context '0-bit prefix' do it "can decode the value 10" do buffer << [10].pack('C') expect(subject.read_integer(0)).to be == 10 end it "can decode the value 1337" do buffer << [128 + 57, 10].pack('C*') expect(subject.read_integer(0)).to be == 1337 end end context '5-bit prefix' do it "can decode the value 10" do buffer << [10].pack('C') expect(subject.read_integer(5)).to be == 10 end it "can decode the value 1337" do buffer << [31, 128 + 26, 10].pack('C*') expect(subject.read_integer(5)).to be == 1337 end end end end ruby-protocol-hpack-1.4.2/spec/protocol/hpack/external_spec.rb000066400000000000000000000066371361527647700245220ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'protocol/hpack/compressor' require 'protocol/hpack/decompressor' require 'json' RSpec.describe Protocol::HPACK::Decompressor do folders = %w( go-hpack haskell-http2-diff haskell-http2-diff-huffman haskell-http2-linear haskell-http2-linear-huffman haskell-http2-naive haskell-http2-naive-huffman haskell-http2-static haskell-http2-static-huffman nghttp2 nghttp2-16384-4096 nghttp2-change-table-size node-http2-hpack ) let(:buffer) {String.new.b} folders.each do |folder| root = File.expand_path("fixtures/#{folder}", __dir__) context folder.to_s, if: File.directory?(root) do Dir.glob(File.join(root, "*.json")) do |path| it "should decode #{File.basename(path)}" do story = JSON.parse(File.read(path)) cases = story['cases'] table_size = cases[0]['header_table_size'] || 4096 context = Protocol::HPACK::Context.new(table_size: table_size) decompressor = Protocol::HPACK::Decompressor.new(buffer, context) cases.each do |c| buffer << [c['wire']].pack('H*').force_encoding(Encoding::BINARY) headers = c['headers'].flat_map(&:to_a) emitted = decompressor.decode expect(emitted).to eq headers end end end end end end if ENV['COVERAGE'].nil? RSpec.describe Protocol::HPACK::Compressor do root = File.expand_path('fixtures/raw-data', __dir__) let(:buffer) {String.new.b} Protocol::HPACK::MODES.each do |mode, encoding_options| [4096, 512].each do |table_size| options = {table_size: table_size} options.update(encoding_options) context "with #{mode} mode and table_size #{table_size}" do Dir.glob(File.join(root, "*.json")) do |path| it "should encode #{File.basename(path)}" do story = JSON.parse(File.read(path)) cases = story['cases'] context = Protocol::HPACK::Context.new(**options) compressor = Protocol::HPACK::Compressor.new(buffer, context) decompressor = Protocol::HPACK::Decompressor.new(buffer) cases.each do |c| headers = c['headers'].flat_map(&:to_a) compressor.encode(headers) decoded = decompressor.decode expect(decoded).to eq headers end end end end end end end if ENV['COVERAGE'].nil? ruby-protocol-hpack-1.4.2/spec/protocol/hpack/fixtures/000077500000000000000000000000001361527647700231765ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/spec/protocol/hpack/huffman_spec.rb000066400000000000000000000070221361527647700243110ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'protocol/hpack/huffman' RSpec.describe Protocol::HPACK::Huffman do huffman_examples = [ # plain, encoded ['www.example.com', 'f1e3c2e5f23a6ba0ab90f4ff'], ['no-cache', 'a8eb10649cbf'], ['Mon, 21 Oct 2013 20:13:21 GMT', 'd07abe941054d444a8200595040b8166e082a62d1bff'], ] context 'encode' do huffman_examples.each do |plain, encoded| it "should encode #{plain} into #{encoded}" do expect(subject.encode(plain).unpack1('H*')).to eq encoded end end end context 'decode' do huffman_examples.each do |plain, encoded| it "should decode #{encoded} into #{plain}" do expect(subject.decode([encoded].pack('H*'))).to eq plain end end [ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'http://www.craigslist.org/about/sites/', 'cl_b=AB2BKbsl4hGM7M4nH5PYWghTM5A; cl_def_lang=en; cl_def_hp=shoals', 'image/png,image/*;q=0.8,*/*;q=0.5', 'BX=c99r6jp89a7no&b=3&s=q4; localization=en-us%3Bus%3Bus', 'UTF-8でエンコードした日本語文字列', ].each do |string| it "should encode then decode '#{string}' into the same" do encoded = subject.encode(string.b) expect(subject.decode(encoded)).to eq string.b end end it 'should encode/decode all_possible 2-byte sequences' do (2**16).times do |n| string = [n].pack('V')[0, 2].b expect(subject.decode(subject.encode(string))).to eq string end end it 'should raise when input is shorter than expected' do encoded = huffman_examples.first.last encoded = [encoded].pack('H*') expect do subject.decode(encoded[0...-1].b) end.to raise_error(/EOS invalid/) end it 'should raise when input is not padded by 1s' do # note the fe at end encoded = 'f1e3c2e5f23a6ba0ab90f4fe' encoded = [encoded].pack('H*') expect do subject.decode(encoded.b) end.to raise_error(/EOS invalid/) end it 'should raise when exceedingly padded' do # note the extra ff encoded = 'e7cf9bebe89b6fb16fa9b6ffff' encoded = [encoded].pack('H*') expect do subject.decode(encoded.b) end.to raise_error(/EOS invalid/) end it 'should raise when EOS is explicitly encoded' do # a b EOS encoded = ['1c7fffffffff'].pack('H*') expect do subject.decode(encoded.b) end.to raise_error(/EOS found/) end end end ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541/000077500000000000000000000000001361527647700224205ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541/d-3-request-examples-without-huffman.yaml000066400000000000000000000020731361527647700323160ustar00rootroot00000000000000--- :title: D.3. Request Examples without Huffman :type: :request :table_size: 4096 :huffman: :never :streams: - :wire: 8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d :emitted: - - ":method" - GET - - ":scheme" - http - - ":path" - "/" - - ":authority" - www.example.com :table: - - ":authority" - www.example.com :table_size: 57 - :wire: 8286 84be 5808 6e6f 2d63 6163 6865 :emitted: - - ":method" - GET - - ":scheme" - http - - ":path" - "/" - - ":authority" - www.example.com - - cache-control - no-cache :table: - - cache-control - no-cache - - ":authority" - www.example.com :table_size: 110 - :wire: 8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65 :emitted: - - ":method" - GET - - ":scheme" - https - - ":path" - "/index.html" - - ":authority" - www.example.com - - custom-key - custom-value :table: - - custom-key - custom-value - - cache-control - no-cache - - ":authority" - www.example.com :table_size: 164 ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541/d-4-request-examples-with-huffman.yaml000066400000000000000000000020401361527647700315610ustar00rootroot00000000000000--- :title: D.4. Request Examples with Huffman :type: :request :table_size: 4096 :huffman: :always :streams: - :wire: 8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff :emitted: - - ":method" - GET - - ":scheme" - http - - ":path" - "/" - - ":authority" - www.example.com :table: - - ":authority" - www.example.com :table_size: 57 - :wire: 8286 84be 5886 a8eb 1064 9cbf :emitted: - - ":method" - GET - - ":scheme" - http - - ":path" - "/" - - ":authority" - www.example.com - - cache-control - no-cache :table: - - cache-control - no-cache - - ":authority" - www.example.com :table_size: 110 - :wire: 8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf :emitted: - - ":method" - GET - - ":scheme" - https - - ":path" - "/index.html" - - ":authority" - www.example.com - - custom-key - custom-value :table: - - custom-key - custom-value - - cache-control - no-cache - - ":authority" - www.example.com :table_size: 164 ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541/d-5-response-examples-without-huffman.yaml000066400000000000000000000033471361527647700324730ustar00rootroot00000000000000--- :title: D.5. Response Examples without Huffman :type: :response :table_size: 256 :huffman: :never :streams: - :wire: 4803 3330 3258 0770 7269 7661 7465 611d 4d6f 6e2c 2032 3120 4f63 7420 3230 3133 2032 303a 3133 3a32 3120 474d 546e 1768 7474 7073 3a2f 2f77 7777 2e65 7861 6d70 6c65 2e63 6f6d :emitted: - - ":status" - '302' - - cache-control - private - - date - Mon, 21 Oct 2013 20:13:21 GMT - - location - https://www.example.com :table: - - location - https://www.example.com - - date - Mon, 21 Oct 2013 20:13:21 GMT - - cache-control - private - - ":status" - '302' :table_size: 222 - :wire: 4803 3330 37c1 c0bf :emitted: - - ":status" - '307' - - cache-control - private - - date - Mon, 21 Oct 2013 20:13:21 GMT - - location - https://www.example.com :table: - - ":status" - '307' - - location - https://www.example.com - - date - Mon, 21 Oct 2013 20:13:21 GMT - - cache-control - private :table_size: 222 - :wire: 88c1 611d 4d6f 6e2c 2032 3120 4f63 7420 3230 3133 2032 303a 3133 3a32 3220 474d 54c0 5a04 677a 6970 7738 666f 6f3d 4153 444a 4b48 514b 425a 584f 5157 454f 5049 5541 5851 5745 4f49 553b 206d 6178 2d61 6765 3d33 3630 303b 2076 6572 7369 6f6e 3d31 :emitted: - - ":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 :table: - - set-cookie - foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1 - - content-encoding - gzip - - date - Mon, 21 Oct 2013 20:13:22 GMT :table_size: 215 ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541/d-6-a-response-examples-with-huffman.yaml000066400000000000000000000005111361527647700321500ustar00rootroot00000000000000--- :title: D.6.a Response Examples with Huffman - dynamic table size updates should not trigger exceptions :type: :response :table_size: 4096 :huffman: :always :only: :decompressor :streams: - :wire: 2088 7689 aa63 55e5 80ae 16d7 17 :emitted: - [":status", "200"] - ["server", "nginx/1.15.2"] :table: [] :table_size: 0ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541/d-6-response-examples-with-huffman.yaml000066400000000000000000000032061361527647700317360ustar00rootroot00000000000000--- :title: D.6. Response Examples with Huffman :type: :response :table_size: 256 :huffman: :always :streams: - :wire: 4882 6402 5885 aec3 771a 4b61 96d0 7abe 9410 54d4 44a8 2005 9504 0b81 66e0 82a6 2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8 e9ae 82ae 43d3 :emitted: - - ":status" - '302' - - cache-control - private - - date - Mon, 21 Oct 2013 20:13:21 GMT - - location - https://www.example.com :table: - - location - https://www.example.com - - date - Mon, 21 Oct 2013 20:13:21 GMT - - cache-control - private - - ":status" - '302' :table_size: 222 - :wire: 4883 640e ffc1 c0bf :emitted: - - ":status" - '307' - - cache-control - private - - date - Mon, 21 Oct 2013 20:13:21 GMT - - location - https://www.example.com :table: - - ":status" - '307' - - location - https://www.example.com - - date - Mon, 21 Oct 2013 20:13:21 GMT - - cache-control - private :table_size: 222 - :wire: 88c1 6196 d07a be94 1054 d444 a820 0595 040b 8166 e084 a62d 1bff c05a 839b d9ab 77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07 :emitted: - - ":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 :table: - - set-cookie - foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1 - - content-encoding - gzip - - date - Mon, 21 Oct 2013 20:13:22 GMT :table_size: 215 ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541/dump.rb000066400000000000000000000142101361527647700237100ustar00rootroot00000000000000#!/usr/bin/env ruby # frozen_string_literal: true require 'yaml' spec_examples = [ {title: 'D.3. Request Examples without Huffman', type: :request, table_size: 4096, huffman: :never, streams: [ {wire: "8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d", emitted: [ [':method', 'GET'], [':scheme', 'http'], [':path', '/'], [':authority', 'www.example.com'], ], table: [ [':authority', 'www.example.com'], ], table_size: 57, }, {wire: '8286 84be 5808 6e6f 2d63 6163 6865', emitted: [ [':method', 'GET'], [':scheme', 'http'], [':path', '/'], [':authority', 'www.example.com'], ['cache-control', 'no-cache'], ], table: [ ['cache-control', 'no-cache'], [':authority', 'www.example.com'], ], table_size: 110, }, {wire: "8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65", emitted: [ [':method', 'GET'], [':scheme', 'https'], [':path', '/index.html'], [':authority', 'www.example.com'], ['custom-key', 'custom-value'], ], table: [ ['custom-key', 'custom-value'], ['cache-control', 'no-cache'], [':authority', 'www.example.com'], ], table_size: 164, }, ], }, {title: 'D.4. Request Examples with Huffman', type: :request, table_size: 4096, huffman: :always, streams: [ {wire: '8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff', emitted: [ [':method', 'GET'], [':scheme', 'http'], [':path', '/'], [':authority', 'www.example.com'], ], table: [ [':authority', 'www.example.com'], ], table_size: 57, }, {wire: '8286 84be 5886 a8eb 1064 9cbf', emitted: [ [':method', 'GET'], [':scheme', 'http'], [':path', '/'], [':authority', 'www.example.com'], ['cache-control', 'no-cache'], ], table: [ ['cache-control', 'no-cache'], [':authority', 'www.example.com'], ], table_size: 110, }, {wire: "8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf", emitted: [ [':method', 'GET'], [':scheme', 'https'], [':path', '/index.html'], [':authority', 'www.example.com'], ['custom-key', 'custom-value'], ], table: [ ['custom-key', 'custom-value'], ['cache-control', 'no-cache'], [':authority', 'www.example.com'], ], table_size: 164, }, ], }, {title: 'D.5. Response Examples without Huffman', type: :response, table_size: 256, huffman: :never, streams: [ {wire: "4803 3330 3258 0770 7269 7661 7465 611d 4d6f 6e2c 2032 3120 4f63 7420 3230 3133 2032 303a 3133 3a32 3120 474d 546e 1768 7474 7073 3a2f 2f77 7777 2e65 7861 6d70 6c65 2e63 6f6d", emitted: [ [':status', '302'], ['cache-control', 'private'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['location', 'https://www.example.com'], ], table: [ ['location', 'https://www.example.com'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['cache-control', 'private'], [':status', '302'], ], table_size: 222, }, {wire: '4803 3330 37c1 c0bf', emitted: [ [':status', '307'], ['cache-control', 'private'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['location', 'https://www.example.com'], ], table: [ [':status', '307'], ['location', 'https://www.example.com'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['cache-control', 'private'], ], table_size: 222, }, {wire: "88c1 611d 4d6f 6e2c 2032 3120 4f63 7420 3230 3133 2032 303a 3133 3a32 3220 474d 54c0 5a04 677a 6970 7738 666f 6f3d 4153 444a 4b48 514b 425a 584f 5157 454f 5049 5541 5851 5745 4f49 553b 206d 6178 2d61 6765 3d33 3630 303b 2076 6572 7369 6f6e 3d31", emitted: [ [':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'], ], table: [ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1'], ['content-encoding', 'gzip'], ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'], ], table_size: 215, }, ], }, {title: 'D.6. Response Examples with Huffman', type: :response, table_size: 256, huffman: :always, streams: [ { wire: "4882 6402 5885 aec3 771a 4b61 96d0 7abe 9410 54d4 44a8 2005 9504 0b81 66e0 82a6 2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8 e9ae 82ae 43d3", emitted: [ [':status', '302'], ['cache-control', 'private'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['location', 'https://www.example.com'], ], table: [ ['location', 'https://www.example.com'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['cache-control', 'private'], [':status', '302'], ], table_size: 222, }, { wire: '4883 640e ffc1 c0bf', emitted: [ [':status', '307'], ['cache-control', 'private'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['location', 'https://www.example.com'], ], table: [ [':status', '307'], ['location', 'https://www.example.com'], ['date', 'Mon, 21 Oct 2013 20:13:21 GMT'], ['cache-control', 'private'], ], table_size: 222, }, { wire: "88c1 6196 d07a be94 1054 d444 a820 0595 040b 8166 e084 a62d 1bff c05a 839b d9ab 77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07", emitted: [ [':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'], ], table: [ ['set-cookie', 'foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1'], ['content-encoding', 'gzip'], ['date', 'Mon, 21 Oct 2013 20:13:22 GMT'], ], table_size: 215, }, ], }, ] spec_examples.each do |example| name = example[:title].downcase.gsub(/[\.\s]+/, "-") + ".yaml" File.open(File.expand_path(name, __dir__), "w") do |file| file.write(YAML.dump(example)) end end ruby-protocol-hpack-1.4.2/spec/protocol/hpack/rfc7541_spec.rb000066400000000000000000000052411361527647700237610ustar00rootroot00000000000000# frozen_string_literal: true require 'protocol/hpack/compressor' require 'protocol/hpack/decompressor' require 'yaml' RSpec.describe "RFC7541" do def self.fixtures(mode) Dir.glob(File.expand_path("rfc7541/*.yaml", __dir__)) do |path| fixture = YAML::load_file(path) if only = fixture[:only] next unless only == mode end yield fixture end end context Protocol::HPACK::Decompressor do fixtures(:decompressor) do |example| context example[:title] do example[:streams].size.times do |nth| context "request #{nth + 1}" do let(:context) {Protocol::HPACK::Context.new(huffman: example[:huffman], table_size: example[:table_size])} let(:buffer) {String.new.b} let(:decompressor) {Protocol::HPACK::Decompressor.new(buffer, context)} before do (0...nth).each do |i| buffer << [example[:streams][i][:wire].gsub(/\s/, '')].pack('H*') decompressor.decode end end let(:bytes) {[example[:streams][nth][:wire].gsub(/\s/, '')].pack('H*')} subject! do buffer << bytes decompressor.decode end it 'should emit expected headers' do expect(subject).to eq example[:streams][nth][:emitted] end it 'should update header table' do expect(context.table).to eq example[:streams][nth][:table] end it 'should compute header table size' do expect(context.current_table_size).to eq example[:streams][nth][:table_size] end end end end end end context Protocol::HPACK::Compressor do fixtures(:compressor) do |example| context example[:title] do example[:streams].size.times do |nth| context "request #{nth + 1}" do let(:context) {Protocol::HPACK::Context.new(huffman: example[:huffman], table_size: example[:table_size])} let(:buffer) {String.new.b} let(:compressor) {Protocol::HPACK::Compressor.new(buffer, context)} before do (0...nth).each do |i| compressor.encode(example[:streams][i][:emitted]) end end subject! do buffer.clear compressor.encode(example[:streams][nth][:emitted]) buffer end it 'should emit expected bytes' do expect(subject.unpack1('H*')).to eq example[:streams][nth][:wire].gsub(/\s/, '') end it 'should update header table' do expect(context.table).to eq example[:streams][nth][:table] end it 'should compute header table size' do expect(context.current_table_size).to eq example[:streams][nth][:table_size] end end end end end end endruby-protocol-hpack-1.4.2/spec/protocol/hpack/sequence1.json000066400000000000000000000150371361527647700241170ustar00rootroot00000000000000[ [[":status", "200"], ["content-type", "text/html; charset=utf-8"], ["cache-control", "public, max-age=3600"], ["expires", "Tue, 18 Jun 2019 03:17:44 GMT"], ["content-encoding", "gzip"]], [[":status", "200"], ["last-modified", "Thu, 07 Feb 2019 03:14:24 GMT"], ["content-type", "text/css"], ["cache-control", "public, max-age=3600"], ["etag", "a9ed9d04741fa5a25a7e35d44318de8cbf60c74e"], ["accept-ranges", "bytes"], ["content-encoding", "gzip"]], [[":status", "200"], ["last-modified", "Wed, 29 Mar 2017 22:50:36 GMT"], ["content-type", "application/javascript"], ["cache-control", "public, max-age=3600"], ["etag", "d6861894c429addb06e90587d8db73b3a7996732"], ["accept-ranges", "bytes"], ["content-encoding", "gzip"]], [[":status", "200"], ["last-modified", "Wed, 29 Mar 2017 22:50:36 GMT"], ["content-type", "text/css"], ["cache-control", "public, max-age=3600"], ["etag", "9c6eace97e828fceb1fbe19539306ec130656eba"], ["accept-ranges", "bytes"], ["content-encoding", "gzip"]], [[":status", "200"], ["last-modified", "Wed, 29 Mar 2017 22:50:36 GMT"], ["content-type", "text/css"], ["cache-control", "public, max-age=3600"], ["etag", "95ada2a665ccdb912f6d6ac4a65069f416ec3398"], ["accept-ranges", "bytes"], ["content-encoding", "gzip"]], [[":status", "200"], ["last-modified", "Wed, 29 Mar 2017 22:50:36 GMT"], ["content-type", "application/javascript"], ["cache-control", "public, max-age=3600"], ["etag", "72e86e05a87c2ee89138e0d76c8a7b1f92c64592"], ["accept-ranges", "bytes"], ["content-encoding", "gzip"]], [[":status", "200"], ["content-length", "457447"], ["last-modified", "Wed, 13 Jan 2016 03:53:18 GMT"], ["content-type", "image/svg+xml"], ["cache-control", "public, max-age=3600"], ["etag", "b46169a8f85057e89f850621fecf595b3b903633"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "80027"], ["last-modified", "Mon, 17 Jun 2019 22:35:55 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public,max-age=3600"], ["etag", "a7f6fcc0ac1366a0db8d5145179fdcd0d613c123"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "61409"], ["last-modified", "Mon, 17 Jun 2019 22:35:55 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public,max-age=3600"], ["etag", "fc214399b432cbd43a6cb3476e03087cf46fa4e4"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "131654"], ["last-modified", "Mon, 17 Jun 2019 22:35:56 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "612d28f2b46c7fb2f99222b5c4748ec2a5ddbb4b"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "118529"], ["last-modified", "Mon, 17 Jun 2019 22:35:56 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "cc4854f05953176f01fbfa32a98b89cb09524b78"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "98399"], ["last-modified", "Mon, 17 Jun 2019 22:35:56 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public,max-age=3600"], ["etag", "3e7702604e29db07c342ee769fde118dcd75c358"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "112008"], ["last-modified", "Mon, 17 Jun 2019 22:35:56 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "beed08ba661b3288bca6bccf57c34694fcbdc5e4"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "114601"], ["last-modified", "Mon, 17 Jun 2019 22:35:56 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "bf09f52fc9f0d4b55f6c13ef28df051527383521"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "113592"], ["last-modified", "Mon, 17 Jun 2019 22:35:57 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "2759fffe3db30b2679e01ec221d69cfd903b5b60"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "104024"], ["last-modified", "Mon, 17 Jun 2019 22:35:57 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "87d99041cee40b79962ba387bf4793c9a4c8692c"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "75993"], ["last-modified", "Mon, 17 Jun 2019 22:35:57 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public,max-age=3600"], ["etag", "c84bba35b84236a790b7fd69c310812a150ade91"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "126693"], ["last-modified", "Mon, 17 Jun 2019 22:35:57 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "3d58af58da977d4867fc639f99d333b3cb283775"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "82218"], ["last-modified", "Mon, 17 Jun 2019 22:35:57 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public,max-age=3600"], ["etag", "44b9cced590ea0360f375f9591d1acc142e0fac0"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "92190"], ["last-modified", "Mon, 17 Jun 2019 22:35:58 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public,max-age=3600"], ["etag", "172b50bf8c20b39cc6021b1a78e0076c47bfe36b"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "87902"], ["last-modified", "Mon, 17 Jun 2019 22:35:58 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public,max-age=3600"], ["etag", "9eb9abb486e0a55a2fe67f3562d4350b61310e99"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "123659"], ["last-modified", "Mon, 17 Jun 2019 22:35:58 GMT"], ["content-type", "image/jpeg"], ["cache-control", "public, max-age=3600"], ["etag", "43694484fd51c7a223974cb206cff32080133da8"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "563"], ["last-modified", "Mon, 11 Jan 2016 00:20:51 GMT"], ["content-type", "image/svg+xml"], ["cache-control", "public, max-age=3600"], ["etag", "f9c0d0b68537f93fec6f95a363540a8a15fe3847"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "53760"], ["last-modified", "Mon, 16 Nov 2015 02:15:20 GMT"], ["content-type", "application/x-font-ttf"], ["cache-control", "public, max-age=3600"], ["etag", "1e29bf01382900319878413547486128df7c5bdb"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-length", "457219"], ["last-modified", "Mon, 11 Jan 2016 00:13:16 GMT"], ["content-type", "image/svg+xml"], ["cache-control", "public, max-age=3600"], ["etag", "67122d85ad83c7de391ac8072319802702cab4ed"], ["accept-ranges", "bytes"]], [[":status", "200"], ["content-type", "text/html; charset=utf-8"], ["cache-control", "public, max-age=3600"], ["expires", "Tue, 18 Jun 2019 03:17:45 GMT"], ["content-encoding", "gzip"]] ]ruby-protocol-hpack-1.4.2/spec/protocol/hpack_spec.rb000066400000000000000000000024401361527647700226640ustar00rootroot00000000000000# frozen_string_literal: true # Copyright, 2018, by Samuel G. D. Williams. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'protocol/hpack' RSpec.describe Protocol::HPACK do it "has a version number" do expect(Protocol::HPACK::VERSION).not_to be nil end end ruby-protocol-hpack-1.4.2/spec/spec_helper.rb000066400000000000000000000005601361527647700212150ustar00rootroot00000000000000# frozen_string_literal: true require 'covered/rspec' RSpec.configure do |config| # Enable flags like --only-failures and --next-failure config.example_status_persistence_file_path = ".rspec_status" # Disable RSpec exposing methods globally on `Module` and `main` config.disable_monkey_patching! config.expect_with :rspec do |c| c.syntax = :expect end end ruby-protocol-hpack-1.4.2/tasks/000077500000000000000000000000001361527647700165715ustar00rootroot00000000000000ruby-protocol-hpack-1.4.2/tasks/huffman.rake000066400000000000000000000003051361527647700210570ustar00rootroot00000000000000# frozen_string_literal: true namespace :huffman do desc 'Generate the huffman state table' task :generate_table do require_relative 'huffman' Huffman::Node.generate_state_table end end ruby-protocol-hpack-1.4.2/tasks/huffman.rb000066400000000000000000000110631361527647700205430ustar00rootroot00000000000000# frozen_string_literal: true require_relative '../lib/http/hpack/huffman' require 'set' module Huffman BITS_AT_ONCE = HTTP::HPACK::Huffman::BITS_AT_ONCE EOS = 256 class Node attr_accessor :next, :emit, :final, :depth attr_accessor :transitions attr_accessor :id @@id = 0 # rubocop:disable Style/ClassVars def initialize(depth) @next = [nil, nil] @id = @@id @@id += 1 # rubocop:disable Style/ClassVars @final = false @depth = depth end def add(code, len, chr) self.final = true if chr == EOS && @depth <= 7 if len.zero? @emit = chr else bit = (code & (1 << (len - 1))).zero? ? 0 : 1 node = @next[bit] ||= Node.new(@depth + 1) node.add(code, len - 1, chr) end end class Transition attr_accessor :emit, :node def initialize(emit, node) @emit = emit @node = node end end def self.generate_tree @root = new(0) HTTP::HPACK::Huffman::CODES.each_with_index do |c, chr| code, len = c @root.add(code, len, chr) end puts "#{@@id} nodes" @root end def self.generate_machine generate_tree togo = Set[@root] @states = Set[@root] until togo.empty? node = togo.first togo.delete(node) next if node.transitions node.transitions = Array[1 << BITS_AT_ONCE] (1 << BITS_AT_ONCE).times do |input| n = node emit = '' (BITS_AT_ONCE - 1).downto(0) do |i| bit = (input & (1 << i)).zero? ? 0 : 1 n = n.next[bit] next unless n.emit if n.emit == EOS emit = EOS # cause error on decoding else emit << n.emit.chr(Encoding::BINARY) unless emit == EOS end n = @root end node.transitions[input] = Transition.new(emit, n) togo << n @states << n end end puts "#{@states.size} states" @root end def self.generate_state_table generate_machine state_id = {} id_state = {} state_id[@root] = 0 id_state[0] = @root max_final = 0 id = 1 (@states - [@root]).sort_by {|s| s.final ? 0 : 1}.each do |s| state_id[s] = id id_state[id] = s max_final = id if s.final id += 1 end File.open(File.expand_path('../lib/http/hpack/huffman/machine.rb', File.dirname(__FILE__)), 'w') do |f| f.print <
# Copyrigh, 2013, by Ilya Grigorik. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # Machine generated Huffman decoder state machine. # DO NOT EDIT THIS FILE. module Protocol module HPACK class Huffman # :nodoc: MAX_FINAL_STATE = #{max_final} MACHINE = [ HEADER id.times do |i| n = id_state[i] f.print "\t\t\t\t[" string = (1 << BITS_AT_ONCE).times.map do |t| transition = n.transitions.fetch(t) emit = transition.emit unless emit == EOS bytes = emit.bytes fail ArgumentError if bytes.size > 1 emit = bytes.first end "[#{emit.inspect}, #{state_id.fetch(transition.node)}]" end.join(', ') f.print(string) f.print "],\n" end f.print <> 4), b & 0xf]} until nibbles.empty? nb = nibbles.shift t = n.transitions[nb] emit << t.emit n = t.node end unless n.final && nibbles.all? {|x| x == 0xf} puts "len = #{emit.size} n.final = #{n.final} nibbles = #{nibbles}" end emit end end end