http-2-next 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HTTP2Next
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc "Generate Huffman precompiled table in huffman_statemachine.rb"
4
+ task :generate_table do
5
+ HuffmanTable::Node.generate_state_table
6
+ end
7
+
8
+ require_relative "../http/2/next/huffman"
9
+
10
+ # @private
11
+ module HuffmanTable
12
+ BITS_AT_ONCE = HTTP2Next::Header::Huffman::BITS_AT_ONCE
13
+ EOS = 256
14
+
15
+ class Node
16
+ attr_accessor :next, :emit, :final, :depth
17
+ attr_accessor :transitions
18
+ attr_accessor :id
19
+ @@id = 0 # rubocop:disable Style/ClassVars
20
+ def initialize(depth)
21
+ @next = [nil, nil]
22
+ @id = @@id
23
+ @@id += 1 # rubocop:disable Style/ClassVars
24
+ @final = false
25
+ @depth = depth
26
+ end
27
+
28
+ def add(code, len, chr)
29
+ self.final = true if chr == EOS && @depth <= 7
30
+ if len.zero?
31
+ @emit = chr
32
+ else
33
+ bit = (code & (1 << (len - 1))).zero? ? 0 : 1
34
+ node = @next[bit] ||= Node.new(@depth + 1)
35
+ node.add(code, len - 1, chr)
36
+ end
37
+ end
38
+
39
+ class Transition
40
+ attr_accessor :emit, :node
41
+ def initialize(emit, node)
42
+ @emit = emit
43
+ @node = node
44
+ end
45
+ end
46
+
47
+ def self.generate_tree
48
+ @root = new(0)
49
+ HTTP2Next::Header::Huffman::CODES.each_with_index do |c, chr|
50
+ code, len = c
51
+ @root.add(code, len, chr)
52
+ end
53
+ puts "#{@@id} nodes"
54
+ @root
55
+ end
56
+
57
+ def self.generate_machine
58
+ generate_tree
59
+ togo = Set[@root]
60
+ @states = Set[@root]
61
+
62
+ until togo.empty?
63
+ node = togo.first
64
+ togo.delete(node)
65
+
66
+ next if node.transitions
67
+
68
+ node.transitions = Array[1 << BITS_AT_ONCE]
69
+
70
+ (1 << BITS_AT_ONCE).times do |input|
71
+ n = node
72
+ emit = ""
73
+ (BITS_AT_ONCE - 1).downto(0) do |i|
74
+ bit = (input & (1 << i)).zero? ? 0 : 1
75
+ n = n.next[bit]
76
+ next unless n.emit
77
+
78
+ if n.emit == EOS
79
+ emit = EOS # cause error on decoding
80
+ else
81
+ emit << n.emit.chr(Encoding::BINARY) unless emit == EOS
82
+ end
83
+ n = @root
84
+ end
85
+ node.transitions[input] = Transition.new(emit, n)
86
+ togo << n
87
+ @states << n
88
+ end
89
+ end
90
+ puts "#{@states.size} states"
91
+ @root
92
+ end
93
+
94
+ def self.generate_state_table
95
+ generate_machine
96
+ state_id = {}
97
+ id_state = {}
98
+ state_id[@root] = 0
99
+ id_state[0] = @root
100
+ max_final = 0
101
+ id = 1
102
+ (@states - [@root]).sort_by { |s| s.final ? 0 : 1 }.each do |s|
103
+ state_id[s] = id
104
+ id_state[id] = s
105
+ max_final = id if s.final
106
+ id += 1
107
+ end
108
+
109
+ File.open(File.expand_path("../http/2/huffman_statemachine.rb", File.dirname(__FILE__)), "w") do |f|
110
+ f.print <<HEADER
111
+ # Machine generated Huffman decoder state machine.
112
+ # DO NOT EDIT THIS FILE.
113
+
114
+ # The following task generates this file.
115
+ # rake generate_huffman_table
116
+
117
+ module HTTP2Next
118
+ module Header
119
+ class Huffman
120
+ # :nodoc:
121
+ MAX_FINAL_STATE = #{max_final}
122
+ MACHINE = [
123
+ HEADER
124
+ id.times do |i|
125
+ n = id_state[i]
126
+ f.print " ["
127
+ string = (1 << BITS_AT_ONCE).times.map do |t|
128
+ transition = n.transitions.fetch(t)
129
+ emit = transition.emit
130
+ unless emit == EOS
131
+ bytes = emit.bytes
132
+ raise ArgumentError if bytes.size > 1
133
+
134
+ emit = bytes.first
135
+ end
136
+ "[#{emit.inspect}, #{state_id.fetch(transition.node)}]"
137
+ end.join(", ")
138
+ f.print(string)
139
+ f.print "],\n"
140
+ end
141
+ f.print <<TAILER
142
+ ].each { |arr| arr.each { |subarr| subarr.each(&:freeze) }.freeze }.freeze
143
+ end
144
+ end
145
+ end
146
+ TAILER
147
+ end
148
+ end
149
+
150
+ class << self
151
+ attr_reader :root
152
+ end
153
+
154
+ # Test decoder
155
+ def self.decode(input)
156
+ emit = ""
157
+ n = root
158
+ nibbles = input.unpack("C*").flat_map { |b| [((b & 0xf0) >> 4), b & 0xf] }
159
+ until nibbles.empty?
160
+ nb = nibbles.shift
161
+ t = n.transitions[nb]
162
+ emit << t.emit
163
+ n = t.node
164
+ end
165
+ puts "len = #{emit.size} n.final = #{n.final} nibbles = #{nibbles}" unless n.final && nibbles.all? { |x| x == 0xf }
166
+ emit
167
+ end
168
+ end
169
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http-2-next
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tiago Cardoso
8
+ - Ilya Grigorik
9
+ - Kaoru Maeda
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2019-11-13 00:00:00.000000000 Z
14
+ dependencies: []
15
+ description: Pure-ruby HTTP 2.0 protocol implementation
16
+ email:
17
+ - cardoso_tiago@hotmail.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - README.md
23
+ - lib/http/2/next.rb
24
+ - lib/http/2/next/buffer.rb
25
+ - lib/http/2/next/client.rb
26
+ - lib/http/2/next/compressor.rb
27
+ - lib/http/2/next/connection.rb
28
+ - lib/http/2/next/emitter.rb
29
+ - lib/http/2/next/error.rb
30
+ - lib/http/2/next/flow_buffer.rb
31
+ - lib/http/2/next/framer.rb
32
+ - lib/http/2/next/huffman.rb
33
+ - lib/http/2/next/huffman_statemachine.rb
34
+ - lib/http/2/next/server.rb
35
+ - lib/http/2/next/stream.rb
36
+ - lib/http/2/next/version.rb
37
+ - lib/tasks/generate_huffman_table.rb
38
+ homepage: https://gitlab.com/honeyryderchuck/http-2-next
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.1.0
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.0.6
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Pure-ruby HTTP 2.0 protocol implementation
61
+ test_files: []