requests_ruby 1.0.2 → 1.0.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +70 -1
- data/README.md +157 -8
- data/lib/requests/adapters.rb +116 -22
- data/lib/requests/api.rb +10 -5
- data/lib/requests/cookies.rb +92 -19
- data/lib/requests/hpack.rb +241 -0
- data/lib/requests/http2.rb +469 -0
- data/lib/requests/sessions.rb +75 -19
- data/lib/requests/utils.rb +18 -0
- data/lib/requests/version.rb +1 -1
- data/lib/requests.rb +2 -0
- metadata +10 -4
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Requests
|
|
4
|
+
module HPACK
|
|
5
|
+
STATIC_TABLE = [
|
|
6
|
+
[':authority', ''],[':method', 'GET'],[':method', 'POST'],[':path', '/'],
|
|
7
|
+
[':path', '/index.html'],[':scheme', 'http'],[':scheme', 'https'],[':status', '200'],
|
|
8
|
+
[':status', '204'],[':status', '206'],[':status', '304'],[':status', '400'],
|
|
9
|
+
[':status', '404'],[':status', '500'],['accept-charset', ''],['accept-encoding', 'gzip, deflate'],
|
|
10
|
+
['accept-language', ''],['accept-ranges', ''],['accept', ''],['access-control-allow-origin', ''],
|
|
11
|
+
['age', ''],['allow', ''],['authorization', ''],['cache-control', ''],
|
|
12
|
+
['content-disposition', ''],['content-encoding', ''],['content-language', ''],['content-length', ''],
|
|
13
|
+
['content-location', ''],['content-range', ''],['content-type', ''],['cookie', ''],
|
|
14
|
+
['date', ''],['etag', ''],['expect', ''],['expires', ''],
|
|
15
|
+
['from', ''],['host', ''],['if-match', ''],['if-modified-since', ''],
|
|
16
|
+
['if-none-match', ''],['if-range', ''],['if-unmodified-since', ''],['last-modified', ''],
|
|
17
|
+
['link', ''],['location', ''],['max-forwards', ''],['proxy-authenticate', ''],
|
|
18
|
+
['proxy-authorization', ''],['range', ''],['referer', ''],['refresh', ''],
|
|
19
|
+
['retry-after', ''],['server', ''],['set-cookie', ''],['strict-transport-security', ''],
|
|
20
|
+
['transfer-encoding', ''],['user-agent', ''],['vary', ''],['via', ''],
|
|
21
|
+
['www-authenticate', '']
|
|
22
|
+
].freeze
|
|
23
|
+
|
|
24
|
+
module Huffman
|
|
25
|
+
CODES = [
|
|
26
|
+
[0x1ff8, 13],[0x7fffd8, 23],[0xfffffe2, 28],[0xfffffe3, 28],[0xfffffe4, 28],[0xfffffe5, 28],
|
|
27
|
+
[0xfffffe6, 28],[0xfffffe7, 28],[0xfffffe8, 28],[0xffffea, 24],[0x3ffffffc, 30],[0xfffffe9, 28],
|
|
28
|
+
[0xfffffea, 28],[0x3ffffffd, 30],[0xfffffeb, 28],[0xfffffec, 28],[0xfffffed, 28],[0xfffffee, 28],
|
|
29
|
+
[0xfffffef, 28],[0xffffff0, 28],[0xffffff1, 28],[0xffffff2, 28],[0x3ffffffe, 30],[0xffffff3, 28],
|
|
30
|
+
[0xffffff4, 28],[0xffffff5, 28],[0xffffff6, 28],[0xffffff7, 28],[0xffffff8, 28],[0xffffff9, 28],
|
|
31
|
+
[0xffffffa, 28],[0xffffffb, 28],[0x14, 6],[0x3f8, 10],[0x3f9, 10],[0xffa, 12],
|
|
32
|
+
[0x1ff9, 13],[0x15, 6],[0xf8, 8],[0x7fa, 11],[0x3fa, 10],[0x3fb, 10],
|
|
33
|
+
[0xf9, 8],[0x7fb, 11],[0xfa, 8],[0x16, 6],[0x17, 6],[0x18, 6],
|
|
34
|
+
[0x0, 5],[0x1, 5],[0x2, 5],[0x19, 6],[0x1a, 6],[0x1b, 6],
|
|
35
|
+
[0x1c, 6],[0x1d, 6],[0x1e, 6],[0x1f, 6],[0x5c, 7],[0xfb, 8],
|
|
36
|
+
[0x7ffc, 15],[0x20, 6],[0xffb, 12],[0x3fc, 10],[0x1ffa, 13],[0x21, 6],
|
|
37
|
+
[0x5d, 7],[0x5e, 7],[0x5f, 7],[0x60, 7],[0x61, 7],[0x62, 7],
|
|
38
|
+
[0x63, 7],[0x64, 7],[0x65, 7],[0x66, 7],[0x67, 7],[0x68, 7],
|
|
39
|
+
[0x69, 7],[0x6a, 7],[0x6b, 7],[0x6c, 7],[0x6d, 7],[0x6e, 7],
|
|
40
|
+
[0x6f, 7],[0x70, 7],[0x71, 7],[0x72, 7],[0xfc, 8],[0x73, 7],
|
|
41
|
+
[0xfd, 8],[0x1ffb, 13],[0x7fff0, 19],[0x1ffc, 13],[0x3ffc, 14],[0x22, 6],
|
|
42
|
+
[0x7ffd, 15],[0x3, 5],[0x23, 6],[0x4, 5],[0x24, 6],[0x5, 5],
|
|
43
|
+
[0x25, 6],[0x26, 6],[0x27, 6],[0x6, 5],[0x74, 7],[0x75, 7],
|
|
44
|
+
[0x28, 6],[0x29, 6],[0x2a, 6],[0x7, 5],[0x2b, 6],[0x76, 7],
|
|
45
|
+
[0x2c, 6],[0x8, 5],[0x9, 5],[0x2d, 6],[0x77, 7],[0x78, 7],
|
|
46
|
+
[0x79, 7],[0x7a, 7],[0x7b, 7],[0x7ffe, 15],[0x7fc, 11],[0x3ffd, 14],
|
|
47
|
+
[0x1ffd, 13],[0xffffffc, 28],[0xfffe6, 20],[0x3fffd2, 22],[0xfffe7, 20],[0xfffe8, 20],
|
|
48
|
+
[0x3fffd3, 22],[0x3fffd4, 22],[0x3fffd5, 22],[0x7fffd9, 23],[0x3fffd6, 22],[0x7fffda, 23],
|
|
49
|
+
[0x7fffdb, 23],[0x7fffdc, 23],[0x7fffdd, 23],[0x7fffde, 23],[0xffffeb, 24],[0x7fffdf, 23],
|
|
50
|
+
[0xffffec, 24],[0xffffed, 24],[0x3fffd7, 22],[0x7fffe0, 23],[0xffffee, 24],[0x7fffe1, 23],
|
|
51
|
+
[0x7fffe2, 23],[0x7fffe3, 23],[0x7fffe4, 23],[0x1fffdc, 21],[0x3fffd8, 22],[0x7fffe5, 23],
|
|
52
|
+
[0x3fffd9, 22],[0x7fffe6, 23],[0x7fffe7, 23],[0xffffef, 24],[0x3fffda, 22],[0x1fffdd, 21],
|
|
53
|
+
[0xfffe9, 20],[0x3fffdb, 22],[0x3fffdc, 22],[0x7fffe8, 23],[0x7fffe9, 23],[0x1fffde, 21],
|
|
54
|
+
[0x7fffea, 23],[0x3fffdd, 22],[0x3fffde, 22],[0xfffff0, 24],[0x1fffdf, 21],[0x3fffdf, 22],
|
|
55
|
+
[0x7fffeb, 23],[0x7fffec, 23],[0x1fffe0, 21],[0x1fffe1, 21],[0x3fffe0, 22],[0x1fffe2, 21],
|
|
56
|
+
[0x7fffed, 23],[0x3fffe1, 22],[0x7fffee, 23],[0x7fffef, 23],[0xfffea, 20],[0x3fffe2, 22],
|
|
57
|
+
[0x3fffe3, 22],[0x3fffe4, 22],[0x7ffff0, 23],[0x3fffe5, 22],[0x3fffe6, 22],[0x7ffff1, 23],
|
|
58
|
+
[0x3ffffe0, 26],[0x3ffffe1, 26],[0xfffeb, 20],[0x7fff1, 19],[0x3fffe7, 22],[0x7ffff2, 23],
|
|
59
|
+
[0x3fffe8, 22],[0x1ffffec, 25],[0x3ffffe2, 26],[0x3ffffe3, 26],[0x3ffffe4, 26],[0x7ffffde, 27],
|
|
60
|
+
[0x7ffffdf, 27],[0x3ffffe5, 26],[0xfffff1, 24],[0x1ffffed, 25],[0x7fff2, 19],[0x1fffe3, 21],
|
|
61
|
+
[0x3ffffe6, 26],[0x7ffffe0, 27],[0x7ffffe1, 27],[0x3ffffe7, 26],[0x7ffffe2, 27],[0xfffff2, 24],
|
|
62
|
+
[0x1fffe4, 21],[0x1fffe5, 21],[0x3ffffe8, 26],[0x3ffffe9, 26],[0xffffffd, 28],[0x7ffffe3, 27],
|
|
63
|
+
[0x7ffffe4, 27],[0x7ffffe5, 27],[0xfffec, 20],[0xfffff3, 24],[0xfffed, 20],[0x1fffe6, 21],
|
|
64
|
+
[0x3fffe9, 22],[0x1fffe7, 21],[0x1fffe8, 21],[0x7ffff3, 23],[0x3fffea, 22],[0x3fffeb, 22],
|
|
65
|
+
[0x1ffffee, 25],[0x1ffffef, 25],[0xfffff4, 24],[0xfffff5, 24],[0x3ffffea, 26],[0x7ffff4, 23],
|
|
66
|
+
[0x3ffffeb, 26],[0x7ffffe6, 27],[0x3ffffec, 26],[0x3ffffed, 26],[0x7ffffe7, 27],[0x7ffffe8, 27],
|
|
67
|
+
[0x7ffffe9, 27],[0x7ffffea, 27],[0x7ffffeb, 27],[0xffffffe, 28],[0x7ffffec, 27],[0x7ffffed, 27],
|
|
68
|
+
[0x7ffffee, 27],[0x7ffffef, 27],[0x7fffff0, 27],[0x3ffffee, 26],[0x3fffffff, 30]
|
|
69
|
+
].freeze
|
|
70
|
+
EOS = 256
|
|
71
|
+
ENCODE_TABLE = CODES.map { |c, l| [c].pack('N').unpack1('B*')[-l..-1] }.freeze
|
|
72
|
+
def self.build_tree
|
|
73
|
+
root = {}
|
|
74
|
+
CODES.each_with_index do |(code, len), sym|
|
|
75
|
+
node = root
|
|
76
|
+
(len - 1).downto(0) do |i|
|
|
77
|
+
bit = (code >> i) & 1
|
|
78
|
+
node = (node[bit] ||= {})
|
|
79
|
+
end
|
|
80
|
+
node[:sym] = sym
|
|
81
|
+
end
|
|
82
|
+
root
|
|
83
|
+
end
|
|
84
|
+
DECODE_TREE = build_tree
|
|
85
|
+
def self.encode(str)
|
|
86
|
+
bits = String.new
|
|
87
|
+
str.each_byte { |b| bits << ENCODE_TABLE[b] }
|
|
88
|
+
pad = (8 - bits.size % 8) % 8
|
|
89
|
+
bits << ('1' * pad) if pad > 0
|
|
90
|
+
[bits].pack('B*')
|
|
91
|
+
end
|
|
92
|
+
def self.decode(bytes)
|
|
93
|
+
out = String.new(encoding: Encoding::BINARY)
|
|
94
|
+
node = DECODE_TREE
|
|
95
|
+
bitcount = bytes.bytesize * 8
|
|
96
|
+
pos = 0
|
|
97
|
+
bytes.each_byte do |byte|
|
|
98
|
+
7.downto(0) do |i|
|
|
99
|
+
pos += 1
|
|
100
|
+
bit = (byte >> i) & 1
|
|
101
|
+
nxt = node[bit]
|
|
102
|
+
unless nxt
|
|
103
|
+
raise Requests::ContentDecodingError, 'invalid huffman padding' if pos > bitcount - 8 || pos < bitcount
|
|
104
|
+
return out
|
|
105
|
+
end
|
|
106
|
+
node = nxt
|
|
107
|
+
if node.key?(:sym)
|
|
108
|
+
sym = node[:sym]
|
|
109
|
+
raise Requests::ContentDecodingError, 'unexpected huffman EOS' if sym == EOS
|
|
110
|
+
out << sym.chr(Encoding::BINARY)
|
|
111
|
+
node = DECODE_TREE
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
out
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
module Integer
|
|
120
|
+
module_function
|
|
121
|
+
def encode(value, prefix_bits, first_byte = 0)
|
|
122
|
+
max = (1 << prefix_bits) - 1
|
|
123
|
+
if value < max
|
|
124
|
+
[first_byte | value].pack('C')
|
|
125
|
+
else
|
|
126
|
+
out = [first_byte | max].pack('C')
|
|
127
|
+
value -= max
|
|
128
|
+
while value >= 128
|
|
129
|
+
out << [(value % 128) | 128].pack('C')
|
|
130
|
+
value /= 128
|
|
131
|
+
end
|
|
132
|
+
out << [value].pack('C')
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
def decode(bytes, pos, prefix_bits)
|
|
136
|
+
max = (1 << prefix_bits) - 1
|
|
137
|
+
value = bytes.getbyte(pos) & max
|
|
138
|
+
pos += 1
|
|
139
|
+
if value == max
|
|
140
|
+
m = 0
|
|
141
|
+
loop do
|
|
142
|
+
b = bytes.getbyte(pos)
|
|
143
|
+
raise Requests::ContentDecodingError, 'truncated hpack integer' if b.nil?
|
|
144
|
+
pos += 1
|
|
145
|
+
value += (b & 127) * (2**m)
|
|
146
|
+
m += 7
|
|
147
|
+
break if b & 128 == 0
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
[value, pos]
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
class Encoder
|
|
155
|
+
def encode(headers)
|
|
156
|
+
out = String.new(encoding: Encoding::BINARY)
|
|
157
|
+
headers.each { |name, value| out << encode_field(name.to_s.downcase, value.to_s) }
|
|
158
|
+
out
|
|
159
|
+
end
|
|
160
|
+
private
|
|
161
|
+
def encode_field(name, value)
|
|
162
|
+
exact = STATIC_TABLE.index { |n, v| n == name && v == value }
|
|
163
|
+
return Integer.encode(exact + 1, 7, 0x80) if exact
|
|
164
|
+
name_idx = STATIC_TABLE.index { |n, _| n == name }
|
|
165
|
+
head = name_idx ? Integer.encode(name_idx + 1, 4, 0x00) : Integer.encode(0, 4, 0x00) + literal(name)
|
|
166
|
+
head + literal(value)
|
|
167
|
+
end
|
|
168
|
+
def literal(str)
|
|
169
|
+
h = Huffman.encode(str)
|
|
170
|
+
if h.bytesize < str.bytesize
|
|
171
|
+
Integer.encode(h.bytesize, 7, 0x80) + h
|
|
172
|
+
else
|
|
173
|
+
Integer.encode(str.bytesize, 7, 0x00) + str.dup.force_encoding(Encoding::BINARY)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
class Decoder
|
|
179
|
+
def initialize(max_size: 4096)
|
|
180
|
+
@dynamic = []
|
|
181
|
+
@max_size = max_size
|
|
182
|
+
@size = 0
|
|
183
|
+
end
|
|
184
|
+
def decode(bytes)
|
|
185
|
+
pos = 0
|
|
186
|
+
out = []
|
|
187
|
+
while pos < bytes.bytesize
|
|
188
|
+
byte = bytes.getbyte(pos)
|
|
189
|
+
if byte & 0x80 != 0
|
|
190
|
+
idx, pos = Integer.decode(bytes, pos, 7)
|
|
191
|
+
out << lookup(idx)
|
|
192
|
+
elsif byte & 0x40 != 0
|
|
193
|
+
name, value, pos = read_literal(bytes, pos, 6)
|
|
194
|
+
add_dynamic(name, value)
|
|
195
|
+
out << [name, value]
|
|
196
|
+
elsif byte & 0x20 != 0
|
|
197
|
+
size, pos = Integer.decode(bytes, pos, 5)
|
|
198
|
+
@max_size = size
|
|
199
|
+
evict
|
|
200
|
+
else
|
|
201
|
+
name, value, pos = read_literal(bytes, pos, 4)
|
|
202
|
+
out << [name, value]
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
out
|
|
206
|
+
end
|
|
207
|
+
private
|
|
208
|
+
def lookup(idx)
|
|
209
|
+
return STATIC_TABLE[idx - 1] if idx <= STATIC_TABLE.size
|
|
210
|
+
d = @dynamic[idx - STATIC_TABLE.size - 1]
|
|
211
|
+
raise Requests::ContentDecodingError, "invalid hpack index #{idx}" unless d
|
|
212
|
+
d
|
|
213
|
+
end
|
|
214
|
+
def read_literal(bytes, pos, prefix_bits)
|
|
215
|
+
idx, pos = Integer.decode(bytes, pos, prefix_bits)
|
|
216
|
+
name, pos = idx.zero? ? read_string(bytes, pos) : [lookup(idx)[0], pos]
|
|
217
|
+
value, pos = read_string(bytes, pos)
|
|
218
|
+
[name, value, pos]
|
|
219
|
+
end
|
|
220
|
+
def read_string(bytes, pos)
|
|
221
|
+
huff = bytes.getbyte(pos) & 0x80 != 0
|
|
222
|
+
len, pos = Integer.decode(bytes, pos, 7)
|
|
223
|
+
raw = bytes.byteslice(pos, len)
|
|
224
|
+
pos += len
|
|
225
|
+
[huff ? Huffman.decode(raw) : raw, pos]
|
|
226
|
+
end
|
|
227
|
+
def add_dynamic(name, value)
|
|
228
|
+
entry_size = name.bytesize + value.bytesize + 32
|
|
229
|
+
@dynamic.unshift([name, value])
|
|
230
|
+
@size += entry_size
|
|
231
|
+
evict
|
|
232
|
+
end
|
|
233
|
+
def evict
|
|
234
|
+
while @size > @max_size && !@dynamic.empty?
|
|
235
|
+
name, value = @dynamic.pop
|
|
236
|
+
@size -= name.bytesize + value.bytesize + 32
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|