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
@@ -1,137 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "tempfile"
|
4
|
-
require "delegate"
|
5
|
-
|
6
|
-
module HTTPX::Plugins
|
7
|
-
module Multipart
|
8
|
-
class FilePart < SimpleDelegator
|
9
|
-
attr_reader :original_filename, :content_type
|
10
|
-
|
11
|
-
def initialize(filename, content_type)
|
12
|
-
@original_filename = filename
|
13
|
-
@content_type = content_type
|
14
|
-
@file = Tempfile.new("httpx", encoding: Encoding::BINARY, mode: File::RDWR)
|
15
|
-
super(@file)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class Decoder
|
20
|
-
include HTTPX::Utils
|
21
|
-
|
22
|
-
CRLF = "\r\n"
|
23
|
-
BOUNDARY_RE = /;\s*boundary=([^;]+)/i.freeze
|
24
|
-
MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{CRLF}/ni.freeze
|
25
|
-
MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni.freeze
|
26
|
-
MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{CRLF}]*)/ni.freeze
|
27
|
-
WINDOW_SIZE = 2 << 14
|
28
|
-
|
29
|
-
def initialize(response)
|
30
|
-
@boundary = begin
|
31
|
-
m = response.headers["content-type"].to_s[BOUNDARY_RE, 1]
|
32
|
-
raise Error, "no boundary declared in content-type header" unless m
|
33
|
-
|
34
|
-
m.strip
|
35
|
-
end
|
36
|
-
@buffer = "".b
|
37
|
-
@parts = {}
|
38
|
-
@intermediate_boundary = "--#{@boundary}"
|
39
|
-
@state = :idle
|
40
|
-
end
|
41
|
-
|
42
|
-
def call(response, *)
|
43
|
-
response.body.each do |chunk|
|
44
|
-
@buffer << chunk
|
45
|
-
|
46
|
-
parse
|
47
|
-
end
|
48
|
-
|
49
|
-
raise Error, "invalid or unsupported multipart format" unless @buffer.empty?
|
50
|
-
|
51
|
-
@parts
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def parse
|
57
|
-
case @state
|
58
|
-
when :idle
|
59
|
-
raise Error, "payload does not start with boundary" unless @buffer.start_with?("#{@intermediate_boundary}#{CRLF}")
|
60
|
-
|
61
|
-
@buffer = @buffer.byteslice(@intermediate_boundary.bytesize + 2..-1)
|
62
|
-
|
63
|
-
@state = :part_header
|
64
|
-
when :part_header
|
65
|
-
idx = @buffer.index("#{CRLF}#{CRLF}")
|
66
|
-
|
67
|
-
# raise Error, "couldn't parse part headers" unless idx
|
68
|
-
return unless idx
|
69
|
-
|
70
|
-
head = @buffer.byteslice(0..idx + 4 - 1)
|
71
|
-
|
72
|
-
@buffer = @buffer.byteslice(head.bytesize..-1)
|
73
|
-
|
74
|
-
content_type = head[MULTIPART_CONTENT_TYPE, 1]
|
75
|
-
if (name = head[MULTIPART_CONTENT_DISPOSITION, 1])
|
76
|
-
name = /\A"(.*)"\Z/ =~ name ? Regexp.last_match(1) : name.dup
|
77
|
-
name.gsub!(/\\(.)/, "\\1")
|
78
|
-
name
|
79
|
-
else
|
80
|
-
name = head[MULTIPART_CONTENT_ID, 1]
|
81
|
-
end
|
82
|
-
|
83
|
-
filename = HTTPX::Utils.get_filename(head)
|
84
|
-
|
85
|
-
name = filename || +"#{content_type || "text/plain"}[]" if name.nil? || name.empty?
|
86
|
-
|
87
|
-
@current = name
|
88
|
-
|
89
|
-
@parts[name] = if filename
|
90
|
-
FilePart.new(filename, content_type)
|
91
|
-
else
|
92
|
-
"".b
|
93
|
-
end
|
94
|
-
|
95
|
-
@state = :part_body
|
96
|
-
when :part_body
|
97
|
-
part = @parts[@current]
|
98
|
-
|
99
|
-
body_separator = if part.is_a?(FilePart)
|
100
|
-
"#{CRLF}#{CRLF}"
|
101
|
-
else
|
102
|
-
CRLF
|
103
|
-
end
|
104
|
-
idx = @buffer.index(body_separator)
|
105
|
-
|
106
|
-
if idx
|
107
|
-
payload = @buffer.byteslice(0..idx - 1)
|
108
|
-
@buffer = @buffer.byteslice(idx + body_separator.bytesize..-1)
|
109
|
-
part << payload
|
110
|
-
part.rewind if part.respond_to?(:rewind)
|
111
|
-
@state = :parse_boundary
|
112
|
-
else
|
113
|
-
part << @buffer
|
114
|
-
@buffer.clear
|
115
|
-
end
|
116
|
-
when :parse_boundary
|
117
|
-
raise Error, "payload does not start with boundary" unless @buffer.start_with?(@intermediate_boundary)
|
118
|
-
|
119
|
-
@buffer = @buffer.byteslice(@intermediate_boundary.bytesize..-1)
|
120
|
-
|
121
|
-
if @buffer == "--"
|
122
|
-
@buffer.clear
|
123
|
-
@state = :done
|
124
|
-
return
|
125
|
-
elsif @buffer.start_with?(CRLF)
|
126
|
-
@buffer = @buffer.byteslice(2..-1)
|
127
|
-
@state = :part_header
|
128
|
-
else
|
129
|
-
return
|
130
|
-
end
|
131
|
-
when :done
|
132
|
-
raise Error, "parsing should have been over by now"
|
133
|
-
end until @buffer.empty?
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module HTTPX
|
4
|
-
module Plugins
|
5
|
-
#
|
6
|
-
# This plugin adds support for passing `http-form_data` objects (like file objects) as "multipart/form-data";
|
7
|
-
#
|
8
|
-
# HTTPX.post(URL, form: form: { image: HTTP::FormData::File.new("path/to/file")})
|
9
|
-
#
|
10
|
-
# https://gitlab.com/os85/httpx/wikis/Multipart-Uploads
|
11
|
-
#
|
12
|
-
module Multipart
|
13
|
-
MULTIPART_VALUE_COND = lambda do |value|
|
14
|
-
value.respond_to?(:read) ||
|
15
|
-
(value.respond_to?(:to_hash) &&
|
16
|
-
value.key?(:body) &&
|
17
|
-
(value.key?(:filename) || value.key?(:content_type)))
|
18
|
-
end
|
19
|
-
|
20
|
-
class << self
|
21
|
-
def normalize_keys(key, value, &block)
|
22
|
-
Transcoder.normalize_keys(key, value, MULTIPART_VALUE_COND, &block)
|
23
|
-
end
|
24
|
-
|
25
|
-
def load_dependencies(*)
|
26
|
-
# :nocov:
|
27
|
-
begin
|
28
|
-
unless defined?(HTTP::FormData)
|
29
|
-
# in order not to break legacy code, we'll keep loading http/form_data for them.
|
30
|
-
require "http/form_data"
|
31
|
-
warn "httpx: http/form_data is no longer a requirement to use HTTPX :multipart plugin. See migration instructions under" \
|
32
|
-
"https://os85.gitlab.io/httpx/wiki/Multipart-Uploads.html#notes. \n\n" \
|
33
|
-
"If you'd like to stop seeing this message, require 'http/form_data' yourself."
|
34
|
-
end
|
35
|
-
rescue LoadError
|
36
|
-
end
|
37
|
-
# :nocov:
|
38
|
-
require "httpx/plugins/multipart/encoder"
|
39
|
-
require "httpx/plugins/multipart/decoder"
|
40
|
-
require "httpx/plugins/multipart/part"
|
41
|
-
require "httpx/plugins/multipart/mime_type_detector"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
module RequestBodyMethods
|
46
|
-
private
|
47
|
-
|
48
|
-
def initialize_body(options)
|
49
|
-
return FormTranscoder.encode(options.form) if options.form
|
50
|
-
|
51
|
-
super
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
module ResponseMethods
|
56
|
-
def form
|
57
|
-
decode(FormTranscoder)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
module FormTranscoder
|
62
|
-
module_function
|
63
|
-
|
64
|
-
def encode(form)
|
65
|
-
if multipart?(form)
|
66
|
-
Encoder.new(form)
|
67
|
-
else
|
68
|
-
Transcoder::Form::Encoder.new(form)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def decode(response)
|
73
|
-
content_type = response.content_type.mime_type
|
74
|
-
|
75
|
-
case content_type
|
76
|
-
when "application/x-www-form-urlencoded"
|
77
|
-
Transcoder::Form.decode(response)
|
78
|
-
when "multipart/form-data"
|
79
|
-
Decoder.new(response)
|
80
|
-
else
|
81
|
-
raise Error, "invalid form mime type (#{content_type})"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def multipart?(data)
|
86
|
-
data.any? do |_, v|
|
87
|
-
MULTIPART_VALUE_COND.call(v) ||
|
88
|
-
(v.respond_to?(:to_ary) && v.to_ary.any?(&MULTIPART_VALUE_COND)) ||
|
89
|
-
(v.respond_to?(:to_hash) && v.to_hash.any? { |_, e| MULTIPART_VALUE_COND.call(e) })
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
register_plugin :multipart, Multipart
|
95
|
-
end
|
96
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module HTTPX
|
2
|
-
module Plugins
|
3
|
-
module Authentication
|
4
|
-
module InstanceMethods
|
5
|
-
def authentication: (string token) -> instance
|
6
|
-
|
7
|
-
def bearer_auth: (string token) -> instance
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
type sessionAuthentication = Session & Authentication::InstanceMethods
|
12
|
-
end
|
13
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
module HTTPX
|
2
|
-
module Plugins
|
3
|
-
module Compression
|
4
|
-
module Brotli
|
5
|
-
def self.load_dependencies: (singleton(Session)) -> void
|
6
|
-
def self.configure: (singleton(Session)) -> void
|
7
|
-
|
8
|
-
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.decoder: (Integer | Float bytesize) -> Inflater
|
10
|
-
|
11
|
-
module Deflater
|
12
|
-
extend _Deflater
|
13
|
-
end
|
14
|
-
|
15
|
-
class Inflater
|
16
|
-
include _Inflater
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module HTTPX
|
2
|
-
module Plugins
|
3
|
-
module Compression
|
4
|
-
module Deflate
|
5
|
-
def self.load_dependencies: (singleton(Session)) -> void
|
6
|
-
def self.configure: (singleton(Session)) -> void
|
7
|
-
|
8
|
-
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.inflater: (Integer | Float bytesize) -> GZIP::Inflater
|
10
|
-
|
11
|
-
module Deflater
|
12
|
-
extend _Deflater
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module HTTPX
|
2
|
-
module Plugins
|
3
|
-
module Compression
|
4
|
-
module GZIP
|
5
|
-
def self.load_dependencies: (singleton(Session)) -> void
|
6
|
-
def self.configure: (singleton(Session)) -> void
|
7
|
-
|
8
|
-
def self?.deflater: () -> _Deflater
|
9
|
-
def self?.inflater: (Integer | Float bytesize) -> Inflater
|
10
|
-
|
11
|
-
class Deflater
|
12
|
-
include _Deflater
|
13
|
-
|
14
|
-
@compressed_chunk: String
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def initialize: () -> untyped
|
19
|
-
def write: (string) -> void
|
20
|
-
def compressed_chunk: () -> String
|
21
|
-
end
|
22
|
-
|
23
|
-
class Inflater
|
24
|
-
include _Inflater
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
File without changes
|
File without changes
|
File without changes
|