Class: HTTP::HPACK::Decompressor

Inherits:
Object
  • Object
show all
Defined in:
lib/http/hpack/decompressor.rb

Overview

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.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buffer, context = Context.new) ⇒ Decompressor

Returns a new instance of Decompressor.



31
32
33
34
35
# File 'lib/http/hpack/decompressor.rb', line 31

def initialize(buffer, context = Context.new)
	@buffer = buffer
	@context = context
	@offset = 0
end

Instance Attribute Details

#bufferObject (readonly)

Returns the value of attribute buffer.



37
38
39
# File 'lib/http/hpack/decompressor.rb', line 37

def buffer
  @buffer
end

#contextObject (readonly)

Returns the value of attribute context.



38
39
40
# File 'lib/http/hpack/decompressor.rb', line 38

def context
  @context
end

#offsetObject (readonly)

Returns the value of attribute offset.



39
40
41
# File 'lib/http/hpack/decompressor.rb', line 39

def offset
  @offset
end

Instance Method Details

#decode(list = []) ⇒ Array

Decodes and processes header commands within provided buffer.

Parameters:

  • buffer (Buffer)

Returns:

  • (Array)

    [[name, value], …]



143
144
145
146
147
148
149
150
151
# File 'lib/http/hpack/decompressor.rb', line 143

def decode(list = [])
	while !end?
		if pair = @context.decode(read_header)
			list << pair
		end
	end
	
	return list
end

#end?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/http/hpack/decompressor.rb', line 41

def end?
	@offset >= @buffer.bytesize
end

#peek_byteObject



54
55
56
# File 'lib/http/hpack/decompressor.rb', line 54

def peek_byte
	@buffer.getbyte(@offset)
end

#read_byteObject



45
46
47
48
49
50
51
# File 'lib/http/hpack/decompressor.rb', line 45

def read_byte
	if byte = @buffer.getbyte(@offset)
		@offset += 1
	end
	
	return byte
end

#read_bytes(length) ⇒ Object



58
59
60
61
62
63
64
# File 'lib/http/hpack/decompressor.rb', line 58

def read_bytes(length)
	slice = @buffer.byteslice(@offset, length)
	
	@offset += length
	
	return slice
end

#read_headerHash

Decodes header command from provided buffer.

Parameters:

  • buffer (Buffer)

Returns:

  • (Hash)

    command

Raises:



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/http/hpack/decompressor.rb', line 107

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 :changetablesize
		header[:value] = header[:name]
	else
		if (header[:name]).zero?
			header[:name] = read_string
		else
			header[:name] -= 1
		end
		
		header[:value] = read_string
	end

	return header
end

#read_integer(bits) ⇒ Integer

Decodes integer value from provided buffer.

Parameters:

  • bits (Integer)

    number of available bits

Returns:

  • (Integer)


70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/http/hpack/decompressor.rb', line 70

def read_integer(bits)
	limit = 2**bits - 1
	value = !bits.zero? ? (read_byte & limit) : 0
	
	shift = 0
	
	while byte = read_byte
		value += ((byte & 127) << shift)
		shift += 7
		
		break if (byte & 128).zero?
	end if (value == limit)

	return value
end

#read_stringString

Decodes string value from provided buffer.

Returns:

  • (String)

    UTF-8 encoded string

Raises:



90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/http/hpack/decompressor.rb', line 90

def read_string
	huffman = (peek_byte & 0x80) == 0x80
	
	length = read_integer(7)
	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