class Protocol::HPACK::Compressor
Responsible for encoding header key-value pairs using HPACK
algorithm.
Attributes
Public Class Methods
# File lib/protocol/hpack/compressor.rb, line 53 def initialize(buffer, context = Context.new, table_size_limit: nil) @buffer = buffer @context = context @table_size_limit = table_size_limit end
Public Instance Methods
Encodes provided list of HTTP headers.
@param headers [Array] +[[name, value], …]+ @return [Buffer]
# File lib/protocol/hpack/compressor.rb, line 188 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
# File lib/protocol/hpack/compressor.rb, line 108 def huffman @context.huffman end
# File lib/protocol/hpack/compressor.rb, line 66 def write_byte(byte) @buffer << byte.chr end
# File lib/protocol/hpack/compressor.rb, line 70 def write_bytes(bytes) @buffer << bytes end
Encodes header command with appropriate header representation.
@param h [Hash] header command @param buffer [String] @return [Buffer]
# File lib/protocol/hpack/compressor.rb, line 159 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 value via integer representation.
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
# File lib/protocol/hpack/compressor.rb, line 89 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
Encodes provided value via string literal representation.
-
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
# File lib/protocol/hpack/compressor.rb, line 132 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