httpx 0.22.4 → 0.23.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.
- checksums.yaml +4 -4
- data/doc/release_notes/0_22_5.md +6 -0
- data/doc/release_notes/0_23_0.md +42 -0
- data/lib/httpx/adapters/datadog.rb +12 -2
- data/lib/httpx/adapters/faraday.rb +1 -1
- data/lib/httpx/adapters/sentry.rb +15 -5
- data/lib/httpx/adapters/webmock.rb +2 -2
- data/lib/httpx/buffer.rb +4 -0
- data/lib/httpx/callbacks.rb +3 -3
- data/lib/httpx/chainable.rb +4 -4
- data/lib/httpx/connection/http1.rb +2 -2
- data/lib/httpx/connection/http2.rb +2 -3
- data/lib/httpx/connection.rb +31 -11
- data/lib/httpx/io/udp.rb +2 -0
- data/lib/httpx/io/unix.rb +1 -5
- data/lib/httpx/io.rb +0 -10
- data/lib/httpx/options.rb +16 -2
- data/lib/httpx/plugins/authentication/digest.rb +1 -1
- data/lib/httpx/plugins/aws_sdk_authentication.rb +1 -3
- data/lib/httpx/plugins/aws_sigv4.rb +1 -1
- data/lib/httpx/plugins/compression/brotli.rb +4 -4
- data/lib/httpx/plugins/compression/deflate.rb +12 -7
- data/lib/httpx/plugins/compression/gzip.rb +7 -5
- data/lib/httpx/plugins/compression.rb +9 -8
- data/lib/httpx/plugins/digest_authentication.rb +1 -4
- data/lib/httpx/plugins/follow_redirects.rb +1 -1
- data/lib/httpx/plugins/grpc/message.rb +3 -1
- data/lib/httpx/plugins/grpc.rb +3 -3
- data/lib/httpx/plugins/h2c.rb +5 -9
- data/lib/httpx/plugins/internal_telemetry.rb +16 -0
- data/lib/httpx/plugins/multipart.rb +14 -2
- data/lib/httpx/plugins/proxy/http.rb +4 -4
- data/lib/httpx/plugins/proxy.rb +65 -31
- data/lib/httpx/plugins/response_cache.rb +2 -2
- data/lib/httpx/plugins/retries.rb +49 -2
- data/lib/httpx/plugins/upgrade/h2.rb +3 -3
- data/lib/httpx/plugins/upgrade.rb +4 -7
- data/lib/httpx/plugins/webdav.rb +7 -7
- data/lib/httpx/pool.rb +7 -3
- data/lib/httpx/request.rb +23 -13
- data/lib/httpx/resolver/https.rb +37 -20
- data/lib/httpx/resolver/multi.rb +1 -6
- data/lib/httpx/resolver/native.rb +128 -36
- data/lib/httpx/resolver.rb +26 -14
- data/lib/httpx/response.rb +14 -16
- data/lib/httpx/session.rb +1 -0
- data/lib/httpx/transcoder/body.rb +0 -1
- data/lib/httpx/transcoder/chunker.rb +0 -1
- data/lib/httpx/transcoder/form.rb +0 -1
- data/lib/httpx/transcoder/json.rb +0 -1
- data/lib/httpx/transcoder/xml.rb +0 -1
- data/lib/httpx/transcoder.rb +0 -2
- data/lib/httpx/version.rb +1 -1
- data/lib/httpx.rb +0 -1
- data/sig/buffer.rbs +1 -0
- data/sig/chainable.rbs +3 -3
- data/sig/connection.rbs +17 -6
- data/sig/errors.rbs +9 -0
- data/sig/httpx.rbs +3 -3
- data/sig/io/ssl.rbs +17 -0
- data/sig/io/tcp.rbs +57 -0
- data/sig/io/udp.rbs +20 -0
- data/sig/io/unix.rbs +10 -0
- data/sig/options.rbs +5 -1
- data/sig/plugins/compression.rbs +6 -2
- data/sig/plugins/cookies/jar.rbs +2 -2
- data/sig/plugins/grpc.rbs +3 -3
- data/sig/plugins/h2c.rbs +1 -1
- data/sig/plugins/proxy.rbs +1 -5
- data/sig/plugins/response_cache.rbs +1 -1
- data/sig/plugins/retries.rbs +28 -8
- data/sig/plugins/upgrade.rbs +5 -3
- data/sig/request.rbs +6 -2
- data/sig/resolver/https.rbs +3 -1
- data/sig/resolver/native.rbs +7 -2
- data/sig/resolver/resolver.rbs +0 -2
- data/sig/resolver/system.rbs +2 -0
- data/sig/resolver.rbs +8 -4
- data/sig/response.rbs +6 -2
- data/sig/session.rbs +10 -10
- data/sig/transcoder/xml.rbs +1 -1
- data/sig/transcoder.rbs +4 -5
- metadata +11 -5
- data/lib/httpx/registry.rb +0 -85
- data/sig/registry.rbs +0 -13
data/lib/httpx/resolver/https.rb
CHANGED
@@ -104,7 +104,7 @@ module HTTPX
|
|
104
104
|
resolver_connection.send(request)
|
105
105
|
@connections << connection
|
106
106
|
rescue ResolveError, Resolv::DNS::EncodeError => e
|
107
|
-
|
107
|
+
reset_hostname(hostname)
|
108
108
|
emit_resolve_error(connection, connection.origin.host, e)
|
109
109
|
end
|
110
110
|
end
|
@@ -113,7 +113,7 @@ module HTTPX
|
|
113
113
|
response.raise_for_status
|
114
114
|
rescue StandardError => e
|
115
115
|
hostname = @requests.delete(request)
|
116
|
-
connection =
|
116
|
+
connection = reset_hostname(hostname)
|
117
117
|
emit_resolve_error(connection, connection.origin.host, e)
|
118
118
|
else
|
119
119
|
# @type var response: HTTPX::Response
|
@@ -128,30 +128,35 @@ module HTTPX
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def parse(request, response)
|
131
|
-
|
132
|
-
answers = decode_response_body(response)
|
133
|
-
rescue Resolv::DNS::DecodeError => e
|
134
|
-
host, connection = @queries.first
|
135
|
-
@queries.delete(host)
|
136
|
-
emit_resolve_error(connection, connection.origin.host, e)
|
137
|
-
return
|
138
|
-
end
|
131
|
+
code, result = decode_response_body(response)
|
139
132
|
|
140
|
-
|
133
|
+
case code
|
134
|
+
when :ok
|
135
|
+
parse_addresses(result)
|
136
|
+
when :no_domain_found
|
141
137
|
# Indicates no such domain was found.
|
142
138
|
|
143
139
|
host = @requests.delete(request)
|
144
|
-
connection =
|
140
|
+
connection = reset_hostname(host)
|
145
141
|
|
146
|
-
emit_resolve_error(connection)
|
147
|
-
|
148
|
-
# no address found, eliminate candidates
|
142
|
+
emit_resolve_error(connection)
|
143
|
+
when :dns_error
|
149
144
|
host = @requests.delete(request)
|
150
|
-
connection =
|
145
|
+
connection = reset_hostname(host)
|
151
146
|
|
152
|
-
|
153
|
-
|
147
|
+
emit_resolve_error(connection)
|
148
|
+
when :decode_error
|
149
|
+
host, connection = @queries.first
|
150
|
+
reset_hostname(host)
|
151
|
+
emit_resolve_error(connection, connection.origin.host, result)
|
152
|
+
end
|
153
|
+
end
|
154
154
|
|
155
|
+
def parse_addresses(answers)
|
156
|
+
if answers.empty?
|
157
|
+
# no address found, eliminate candidates
|
158
|
+
host = @requests.delete(request)
|
159
|
+
connection = reset_hostname(host)
|
155
160
|
emit_resolve_error(connection)
|
156
161
|
return
|
157
162
|
|
@@ -162,7 +167,7 @@ module HTTPX
|
|
162
167
|
if address.key?("alias")
|
163
168
|
alias_address = answers[address["alias"]]
|
164
169
|
if alias_address.nil?
|
165
|
-
|
170
|
+
reset_hostname(address["name"])
|
166
171
|
if catch(:coalesced) { early_resolve(connection, hostname: address["alias"]) }
|
167
172
|
@connections.delete(connection)
|
168
173
|
else
|
@@ -179,7 +184,7 @@ module HTTPX
|
|
179
184
|
next if addresses.empty?
|
180
185
|
|
181
186
|
hostname.delete_suffix!(".") if hostname.end_with?(".")
|
182
|
-
connection =
|
187
|
+
connection = reset_hostname(hostname, reset_candidates: false)
|
183
188
|
next unless connection # probably a retried query for which there's an answer
|
184
189
|
|
185
190
|
@connections.delete(connection)
|
@@ -224,5 +229,17 @@ module HTTPX
|
|
224
229
|
raise Error, "unsupported DNS mime-type (#{response.headers["content-type"]})"
|
225
230
|
end
|
226
231
|
end
|
232
|
+
|
233
|
+
def reset_hostname(hostname, reset_candidates: true)
|
234
|
+
connection = @queries.delete(hostname)
|
235
|
+
|
236
|
+
return connection unless connection && reset_candidates
|
237
|
+
|
238
|
+
# eliminate other candidates
|
239
|
+
candidates = @queries.select { |_, conn| connection == conn }.keys
|
240
|
+
@queries.delete_if { |h, _| candidates.include?(h) }
|
241
|
+
|
242
|
+
connection
|
243
|
+
end
|
227
244
|
end
|
228
245
|
end
|
data/lib/httpx/resolver/multi.rb
CHANGED
@@ -64,12 +64,7 @@ module HTTPX
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def on_resolver_error(connection, error)
|
67
|
-
|
68
|
-
|
69
|
-
return unless @errors[connection].size >= @resolvers.size
|
70
|
-
|
71
|
-
errors = @errors.delete(connection)
|
72
|
-
emit(:error, connection, errors.first)
|
67
|
+
emit(:error, connection, error)
|
73
68
|
end
|
74
69
|
|
75
70
|
def on_resolver_close(resolver)
|
@@ -33,6 +33,7 @@ module HTTPX
|
|
33
33
|
super
|
34
34
|
@ns_index = 0
|
35
35
|
@resolver_options = DEFAULTS.merge(@options.resolver_options)
|
36
|
+
@socket_type = @resolver_options.fetch(:socket_type, :udp)
|
36
37
|
@nameserver = Array(@resolver_options[:nameserver]) if @resolver_options[:nameserver]
|
37
38
|
@ndots = @resolver_options[:ndots]
|
38
39
|
@search = Array(@resolver_options[:search]).map { |srch| srch.scan(/[^.]+/) }
|
@@ -156,7 +157,7 @@ module HTTPX
|
|
156
157
|
else
|
157
158
|
|
158
159
|
@timeouts.delete(host)
|
159
|
-
|
160
|
+
reset_hostname(h, reset_candidates: false)
|
160
161
|
|
161
162
|
return unless @queries.empty?
|
162
163
|
|
@@ -169,10 +170,49 @@ module HTTPX
|
|
169
170
|
|
170
171
|
def dread(wsize = @resolver_options[:packet_size])
|
171
172
|
loop do
|
173
|
+
wsize = @large_packet.capacity if @large_packet
|
174
|
+
|
172
175
|
siz = @io.read(wsize, @read_buffer)
|
173
|
-
return unless siz && siz.positive?
|
174
176
|
|
175
|
-
|
177
|
+
unless siz
|
178
|
+
ex = EOFError.new("descriptor closed")
|
179
|
+
ex.set_backtrace(caller)
|
180
|
+
raise ex
|
181
|
+
end
|
182
|
+
|
183
|
+
return unless siz.positive?
|
184
|
+
|
185
|
+
if @socket_type == :tcp
|
186
|
+
# packet may be incomplete, need to keep draining from the socket
|
187
|
+
if @large_packet
|
188
|
+
# large packet buffer already exists, continue pumping
|
189
|
+
@large_packet << @read_buffer
|
190
|
+
|
191
|
+
next unless @large_packet.full?
|
192
|
+
|
193
|
+
parse(@large_packet.to_s)
|
194
|
+
|
195
|
+
@socket_type = @resolver_options.fetch(:socket_type, :udp)
|
196
|
+
@large_packet = nil
|
197
|
+
transition(:closed)
|
198
|
+
return
|
199
|
+
else
|
200
|
+
size = @read_buffer[0, 2].unpack1("n")
|
201
|
+
|
202
|
+
if size > @read_buffer.bytesize
|
203
|
+
# only do buffer logic if it's worth it, and the whole packet isn't here already
|
204
|
+
@large_packet = Buffer.new(size)
|
205
|
+
@large_packet << @read_buffer.byteslice(2..-1)
|
206
|
+
|
207
|
+
next
|
208
|
+
else
|
209
|
+
parse(@read_buffer)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
else # udp
|
213
|
+
parse(@read_buffer)
|
214
|
+
end
|
215
|
+
|
176
216
|
return if @state == :closed
|
177
217
|
end
|
178
218
|
end
|
@@ -182,41 +222,63 @@ module HTTPX
|
|
182
222
|
return if @write_buffer.empty?
|
183
223
|
|
184
224
|
siz = @io.write(@write_buffer)
|
185
|
-
|
225
|
+
|
226
|
+
unless siz
|
227
|
+
ex = EOFError.new("descriptor closed")
|
228
|
+
ex.set_backtrace(caller)
|
229
|
+
raise ex
|
230
|
+
end
|
231
|
+
|
232
|
+
return unless siz.positive?
|
186
233
|
|
187
234
|
return if @state == :closed
|
188
235
|
end
|
189
236
|
end
|
190
237
|
|
191
238
|
def parse(buffer)
|
192
|
-
|
193
|
-
|
194
|
-
|
239
|
+
code, result = Resolver.decode_dns_answer(buffer)
|
240
|
+
|
241
|
+
case code
|
242
|
+
when :ok
|
243
|
+
parse_addresses(result)
|
244
|
+
when :no_domain_found
|
245
|
+
# Indicates no such domain was found.
|
195
246
|
hostname, connection = @queries.first
|
196
|
-
|
197
|
-
|
247
|
+
reset_hostname(hostname)
|
248
|
+
|
198
249
|
@connections.delete(connection)
|
199
|
-
|
250
|
+
raise NativeResolveError.new(connection, connection.origin.host, "name or service not known (#{hostname})")
|
251
|
+
when :message_truncated
|
252
|
+
# TODO: what to do if it's already tcp??
|
253
|
+
return if @socket_type == :tcp
|
254
|
+
|
255
|
+
@socket_type = :tcp
|
256
|
+
|
257
|
+
hostname, _ = @queries.first
|
258
|
+
reset_hostname(hostname)
|
259
|
+
transition(:closed)
|
260
|
+
when :dns_error
|
261
|
+
hostname, connection = @queries.first
|
262
|
+
reset_hostname(hostname)
|
263
|
+
@connections.delete(connection)
|
264
|
+
ex = NativeResolveError.new(connection, connection.origin.host, "unknown DNS error (error code #{result})")
|
200
265
|
ex.set_backtrace(e.backtrace)
|
201
266
|
raise ex
|
202
|
-
|
203
|
-
|
204
|
-
if addresses.nil?
|
205
|
-
# Indicates no such domain was found.
|
267
|
+
when :decode_error
|
206
268
|
hostname, connection = @queries.first
|
207
|
-
|
208
|
-
@
|
269
|
+
reset_hostname(hostname)
|
270
|
+
@connections.delete(connection)
|
271
|
+
ex = NativeResolveError.new(connection, connection.origin.host, result.message)
|
272
|
+
ex.set_backtrace(result.backtrace)
|
273
|
+
raise ex
|
274
|
+
end
|
275
|
+
end
|
209
276
|
|
210
|
-
|
211
|
-
|
212
|
-
raise NativeResolveError.new(connection, connection.origin.host)
|
213
|
-
end
|
214
|
-
elsif addresses.empty?
|
277
|
+
def parse_addresses(addresses)
|
278
|
+
if addresses.empty?
|
215
279
|
# no address found, eliminate candidates
|
216
280
|
_, connection = @queries.first
|
217
|
-
|
218
|
-
@queries.delete_if { |hs, _| candidates.include?(hs) }
|
219
|
-
@timeouts.delete_if { |hs, _| candidates.include?(hs) }
|
281
|
+
reset_hostname(hostname)
|
220
282
|
@connections.delete(connection)
|
221
283
|
raise NativeResolveError.new(connection, connection.origin.host)
|
222
284
|
else
|
@@ -226,20 +288,21 @@ module HTTPX
|
|
226
288
|
connection = @queries.delete(name)
|
227
289
|
|
228
290
|
unless connection
|
291
|
+
orig_name = name
|
229
292
|
# absolute name
|
230
293
|
name_labels = Resolv::DNS::Name.create(name).to_a
|
231
|
-
name = @queries.
|
294
|
+
name = @queries.each_key.first { |hname| name_labels == Resolv::DNS::Name.create(hname).to_a }
|
232
295
|
|
233
296
|
# probably a retried query for which there's an answer
|
234
|
-
|
297
|
+
unless name
|
298
|
+
@timeouts.delete(orig_name)
|
299
|
+
return
|
300
|
+
end
|
235
301
|
|
236
302
|
address["name"] = name
|
237
303
|
connection = @queries.delete(name)
|
238
304
|
end
|
239
305
|
|
240
|
-
# eliminate other candidates
|
241
|
-
@queries.delete_if { |_, conn| connection == conn }
|
242
|
-
|
243
306
|
if address.key?("alias") # CNAME
|
244
307
|
# clean up intermediate queries
|
245
308
|
@timeouts.delete(name) unless connection.origin.host == name
|
@@ -265,6 +328,7 @@ module HTTPX
|
|
265
328
|
|
266
329
|
def resolve(connection = @connections.first, hostname = nil)
|
267
330
|
raise Error, "no URI to resolve" unless connection
|
331
|
+
|
268
332
|
return unless @write_buffer.empty?
|
269
333
|
|
270
334
|
hostname ||= @queries.key(connection)
|
@@ -281,12 +345,19 @@ module HTTPX
|
|
281
345
|
end
|
282
346
|
log { "resolver: query #{@record_type.name.split("::").last} for #{hostname}" }
|
283
347
|
begin
|
284
|
-
@write_buffer <<
|
348
|
+
@write_buffer << encode_dns_query(hostname)
|
285
349
|
rescue Resolv::DNS::EncodeError => e
|
286
350
|
emit_resolve_error(connection, hostname, e)
|
287
351
|
end
|
288
352
|
end
|
289
353
|
|
354
|
+
def encode_dns_query(hostname)
|
355
|
+
message_id = Resolver.generate_id
|
356
|
+
msg = Resolver.encode_dns_query(hostname, type: @record_type, message_id: message_id)
|
357
|
+
msg[0, 2] = [msg.size, message_id].pack("nn") if @socket_type == :tcp
|
358
|
+
msg
|
359
|
+
end
|
360
|
+
|
290
361
|
def generate_candidates(name)
|
291
362
|
return [name] if name.end_with?(".")
|
292
363
|
|
@@ -294,18 +365,25 @@ module HTTPX
|
|
294
365
|
name_parts = name.scan(/[^.]+/)
|
295
366
|
candidates = [name] if @ndots <= name_parts.size - 1
|
296
367
|
candidates.concat(@search.map { |domain| [*name_parts, *domain].join(".") })
|
297
|
-
|
368
|
+
fname = "#{name}."
|
369
|
+
candidates << fname unless candidates.include?(fname)
|
298
370
|
|
299
371
|
candidates
|
300
372
|
end
|
301
373
|
|
302
374
|
def build_socket
|
303
|
-
return if @io
|
304
|
-
|
305
375
|
ip, port = @nameserver[@ns_index]
|
306
376
|
port ||= DNS_PORT
|
307
|
-
|
308
|
-
|
377
|
+
|
378
|
+
case @socket_type
|
379
|
+
when :udp
|
380
|
+
log { "resolver: server: udp://#{ip}:#{port}..." }
|
381
|
+
UDP.new(ip, port, @options)
|
382
|
+
when :tcp
|
383
|
+
log { "resolver: server: tcp://#{ip}:#{port}..." }
|
384
|
+
origin = URI("tcp://#{ip}:#{port}")
|
385
|
+
TCP.new(origin, [ip], @options)
|
386
|
+
end
|
309
387
|
end
|
310
388
|
|
311
389
|
def transition(nextstate)
|
@@ -319,7 +397,7 @@ module HTTPX
|
|
319
397
|
when :open
|
320
398
|
return unless @state == :idle
|
321
399
|
|
322
|
-
build_socket
|
400
|
+
@io ||= build_socket
|
323
401
|
|
324
402
|
@io.connect
|
325
403
|
return unless @io.connected?
|
@@ -346,5 +424,19 @@ module HTTPX
|
|
346
424
|
end
|
347
425
|
end
|
348
426
|
end
|
427
|
+
|
428
|
+
def reset_hostname(hostname, reset_candidates: true)
|
429
|
+
@timeouts.delete(hostname)
|
430
|
+
connection = @queries.delete(hostname)
|
431
|
+
@timeouts.delete(hostname)
|
432
|
+
|
433
|
+
return unless connection && reset_candidates
|
434
|
+
|
435
|
+
# eliminate other candidates
|
436
|
+
candidates = @queries.select { |_, conn| connection == conn }.keys
|
437
|
+
@queries.delete_if { |h, _| candidates.include?(h) }
|
438
|
+
# reset timeouts
|
439
|
+
@timeouts.delete_if { |h, _| candidates.include?(h) }
|
440
|
+
end
|
349
441
|
end
|
350
442
|
end
|
data/lib/httpx/resolver.rb
CHANGED
@@ -5,8 +5,6 @@ require "ipaddr"
|
|
5
5
|
|
6
6
|
module HTTPX
|
7
7
|
module Resolver
|
8
|
-
extend Registry
|
9
|
-
|
10
8
|
RESOLVE_TIMEOUT = 5
|
11
9
|
|
12
10
|
require "httpx/resolver/resolver"
|
@@ -15,10 +13,6 @@ module HTTPX
|
|
15
13
|
require "httpx/resolver/https"
|
16
14
|
require "httpx/resolver/multi"
|
17
15
|
|
18
|
-
register :system, System
|
19
|
-
register :native, Native
|
20
|
-
register :https, HTTPS
|
21
|
-
|
22
16
|
@lookup_mutex = Mutex.new
|
23
17
|
@lookups = Hash.new { |h, k| h[k] = [] }
|
24
18
|
|
@@ -28,6 +22,18 @@ module HTTPX
|
|
28
22
|
|
29
23
|
module_function
|
30
24
|
|
25
|
+
def resolver_for(resolver_type)
|
26
|
+
case resolver_type
|
27
|
+
when :native then Native
|
28
|
+
when :system then System
|
29
|
+
when :https then HTTPS
|
30
|
+
else
|
31
|
+
return resolver_type if resolver_type.is_a?(Class) && resolver_type < Resolver
|
32
|
+
|
33
|
+
raise Error, "unsupported resolver type (#{resolver_type})"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
31
37
|
def nolookup_resolve(hostname)
|
32
38
|
ip_resolve(hostname) || cached_lookup(hostname) || system_resolve(hostname)
|
33
39
|
end
|
@@ -98,24 +104,29 @@ module HTTPX
|
|
98
104
|
@identifier_mutex.synchronize { @identifier = (@identifier + 1) & 0xFFFF }
|
99
105
|
end
|
100
106
|
|
101
|
-
def encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A)
|
107
|
+
def encode_dns_query(hostname, type: Resolv::DNS::Resource::IN::A, message_id: generate_id)
|
102
108
|
Resolv::DNS::Message.new.tap do |query|
|
103
|
-
query.id =
|
109
|
+
query.id = message_id
|
104
110
|
query.rd = 1
|
105
111
|
query.add_question(hostname, type)
|
106
112
|
end.encode
|
107
113
|
end
|
108
114
|
|
109
115
|
def decode_dns_answer(payload)
|
110
|
-
|
116
|
+
begin
|
117
|
+
message = Resolv::DNS::Message.decode(payload)
|
118
|
+
rescue Resolv::DNS::DecodeError => e
|
119
|
+
return :decode_error, e
|
120
|
+
end
|
111
121
|
|
112
122
|
# no domain was found
|
113
|
-
return if message.rcode == Resolv::DNS::RCode::NXDomain
|
123
|
+
return :no_domain_found if message.rcode == Resolv::DNS::RCode::NXDomain
|
114
124
|
|
115
|
-
|
125
|
+
return :message_truncated if message.tc == 1
|
116
126
|
|
117
|
-
|
118
|
-
|
127
|
+
return :dns_error, message.rcode if message.rcode != Resolv::DNS::RCode::NoError
|
128
|
+
|
129
|
+
addresses = []
|
119
130
|
|
120
131
|
message.each_answer do |question, _, value|
|
121
132
|
case value
|
@@ -134,7 +145,8 @@ module HTTPX
|
|
134
145
|
}
|
135
146
|
end
|
136
147
|
end
|
137
|
-
|
148
|
+
|
149
|
+
[:ok, addresses]
|
138
150
|
end
|
139
151
|
end
|
140
152
|
end
|
data/lib/httpx/response.rb
CHANGED
@@ -56,12 +56,12 @@ module HTTPX
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def bodyless?
|
59
|
-
@request.verb ==
|
59
|
+
@request.verb == "HEAD" ||
|
60
60
|
no_data?
|
61
61
|
end
|
62
62
|
|
63
63
|
def complete?
|
64
|
-
bodyless? || (@request.verb ==
|
64
|
+
bodyless? || (@request.verb == "CONNECT" && @status == 200)
|
65
65
|
end
|
66
66
|
|
67
67
|
# :nocov:
|
@@ -87,32 +87,27 @@ module HTTPX
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def json(*args)
|
90
|
-
decode(
|
90
|
+
decode(Transcoder::JSON, *args)
|
91
91
|
end
|
92
92
|
|
93
93
|
def form
|
94
|
-
decode(
|
94
|
+
decode(Transcoder::Form)
|
95
95
|
end
|
96
96
|
|
97
97
|
def xml
|
98
|
-
decode(
|
98
|
+
decode(Transcoder::Xml)
|
99
99
|
end
|
100
100
|
|
101
101
|
private
|
102
102
|
|
103
|
-
def decode(
|
103
|
+
def decode(transcoder, *args)
|
104
104
|
# TODO: check if content-type is a valid format, i.e. "application/json" for json parsing
|
105
|
-
transcoder = Transcoder.registry(format)
|
106
|
-
|
107
|
-
raise Error, "no decoder available for \"#{format}\"" unless transcoder.respond_to?(:decode)
|
108
105
|
|
109
106
|
decoder = transcoder.decode(self)
|
110
107
|
|
111
|
-
raise Error, "no decoder available for \"#{
|
108
|
+
raise Error, "no decoder available for \"#{transcoder}\"" unless decoder
|
112
109
|
|
113
110
|
decoder.call(self, *args)
|
114
|
-
rescue Registry::Error
|
115
|
-
raise Error, "no decoder available for \"#{format}\""
|
116
111
|
end
|
117
112
|
|
118
113
|
def no_data?
|
@@ -203,10 +198,8 @@ module HTTPX
|
|
203
198
|
rescue ArgumentError # ex: unknown encoding name - utf
|
204
199
|
content
|
205
200
|
end
|
206
|
-
when nil
|
207
|
-
"".b
|
208
201
|
else
|
209
|
-
|
202
|
+
"".b
|
210
203
|
end
|
211
204
|
end
|
212
205
|
alias_method :to_str, :to_s
|
@@ -334,12 +327,13 @@ module HTTPX
|
|
334
327
|
include Loggable
|
335
328
|
extend Forwardable
|
336
329
|
|
337
|
-
attr_reader :request, :error
|
330
|
+
attr_reader :request, :response, :error
|
338
331
|
|
339
332
|
def_delegator :@request, :uri
|
340
333
|
|
341
334
|
def initialize(request, error, options)
|
342
335
|
@request = request
|
336
|
+
@response = request.response if request.response.is_a?(Response)
|
343
337
|
@error = error
|
344
338
|
@options = Options.new(options)
|
345
339
|
log_exception(@error)
|
@@ -361,6 +355,10 @@ module HTTPX
|
|
361
355
|
end
|
362
356
|
end
|
363
357
|
|
358
|
+
def close
|
359
|
+
@response.close if @response.respond_to?(:close)
|
360
|
+
end
|
361
|
+
|
364
362
|
def finished?
|
365
363
|
true
|
366
364
|
end
|
data/lib/httpx/session.rb
CHANGED
data/lib/httpx/transcoder/xml.rb
CHANGED
data/lib/httpx/transcoder.rb
CHANGED
data/lib/httpx/version.rb
CHANGED
data/lib/httpx.rb
CHANGED
data/sig/buffer.rbs
CHANGED
data/sig/chainable.rbs
CHANGED
@@ -2,9 +2,9 @@ module HTTPX
|
|
2
2
|
module Chainable
|
3
3
|
def request: (*Request, **untyped) -> Array[response]
|
4
4
|
| (Request, **untyped) -> response
|
5
|
-
| (verb
|
6
|
-
| (Array[[verb
|
7
|
-
| (verb
|
5
|
+
| (verb, uri | [uri], **untyped) -> response
|
6
|
+
| (Array[[verb, uri] | [verb, uri, options]], **untyped) -> Array[response]
|
7
|
+
| (verb, _Each[uri | [uri, options]], **untyped) -> Array[response]
|
8
8
|
|
9
9
|
def accept: (String) -> Session
|
10
10
|
def wrap: () { (Session) -> void } -> void
|