httpx 0.24.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +0 -48
- data/README.md +4 -13
- data/doc/release_notes/0_24_4.md +3 -3
- data/doc/release_notes/0_24_6.md +5 -0
- data/doc/release_notes/1_0_0.md +60 -0
- data/lib/httpx/adapters/datadog.rb +28 -97
- data/lib/httpx/adapters/faraday.rb +9 -52
- data/lib/httpx/adapters/webmock.rb +2 -7
- data/lib/httpx/altsvc.rb +4 -22
- data/lib/httpx/base64.rb +27 -0
- data/lib/httpx/chainable.rb +2 -25
- data/lib/httpx/connection.rb +11 -32
- data/lib/httpx/domain_name.rb +5 -12
- data/lib/httpx/errors.rb +0 -2
- data/lib/httpx/extensions.rb +0 -124
- data/lib/httpx/io/ssl.rb +26 -59
- data/lib/httpx/io/tcp.rb +27 -68
- data/lib/httpx/io/udp.rb +13 -48
- data/lib/httpx/io/unix.rb +1 -8
- data/lib/httpx/loggable.rb +4 -19
- data/lib/httpx/options.rb +24 -84
- data/lib/httpx/plugins/{authentication → auth}/basic.rb +1 -5
- data/lib/httpx/plugins/{authentication → auth}/digest.rb +2 -5
- data/lib/httpx/plugins/{authentication → auth}/ntlm.rb +1 -3
- data/lib/httpx/plugins/{authentication → auth}/socks5.rb +0 -2
- data/lib/httpx/plugins/auth.rb +25 -0
- data/lib/httpx/plugins/aws_sigv4.rb +0 -1
- data/lib/httpx/plugins/{basic_authentication.rb → basic_auth.rb} +5 -6
- data/lib/httpx/plugins/brotli.rb +50 -0
- data/lib/httpx/plugins/circuit_breaker/circuit.rb +40 -16
- data/lib/httpx/plugins/circuit_breaker/circuit_store.rb +16 -5
- data/lib/httpx/plugins/circuit_breaker.rb +11 -4
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +0 -2
- data/lib/httpx/plugins/cookies.rb +1 -1
- data/lib/httpx/plugins/{digest_authentication.rb → digest_auth.rb} +5 -5
- data/lib/httpx/plugins/follow_redirects.rb +21 -24
- data/lib/httpx/plugins/grpc/grpc_encoding.rb +82 -0
- data/lib/httpx/plugins/grpc/message.rb +7 -39
- data/lib/httpx/plugins/grpc.rb +15 -21
- data/lib/httpx/plugins/h2c.rb +0 -1
- data/lib/httpx/plugins/{ntlm_authentication.rb → ntlm_auth.rb} +5 -5
- data/lib/httpx/plugins/oauth.rb +2 -2
- data/lib/httpx/plugins/proxy/http.rb +0 -2
- data/lib/httpx/plugins/proxy/socks4.rb +0 -4
- data/lib/httpx/plugins/proxy/socks5.rb +1 -5
- data/lib/httpx/plugins/proxy.rb +3 -32
- data/lib/httpx/plugins/retries.rb +3 -4
- data/lib/httpx/plugins/stream.rb +4 -6
- data/lib/httpx/punycode.rb +9 -291
- data/lib/httpx/request/body.rb +145 -0
- data/lib/httpx/request.rb +2 -119
- data/lib/httpx/resolver/https.rb +1 -1
- data/lib/httpx/resolver/native.rb +6 -14
- data/lib/httpx/resolver/resolver.rb +1 -1
- data/lib/httpx/resolver/system.rb +11 -9
- data/lib/httpx/response/body.rb +206 -0
- data/lib/httpx/response/buffer.rb +90 -0
- data/lib/httpx/response.rb +5 -208
- data/lib/httpx/selector.rb +0 -2
- data/lib/httpx/session.rb +3 -10
- data/lib/httpx/transcoder/body.rb +0 -1
- data/lib/httpx/transcoder/deflate.rb +37 -0
- data/lib/httpx/transcoder/form.rb +52 -32
- data/lib/httpx/transcoder/gzip.rb +74 -0
- data/lib/httpx/transcoder/json.rb +2 -4
- data/lib/httpx/transcoder/multipart/decoder.rb +139 -0
- data/lib/httpx/{plugins → transcoder}/multipart/encoder.rb +3 -3
- data/lib/httpx/{plugins → transcoder}/multipart/mime_type_detector.rb +1 -1
- data/lib/httpx/{plugins → transcoder}/multipart/part.rb +3 -2
- data/lib/httpx/transcoder/multipart.rb +17 -0
- data/lib/httpx/transcoder/utils/body_reader.rb +46 -0
- data/lib/httpx/transcoder/utils/deflater.rb +72 -0
- data/lib/httpx/transcoder/xml.rb +0 -2
- data/lib/httpx/transcoder.rb +2 -2
- data/lib/httpx/utils.rb +10 -20
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +0 -8
- data/sig/chainable.rbs +5 -6
- data/sig/connection.rbs +0 -1
- data/sig/errors.rbs +0 -3
- data/sig/httpx.rbs +2 -1
- data/sig/io/unix.rbs +1 -1
- data/sig/options.rbs +12 -8
- data/sig/plugins/{authentication → auth}/basic.rbs +0 -2
- data/sig/plugins/auth.rbs +13 -0
- data/sig/plugins/{basic_authentication.rbs → basic_auth.rbs} +2 -2
- data/sig/plugins/brotli.rbs +22 -0
- data/sig/plugins/circuit_breaker.rbs +7 -3
- data/sig/plugins/compression.rbs +0 -2
- data/sig/plugins/{digest_authentication.rbs → digest_auth.rbs} +2 -2
- data/sig/plugins/follow_redirects.rbs +0 -1
- data/sig/plugins/grpc/call.rbs +19 -0
- data/sig/plugins/grpc/grpc_encoding.rbs +33 -0
- data/sig/plugins/grpc/message.rbs +17 -0
- data/sig/plugins/grpc.rbs +2 -32
- data/sig/plugins/{ntlm_authentication.rbs → ntlm_auth.rbs} +2 -2
- data/sig/plugins/oauth.rbs +1 -1
- data/sig/plugins/proxy/socks4.rbs +2 -3
- data/sig/plugins/proxy/socks5.rbs +0 -1
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/response_cache.rbs +5 -2
- data/sig/request/body.rbs +42 -0
- data/sig/request.rbs +1 -27
- data/sig/resolver/resolver.rbs +1 -1
- data/sig/response/body.rbs +52 -0
- data/sig/response/buffer.rbs +24 -0
- data/sig/response.rbs +0 -39
- data/sig/session.rbs +2 -0
- data/sig/transcoder/body.rbs +4 -3
- data/sig/transcoder/deflate.rbs +11 -0
- data/sig/transcoder/form.rbs +5 -3
- data/sig/transcoder/gzip.rbs +24 -0
- data/sig/transcoder/json.rbs +4 -2
- data/sig/{plugins → transcoder}/multipart.rbs +3 -10
- data/sig/transcoder/utils/body_reader.rbs +15 -0
- data/sig/transcoder/utils/deflater.rbs +29 -0
- data/sig/transcoder.rbs +18 -2
- metadata +52 -34
- data/lib/httpx/plugins/authentication.rb +0 -24
- data/lib/httpx/plugins/compression/brotli.rb +0 -54
- data/lib/httpx/plugins/compression/deflate.rb +0 -54
- data/lib/httpx/plugins/compression/gzip.rb +0 -90
- data/lib/httpx/plugins/compression.rb +0 -165
- data/lib/httpx/plugins/multipart/decoder.rb +0 -137
- data/lib/httpx/plugins/multipart.rb +0 -96
- data/sig/plugins/authentication.rbs +0 -13
- data/sig/plugins/compression/brotli.rbs +0 -21
- data/sig/plugins/compression/deflate.rbs +0 -17
- data/sig/plugins/compression/gzip.rbs +0 -29
- /data/sig/plugins/{authentication → auth}/digest.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/ntlm.rbs +0 -0
- /data/sig/plugins/{authentication → auth}/socks5.rbs +0 -0
data/lib/httpx/punycode.rb
CHANGED
@@ -1,304 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module HTTPX
|
4
|
-
|
5
|
-
|
4
|
+
module Punycode
|
5
|
+
module_function
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
begin
|
8
|
+
require "idnx"
|
9
9
|
|
10
10
|
def encode_hostname(hostname)
|
11
11
|
Idnx.to_punycode(hostname)
|
12
12
|
end
|
13
|
-
|
14
|
-
|
15
|
-
rescue LoadError
|
16
|
-
# :nocov:
|
17
|
-
# -*- coding: utf-8 -*-
|
18
|
-
#--
|
19
|
-
# punycode.rb - PunyCode encoder for the Domain Name library
|
20
|
-
#
|
21
|
-
# Copyright (C) 2011-2017 Akinori MUSHA, All rights reserved.
|
22
|
-
#
|
23
|
-
# Ported from puny.c, a part of VeriSign XCode (encode/decode) IDN
|
24
|
-
# Library.
|
25
|
-
#
|
26
|
-
# Copyright (C) 2000-2002 Verisign Inc., All rights reserved.
|
27
|
-
#
|
28
|
-
# Redistribution and use in source and binary forms, with or
|
29
|
-
# without modification, are permitted provided that the following
|
30
|
-
# conditions are met:
|
31
|
-
#
|
32
|
-
# 1) Redistributions of source code must retain the above copyright
|
33
|
-
# notice, this list of conditions and the following disclaimer.
|
34
|
-
#
|
35
|
-
# 2) Redistributions in binary form must reproduce the above copyright
|
36
|
-
# notice, this list of conditions and the following disclaimer in
|
37
|
-
# the documentation and/or other materials provided with the
|
38
|
-
# distribution.
|
39
|
-
#
|
40
|
-
# 3) Neither the name of the VeriSign Inc. nor the names of its
|
41
|
-
# contributors may be used to endorse or promote products derived
|
42
|
-
# from this software without specific prior written permission.
|
43
|
-
#
|
44
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
45
|
-
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
46
|
-
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
47
|
-
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
48
|
-
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
49
|
-
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
50
|
-
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
51
|
-
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
52
|
-
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
53
|
-
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
54
|
-
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
55
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
56
|
-
#
|
57
|
-
# This software is licensed under the BSD open source license. For more
|
58
|
-
# information visit www.opensource.org.
|
59
|
-
#
|
60
|
-
# Authors:
|
61
|
-
# John Colosi (VeriSign)
|
62
|
-
# Srikanth Veeramachaneni (VeriSign)
|
63
|
-
# Nagesh Chigurupati (Verisign)
|
64
|
-
# Praveen Srinivasan(Verisign)
|
65
|
-
#++
|
66
|
-
module Punycode
|
67
|
-
BASE = 36
|
68
|
-
TMIN = 1
|
69
|
-
TMAX = 26
|
70
|
-
SKEW = 38
|
71
|
-
DAMP = 700
|
72
|
-
INITIAL_BIAS = 72
|
73
|
-
INITIAL_N = 0x80
|
74
|
-
DELIMITER = "-"
|
75
|
-
|
76
|
-
MAXINT = (1 << 32) - 1
|
77
|
-
|
78
|
-
LOBASE = BASE - TMIN
|
79
|
-
CUTOFF = LOBASE * TMAX / 2
|
80
|
-
|
81
|
-
RE_NONBASIC = /[^\x00-\x7f]/.freeze
|
82
|
-
|
83
|
-
# Returns the numeric value of a basic code point (for use in
|
84
|
-
# representing integers) in the range 0 to base-1, or nil if cp
|
85
|
-
# is does not represent a value.
|
86
|
-
DECODE_DIGIT = {}.tap do |map|
|
87
|
-
# ASCII A..Z map to 0..25
|
88
|
-
# ASCII a..z map to 0..25
|
89
|
-
(0..25).each { |i| map[65 + i] = map[97 + i] = i }
|
90
|
-
# ASCII 0..9 map to 26..35
|
91
|
-
(26..35).each { |i| map[22 + i] = i }
|
92
|
-
end
|
93
|
-
|
94
|
-
# Returns the basic code point whose value (when used for
|
95
|
-
# representing integers) is d, which must be in the range 0 to
|
96
|
-
# BASE-1. The lowercase form is used unless flag is true, in
|
97
|
-
# which case the uppercase form is used. The behavior is
|
98
|
-
# undefined if flag is nonzero and digit d has no uppercase
|
99
|
-
# form.
|
100
|
-
ENCODE_DIGIT = proc { |d, flag|
|
101
|
-
(d + 22 + (d < 26 ? 75 : 0) - (flag ? (1 << 5) : 0)).chr
|
102
|
-
# 0..25 map to ASCII a..z or A..Z
|
103
|
-
# 26..35 map to ASCII 0..9
|
104
|
-
}
|
105
|
-
|
106
|
-
DOT = "."
|
107
|
-
PREFIX = "xn--"
|
108
|
-
|
109
|
-
# Most errors we raise are basically kind of ArgumentError.
|
110
|
-
class ArgumentError < ::ArgumentError; end
|
111
|
-
class BufferOverflowError < ArgumentError; end
|
112
|
-
|
113
|
-
module_function
|
114
|
-
|
115
|
-
# Encode a +string+ in Punycode
|
116
|
-
def encode(string)
|
117
|
-
input = string.unpack("U*")
|
118
|
-
output = +""
|
119
|
-
|
120
|
-
# Initialize the state
|
121
|
-
n = INITIAL_N
|
122
|
-
delta = 0
|
123
|
-
bias = INITIAL_BIAS
|
124
|
-
|
125
|
-
# Handle the basic code points
|
126
|
-
input.each { |cp| output << cp.chr if cp < 0x80 }
|
127
|
-
|
128
|
-
h = b = output.length
|
129
|
-
|
130
|
-
# h is the number of code points that have been handled, b is the
|
131
|
-
# number of basic code points, and out is the number of characters
|
132
|
-
# that have been output.
|
133
|
-
|
134
|
-
output << DELIMITER if b > 0
|
135
|
-
|
136
|
-
# Main encoding loop
|
137
|
-
|
138
|
-
while h < input.length
|
139
|
-
# All non-basic code points < n have been handled already. Find
|
140
|
-
# the next larger one
|
141
|
-
|
142
|
-
m = MAXINT
|
143
|
-
input.each do |cp|
|
144
|
-
m = cp if (n...m) === cp
|
145
|
-
end
|
146
|
-
|
147
|
-
# Increase delta enough to advance the decoder's <n,i> state to
|
148
|
-
# <m,0>, but guard against overflow
|
149
|
-
|
150
|
-
delta += (m - n) * (h + 1)
|
151
|
-
raise BufferOverflowError if delta > MAXINT
|
152
|
-
|
153
|
-
n = m
|
154
|
-
|
155
|
-
input.each do |cp|
|
156
|
-
# AMC-ACE-Z can use this simplified version instead
|
157
|
-
if cp < n
|
158
|
-
delta += 1
|
159
|
-
raise BufferOverflowError if delta > MAXINT
|
160
|
-
elsif cp == n
|
161
|
-
# Represent delta as a generalized variable-length integer
|
162
|
-
q = delta
|
163
|
-
k = BASE
|
164
|
-
loop do
|
165
|
-
t = k <= bias ? TMIN : k - bias >= TMAX ? TMAX : k - bias
|
166
|
-
break if q < t
|
167
|
-
|
168
|
-
q, r = (q - t).divmod(BASE - t)
|
169
|
-
output << ENCODE_DIGIT[t + r, false]
|
170
|
-
k += BASE
|
171
|
-
end
|
172
|
-
|
173
|
-
output << ENCODE_DIGIT[q, false]
|
174
|
-
|
175
|
-
# Adapt the bias
|
176
|
-
delta = h == b ? delta / DAMP : delta >> 1
|
177
|
-
delta += delta / (h + 1)
|
178
|
-
bias = 0
|
179
|
-
while delta > CUTOFF
|
180
|
-
delta /= LOBASE
|
181
|
-
bias += BASE
|
182
|
-
end
|
183
|
-
bias += (LOBASE + 1) * delta / (delta + SKEW)
|
184
|
-
|
185
|
-
delta = 0
|
186
|
-
h += 1
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
delta += 1
|
191
|
-
n += 1
|
192
|
-
end
|
193
|
-
|
194
|
-
output
|
195
|
-
end
|
196
|
-
|
197
|
-
# Encode a hostname using IDN/Punycode algorithms
|
13
|
+
rescue LoadError
|
198
14
|
def encode_hostname(hostname)
|
199
|
-
hostname.
|
200
|
-
|
201
|
-
hostname.split(DOT).map do |name|
|
202
|
-
if name.match(RE_NONBASIC)
|
203
|
-
PREFIX + encode(name)
|
204
|
-
else
|
205
|
-
name
|
206
|
-
end
|
207
|
-
end.join(DOT)
|
208
|
-
end
|
209
|
-
|
210
|
-
# Decode a +string+ encoded in Punycode
|
211
|
-
def decode(string)
|
212
|
-
# Initialize the state
|
213
|
-
n = INITIAL_N
|
214
|
-
i = 0
|
215
|
-
bias = INITIAL_BIAS
|
216
|
-
|
217
|
-
if j = string.rindex(DELIMITER)
|
218
|
-
b = string[0...j]
|
219
|
-
|
220
|
-
b.match(RE_NONBASIC) &&
|
221
|
-
raise(ArgumentError, "Illegal character is found in basic part: #{string.inspect}")
|
222
|
-
|
223
|
-
# Handle the basic code points
|
224
|
-
|
225
|
-
output = b.unpack("U*")
|
226
|
-
u = string[(j + 1)..-1]
|
227
|
-
else
|
228
|
-
output = []
|
229
|
-
u = string
|
230
|
-
end
|
231
|
-
|
232
|
-
# Main decoding loop: Start just after the last delimiter if any
|
233
|
-
# basic code points were copied; start at the beginning
|
234
|
-
# otherwise.
|
235
|
-
|
236
|
-
input = u.unpack("C*")
|
237
|
-
input_length = input.length
|
238
|
-
h = 0
|
239
|
-
out = output.length
|
240
|
-
|
241
|
-
while h < input_length
|
242
|
-
# Decode a generalized variable-length integer into delta,
|
243
|
-
# which gets added to i. The overflow checking is easier
|
244
|
-
# if we increase i as we go, then subtract off its starting
|
245
|
-
# value at the end to obtain delta.
|
246
|
-
|
247
|
-
oldi = i
|
248
|
-
w = 1
|
249
|
-
k = BASE
|
250
|
-
|
251
|
-
loop do
|
252
|
-
(digit = DECODE_DIGIT[input[h]]) ||
|
253
|
-
raise(ArgumentError, "Illegal character is found in non-basic part: #{string.inspect}")
|
254
|
-
h += 1
|
255
|
-
i += digit * w
|
256
|
-
raise BufferOverflowError if i > MAXINT
|
257
|
-
|
258
|
-
t = k <= bias ? TMIN : k - bias >= TMAX ? TMAX : k - bias
|
259
|
-
break if digit < t
|
260
|
-
|
261
|
-
w *= BASE - t
|
262
|
-
raise BufferOverflowError if w > MAXINT
|
263
|
-
|
264
|
-
k += BASE
|
265
|
-
(h < input_length) || raise(ArgumentError, "Malformed input given: #{string.inspect}")
|
266
|
-
end
|
267
|
-
|
268
|
-
# Adapt the bias
|
269
|
-
delta = oldi == 0 ? i / DAMP : (i - oldi) >> 1
|
270
|
-
delta += delta / (out + 1)
|
271
|
-
bias = 0
|
272
|
-
while delta > CUTOFF
|
273
|
-
delta /= LOBASE
|
274
|
-
bias += BASE
|
275
|
-
end
|
276
|
-
bias += (LOBASE + 1) * delta / (delta + SKEW)
|
277
|
-
|
278
|
-
# i was supposed to wrap around from out+1 to 0, incrementing
|
279
|
-
# n each time, so we'll fix that now:
|
280
|
-
|
281
|
-
q, i = i.divmod(out + 1)
|
282
|
-
n += q
|
283
|
-
raise BufferOverflowError if n > MAXINT
|
284
|
-
|
285
|
-
# Insert n at position i of the output:
|
286
|
-
|
287
|
-
output[i, 0] = n
|
288
|
-
|
289
|
-
out += 1
|
290
|
-
i += 1
|
291
|
-
end
|
292
|
-
output.pack("U*")
|
293
|
-
end
|
15
|
+
warn "#{hostname} cannot be converted to punycode. Install the " \
|
16
|
+
"\"idnx\" gem: https://github.com/HoneyryderChuck/idnx"
|
294
17
|
|
295
|
-
|
296
|
-
def decode_hostname(hostname)
|
297
|
-
hostname.gsub(/(\A|#{Regexp.quote(DOT)})#{Regexp.quote(PREFIX)}([^#{Regexp.quote(DOT)}]*)/o) do
|
298
|
-
Regexp.last_match(1) << decode(Regexp.last_match(2))
|
299
|
-
end
|
18
|
+
hostname
|
300
19
|
end
|
301
20
|
end
|
302
|
-
# :nocov:
|
303
21
|
end
|
304
|
-
end
|
22
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module HTTPX
|
4
|
+
class Request::Body < SimpleDelegator
|
5
|
+
class << self
|
6
|
+
def new(_, options)
|
7
|
+
return options.body if options.body.is_a?(self)
|
8
|
+
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :threshold_size
|
14
|
+
|
15
|
+
def initialize(headers, options)
|
16
|
+
@headers = headers
|
17
|
+
@threshold_size = options.body_threshold_size
|
18
|
+
|
19
|
+
# forego compression in the Range cases
|
20
|
+
if @headers.key?("range")
|
21
|
+
@headers.delete("accept-encoding")
|
22
|
+
else
|
23
|
+
@headers["accept-encoding"] ||= options.supported_compression_formats
|
24
|
+
end
|
25
|
+
|
26
|
+
initialize_body(options)
|
27
|
+
|
28
|
+
return if @body.nil?
|
29
|
+
|
30
|
+
@headers["content-type"] ||= @body.content_type
|
31
|
+
@headers["content-length"] = @body.bytesize unless unbounded_body?
|
32
|
+
super(@body)
|
33
|
+
end
|
34
|
+
|
35
|
+
def each(&block)
|
36
|
+
return enum_for(__method__) unless block
|
37
|
+
return if @body.nil?
|
38
|
+
|
39
|
+
body = stream(@body)
|
40
|
+
if body.respond_to?(:read)
|
41
|
+
::IO.copy_stream(body, ProcIO.new(block))
|
42
|
+
elsif body.respond_to?(:each)
|
43
|
+
body.each(&block)
|
44
|
+
else
|
45
|
+
block[body.to_s]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def rewind
|
50
|
+
return if empty?
|
51
|
+
|
52
|
+
@body.rewind if @body.respond_to?(:rewind)
|
53
|
+
end
|
54
|
+
|
55
|
+
def empty?
|
56
|
+
return true if @body.nil?
|
57
|
+
return false if chunked?
|
58
|
+
|
59
|
+
@body.bytesize.zero?
|
60
|
+
end
|
61
|
+
|
62
|
+
def bytesize
|
63
|
+
return 0 if @body.nil?
|
64
|
+
|
65
|
+
@body.bytesize
|
66
|
+
end
|
67
|
+
|
68
|
+
def stream(body)
|
69
|
+
encoded = body
|
70
|
+
encoded = Transcoder::Chunker.encode(body.enum_for(:each)) if chunked?
|
71
|
+
encoded
|
72
|
+
end
|
73
|
+
|
74
|
+
def unbounded_body?
|
75
|
+
return @unbounded_body if defined?(@unbounded_body)
|
76
|
+
|
77
|
+
@unbounded_body = !@body.nil? && (chunked? || @body.bytesize == Float::INFINITY)
|
78
|
+
end
|
79
|
+
|
80
|
+
def chunked?
|
81
|
+
@headers["transfer-encoding"] == "chunked"
|
82
|
+
end
|
83
|
+
|
84
|
+
def chunk!
|
85
|
+
@headers.add("transfer-encoding", "chunked")
|
86
|
+
end
|
87
|
+
|
88
|
+
# :nocov:
|
89
|
+
def inspect
|
90
|
+
"#<HTTPX::Request::Body:#{object_id} " \
|
91
|
+
"#{unbounded_body? ? "stream" : "@bytesize=#{bytesize}"}>"
|
92
|
+
end
|
93
|
+
# :nocov:
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def initialize_body(options)
|
98
|
+
@body = if options.body
|
99
|
+
Transcoder::Body.encode(options.body)
|
100
|
+
elsif options.form
|
101
|
+
Transcoder::Form.encode(options.form)
|
102
|
+
elsif options.json
|
103
|
+
Transcoder::JSON.encode(options.json)
|
104
|
+
elsif options.xml
|
105
|
+
Transcoder::Xml.encode(options.xml)
|
106
|
+
end
|
107
|
+
|
108
|
+
return unless @body
|
109
|
+
|
110
|
+
return unless options.compress_request_body
|
111
|
+
|
112
|
+
return unless @headers.key?("content-encoding")
|
113
|
+
|
114
|
+
@headers.get("content-encoding").each do |encoding|
|
115
|
+
@body = self.class.initialize_deflater_body(@body, encoding)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class << self
|
120
|
+
def initialize_deflater_body(body, encoding)
|
121
|
+
case encoding
|
122
|
+
when "gzip"
|
123
|
+
Transcoder::GZIP.encode(body)
|
124
|
+
when "deflate"
|
125
|
+
Transcoder::Deflate.encode(body)
|
126
|
+
when "identity"
|
127
|
+
body
|
128
|
+
else
|
129
|
+
body
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class ProcIO
|
136
|
+
def initialize(block)
|
137
|
+
@block = block
|
138
|
+
end
|
139
|
+
|
140
|
+
def write(data)
|
141
|
+
@block.call(data.dup)
|
142
|
+
data.bytesize
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/httpx/request.rb
CHANGED
@@ -19,10 +19,6 @@ module HTTPX
|
|
19
19
|
def_delegator :@body, :empty?
|
20
20
|
|
21
21
|
def initialize(verb, uri, options = {})
|
22
|
-
if verb.is_a?(Symbol)
|
23
|
-
warn "DEPRECATION WARNING: Using symbols for `verb` is deprecated, and will not be supported in httpx 1.0. " \
|
24
|
-
"Use \"#{verb.to_s.upcase}\" instead."
|
25
|
-
end
|
26
22
|
@verb = verb.to_s.upcase
|
27
23
|
@options = Options.new(options)
|
28
24
|
@uri = Utils.to_uri(uri)
|
@@ -69,16 +65,6 @@ module HTTPX
|
|
69
65
|
:w
|
70
66
|
end
|
71
67
|
|
72
|
-
if RUBY_VERSION < "2.2"
|
73
|
-
URIParser = URI::DEFAULT_PARSER
|
74
|
-
|
75
|
-
def initialize_with_escape(verb, uri, options = {})
|
76
|
-
initialize_without_escape(verb, URIParser.escape(uri.to_s), options)
|
77
|
-
end
|
78
|
-
alias_method :initialize_without_escape, :initialize
|
79
|
-
alias_method :initialize, :initialize_with_escape
|
80
|
-
end
|
81
|
-
|
82
68
|
def merge_headers(h)
|
83
69
|
@headers = @headers.merge(h)
|
84
70
|
end
|
@@ -153,100 +139,6 @@ module HTTPX
|
|
153
139
|
end
|
154
140
|
# :nocov:
|
155
141
|
|
156
|
-
class Body < SimpleDelegator
|
157
|
-
class << self
|
158
|
-
def new(_, options)
|
159
|
-
return options.body if options.body.is_a?(self)
|
160
|
-
|
161
|
-
super
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
def initialize(headers, options)
|
166
|
-
@headers = headers
|
167
|
-
@body = initialize_body(options)
|
168
|
-
return if @body.nil?
|
169
|
-
|
170
|
-
@headers["content-type"] ||= @body.content_type
|
171
|
-
@headers["content-length"] = @body.bytesize unless unbounded_body?
|
172
|
-
super(@body)
|
173
|
-
end
|
174
|
-
|
175
|
-
def each(&block)
|
176
|
-
return enum_for(__method__) unless block
|
177
|
-
return if @body.nil?
|
178
|
-
|
179
|
-
body = stream(@body)
|
180
|
-
if body.respond_to?(:read)
|
181
|
-
::IO.copy_stream(body, ProcIO.new(block))
|
182
|
-
elsif body.respond_to?(:each)
|
183
|
-
body.each(&block)
|
184
|
-
else
|
185
|
-
block[body.to_s]
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def rewind
|
190
|
-
return if empty?
|
191
|
-
|
192
|
-
@body.rewind if @body.respond_to?(:rewind)
|
193
|
-
end
|
194
|
-
|
195
|
-
def empty?
|
196
|
-
return true if @body.nil?
|
197
|
-
return false if chunked?
|
198
|
-
|
199
|
-
@body.bytesize.zero?
|
200
|
-
end
|
201
|
-
|
202
|
-
def bytesize
|
203
|
-
return 0 if @body.nil?
|
204
|
-
|
205
|
-
@body.bytesize
|
206
|
-
end
|
207
|
-
|
208
|
-
def stream(body)
|
209
|
-
encoded = body
|
210
|
-
encoded = Transcoder::Chunker.encode(body.enum_for(:each)) if chunked?
|
211
|
-
encoded
|
212
|
-
end
|
213
|
-
|
214
|
-
def unbounded_body?
|
215
|
-
return @unbounded_body if defined?(@unbounded_body)
|
216
|
-
|
217
|
-
@unbounded_body = !@body.nil? && (chunked? || @body.bytesize == Float::INFINITY)
|
218
|
-
end
|
219
|
-
|
220
|
-
def chunked?
|
221
|
-
@headers["transfer-encoding"] == "chunked"
|
222
|
-
end
|
223
|
-
|
224
|
-
def chunk!
|
225
|
-
@headers.add("transfer-encoding", "chunked")
|
226
|
-
end
|
227
|
-
|
228
|
-
# :nocov:
|
229
|
-
def inspect
|
230
|
-
"#<HTTPX::Request::Body:#{object_id} " \
|
231
|
-
"#{unbounded_body? ? "stream" : "@bytesize=#{bytesize}"}>"
|
232
|
-
end
|
233
|
-
# :nocov:
|
234
|
-
|
235
|
-
private
|
236
|
-
|
237
|
-
def initialize_body(options)
|
238
|
-
if options.body
|
239
|
-
Transcoder::Body.encode(options.body)
|
240
|
-
elsif options.form
|
241
|
-
Transcoder::Form.encode(options.form)
|
242
|
-
elsif options.json
|
243
|
-
Transcoder::JSON.encode(options.json)
|
244
|
-
elsif options.xml
|
245
|
-
Transcoder::Xml.encode(options.xml)
|
246
|
-
end
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
142
|
def transition(nextstate)
|
251
143
|
case nextstate
|
252
144
|
when :idle
|
@@ -284,16 +176,7 @@ module HTTPX
|
|
284
176
|
def expects?
|
285
177
|
@headers["expect"] == "100-continue" && @informational_status == 100 && !@response
|
286
178
|
end
|
287
|
-
|
288
|
-
class ProcIO
|
289
|
-
def initialize(block)
|
290
|
-
@block = block
|
291
|
-
end
|
292
|
-
|
293
|
-
def write(data)
|
294
|
-
@block.call(data.dup)
|
295
|
-
data.bytesize
|
296
|
-
end
|
297
|
-
end
|
298
179
|
end
|
299
180
|
end
|
181
|
+
|
182
|
+
require_relative "request/body"
|
data/lib/httpx/resolver/https.rb
CHANGED
@@ -4,12 +4,12 @@ require "resolv"
|
|
4
4
|
require "uri"
|
5
5
|
require "cgi"
|
6
6
|
require "forwardable"
|
7
|
+
require "httpx/base64"
|
7
8
|
|
8
9
|
module HTTPX
|
9
10
|
class Resolver::HTTPS < Resolver::Resolver
|
10
11
|
extend Forwardable
|
11
12
|
using URIExtensions
|
12
|
-
using StringExtensions
|
13
13
|
|
14
14
|
module DNSExtensions
|
15
15
|
refine Resolv::DNS do
|
@@ -8,20 +8,12 @@ module HTTPX
|
|
8
8
|
extend Forwardable
|
9
9
|
using URIExtensions
|
10
10
|
|
11
|
-
DEFAULTS =
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
else
|
18
|
-
{
|
19
|
-
nameserver: nil,
|
20
|
-
**Resolv::DNS::Config.default_config_hash,
|
21
|
-
packet_size: 512,
|
22
|
-
timeouts: Resolver::RESOLVE_TIMEOUT,
|
23
|
-
}
|
24
|
-
end.freeze
|
11
|
+
DEFAULTS = {
|
12
|
+
nameserver: nil,
|
13
|
+
**Resolv::DNS::Config.default_config_hash,
|
14
|
+
packet_size: 512,
|
15
|
+
timeouts: Resolver::RESOLVE_TIMEOUT,
|
16
|
+
}.freeze
|
25
17
|
|
26
18
|
DNS_PORT = 53
|
27
19
|
|
@@ -95,7 +95,7 @@ module HTTPX
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def resolve_error(hostname, ex = nil)
|
98
|
-
return ex if ex.is_a?(ResolveError)
|
98
|
+
return ex if ex.is_a?(ResolveError) || ex.is_a?(ResolveTimeoutError)
|
99
99
|
|
100
100
|
message = ex ? ex.message : "Can't resolve #{hostname}"
|
101
101
|
error = ResolveError.new(message)
|
@@ -92,6 +92,12 @@ module HTTPX
|
|
92
92
|
resolve
|
93
93
|
end
|
94
94
|
|
95
|
+
def raise_timeout_error(interval)
|
96
|
+
error = HTTPX::ResolveTimeoutError.new(interval, "timed out while waiting on select")
|
97
|
+
error.set_backtrace(caller)
|
98
|
+
on_error(error)
|
99
|
+
end
|
100
|
+
|
95
101
|
private
|
96
102
|
|
97
103
|
def transition(nextstate)
|
@@ -164,6 +170,7 @@ module HTTPX
|
|
164
170
|
Thread.current.report_on_exception = false
|
165
171
|
begin
|
166
172
|
addrs = if resolve_timeout
|
173
|
+
|
167
174
|
Timeout.timeout(resolve_timeout) do
|
168
175
|
__addrinfo_resolve(hostname, scheme)
|
169
176
|
end
|
@@ -182,16 +189,11 @@ module HTTPX
|
|
182
189
|
@pipe_write.putc(DONE) unless @pipe_write.closed?
|
183
190
|
end
|
184
191
|
end
|
185
|
-
rescue Timeout::Error => e
|
186
|
-
ex = ResolveTimeoutError.new(resolve_timeout, e.message)
|
187
|
-
ex.set_backtrace(ex.backtrace)
|
188
|
-
@pipe_mutex.synchronize do
|
189
|
-
families.each do |family|
|
190
|
-
@ips.unshift([family, connection, ex])
|
191
|
-
@pipe_write.putc(ERROR) unless @pipe_write.closed?
|
192
|
-
end
|
193
|
-
end
|
194
192
|
rescue StandardError => e
|
193
|
+
if e.is_a?(Timeout::Error)
|
194
|
+
e = ResolveTimeoutError.new(resolve_timeout, e.message)
|
195
|
+
e.set_backtrace(e.backtrace)
|
196
|
+
end
|
195
197
|
@pipe_mutex.synchronize do
|
196
198
|
families.each do |family|
|
197
199
|
@ips.unshift([family, connection, e])
|