aboutsummaryrefslogtreecommitdiffstats
path: root/lib/plum/hpack/decoder.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plum/hpack/decoder.rb')
-rw-r--r--lib/plum/hpack/decoder.rb96
1 files changed, 53 insertions, 43 deletions
diff --git a/lib/plum/hpack/decoder.rb b/lib/plum/hpack/decoder.rb
index 13833c1..b536123 100644
--- a/lib/plum/hpack/decoder.rb
+++ b/lib/plum/hpack/decoder.rb
@@ -10,42 +10,47 @@ module Plum
end
def decode(str)
- str = str.dup
headers = []
- headers << parse!(str) while str.size > 0
- headers.compact
+ pos = 0
+ lpos = str.bytesize
+ while pos < lpos
+ l, succ = parse(str, pos)
+ pos += succ
+ headers << l if l
+ end
+ headers
end
private
- def parse!(str)
- first_byte = str.uint8
- if first_byte >= 128 # 0b1XXXXXXX
- parse_indexed!(str)
- elsif first_byte >= 64 # 0b01XXXXXX
- parse_indexing!(str)
- elsif first_byte >= 32 # 0b001XXXXX
- self.limit = read_integer!(str, 5)
- nil
+ def parse(str, pos)
+ first_byte = str.uint8(pos)
+ if first_byte >= 0x80 # 0b1XXXXXXX
+ parse_indexed(str, pos)
+ elsif first_byte >= 0x40 # 0b01XXXXXX
+ parse_indexing(str, pos)
+ elsif first_byte >= 0x20 # 0b001XXXXX
+ self.limit, succ = read_integer(str, pos, 5)
+ [nil, succ]
else # 0b0000XXXX (without indexing) or 0b0001XXXX (never indexing)
- parse_no_indexing!(str)
+ parse_no_indexing(str, pos)
end
end
- def read_integer!(str, prefix_length)
- first_byte = str.byteshift(1).uint8
- raise HPACKError.new("integer: end of buffer") unless first_byte
+ def read_integer(str, pos, prefix_length)
+ raise HPACKError.new("integer: end of buffer") if str.empty?
+ first_byte = str.uint8(pos)
mask = (1 << prefix_length) - 1
ret = first_byte & mask
- return ret if ret < mask
+ return [ret, 1] if ret != mask
octets = 0
- while next_value = str.byteshift(1).uint8
- ret += (next_value & 0b01111111) << (7 * octets)
+ while next_value = str.uint8(pos + octets + 1)
+ ret += (next_value % 0x80) << (7 * octets)
octets += 1
- if next_value < 128
- return ret
+ if next_value < 0x80
+ return [ret, 1 + octets]
elsif octets == 4 # RFC 7541 5.1 tells us that we MUST have limitation. at least > 2 ** 28
raise HPACKError.new("integer: too large integer")
end
@@ -54,29 +59,32 @@ module Plum
raise HPACKError.new("integer: end of buffer")
end
- def read_string!(str)
- first_byte = str.uint8
- raise HPACKError.new("string: end of buffer") unless first_byte
+ def read_string(str, pos)
+ raise HPACKError.new("string: end of buffer") if str.empty?
+ first_byte = str.uint8(pos)
- huffman = (first_byte >> 7) == 1
- length = read_integer!(str, 7)
- bin = str.byteshift(length)
+ huffman = first_byte > 0x80
+ length, ilen = read_integer(str, pos, 7)
+ raise HTTPError.new("string: end of buffer") if str.bytesize < length
- raise HTTPError.new("string: end of buffer") if bin.bytesize < length
- bin = Huffman.decode(bin) if huffman
- bin
+ bin = str.byteslice(pos + ilen, length)
+ if huffman
+ [Huffman.decode(bin), ilen + length]
+ else
+ [bin, ilen + length]
+ end
end
- def parse_indexed!(str)
+ def parse_indexed(str, pos)
# indexed
# +---+---+---+---+---+---+---+---+
# | 1 | Index (7+) |
# +---+---------------------------+
- index = read_integer!(str, 7)
- fetch(index)
+ index, succ = read_integer(str, pos, 7)
+ [fetch(index), succ]
end
- def parse_indexing!(str)
+ def parse_indexing(str, pos)
# +---+---+---+---+---+---+---+---+
# | 0 | 1 | Index (6+) |
# +---+---+-----------------------+
@@ -96,20 +104,21 @@ module Plum
# +---+---------------------------+
# | Value String (Length octets) |
# +-------------------------------+
- index = read_integer!(str, 6)
+ index, ilen = read_integer(str, pos, 6)
if index == 0
- name = read_string!(str)
+ name, nlen = read_string(str, pos + ilen)
else
name, = fetch(index)
+ nlen = 0
end
- val = read_string!(str)
+ val, vlen = read_string(str, pos + ilen + nlen)
store(name, val)
- [name, val]
+ [[name, val], ilen + nlen + vlen]
end
- def parse_no_indexing!(str)
+ def parse_no_indexing(str, pos)
# +---+---+---+---+---+---+---+---+
# | 0 | 0 | 0 |0,1| Index (4+) |
# +---+---+-----------------------+
@@ -129,16 +138,17 @@ module Plum
# +---+---------------------------+
# | Value String (Length octets) |
# +-------------------------------+
- index = read_integer!(str, 4)
+ index, ilen = read_integer(str, pos, 4)
if index == 0
- name = read_string!(str)
+ name, nlen = read_string(str, pos + ilen)
else
name, = fetch(index)
+ nlen = 0
end
- val = read_string!(str)
+ val, vlen = read_string(str, pos + ilen + nlen)
- [name, val]
+ [[name, val], ilen + nlen + vlen]
end
end
end