httpx 0.19.6 → 0.20.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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/doc/release_notes/0_19_7.md +5 -0
  3. data/doc/release_notes/0_19_8.md +5 -0
  4. data/doc/release_notes/0_20_0.md +36 -0
  5. data/lib/httpx/adapters/datadog.rb +112 -58
  6. data/lib/httpx/adapters/sentry.rb +102 -0
  7. data/lib/httpx/connection.rb +10 -2
  8. data/lib/httpx/io/ssl.rb +8 -3
  9. data/lib/httpx/options.rb +5 -0
  10. data/lib/httpx/plugins/authentication/basic.rb +24 -0
  11. data/lib/httpx/plugins/authentication/digest.rb +102 -0
  12. data/lib/httpx/plugins/authentication/ntlm.rb +37 -0
  13. data/lib/httpx/plugins/authentication/socks5.rb +24 -0
  14. data/lib/httpx/plugins/basic_authentication.rb +6 -6
  15. data/lib/httpx/plugins/digest_authentication.rb +15 -111
  16. data/lib/httpx/plugins/follow_redirects.rb +17 -5
  17. data/lib/httpx/plugins/ntlm_authentication.rb +8 -18
  18. data/lib/httpx/plugins/proxy/http.rb +76 -13
  19. data/lib/httpx/plugins/proxy/socks5.rb +6 -4
  20. data/lib/httpx/plugins/proxy.rb +35 -9
  21. data/lib/httpx/plugins/response_cache/store.rb +1 -0
  22. data/lib/httpx/request.rb +3 -1
  23. data/lib/httpx/session.rb +7 -2
  24. data/lib/httpx/version.rb +1 -1
  25. data/sig/chainable.rbs +4 -4
  26. data/sig/plugins/authentication/basic.rbs +19 -0
  27. data/sig/plugins/authentication/digest.rbs +24 -0
  28. data/sig/plugins/authentication/ntlm.rbs +20 -0
  29. data/sig/plugins/authentication/socks5.rbs +18 -0
  30. data/sig/plugins/basic_authentication.rbs +2 -2
  31. data/sig/plugins/digest_authentication.rbs +3 -13
  32. data/sig/plugins/ntlm_authentication.rbs +3 -8
  33. data/sig/plugins/proxy/http.rbs +13 -3
  34. data/sig/plugins/proxy.rbs +5 -3
  35. data/sig/session.rbs +1 -1
  36. metadata +17 -2
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+
5
+ module HTTPX
6
+ module Plugins
7
+ module Authentication
8
+ class Socks5
9
+ def initialize(user, password, **)
10
+ @user = user
11
+ @password = password
12
+ end
13
+
14
+ def can_authenticate?(*)
15
+ @user && @password
16
+ end
17
+
18
+ def authenticate(*)
19
+ [0x01, @user.bytesize, @user, @password.bytesize, @password].pack("CCA*CA*")
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -7,10 +7,10 @@ module HTTPX
7
7
  #
8
8
  # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#basic-authentication
9
9
  #
10
- module BasicAuthentication
10
+ module BasicAuth
11
11
  class << self
12
12
  def load_dependencies(_klass)
13
- require "base64"
13
+ require_relative "authentication/basic"
14
14
  end
15
15
 
16
16
  def configure(klass)
@@ -19,12 +19,12 @@ module HTTPX
19
19
  end
20
20
 
21
21
  module InstanceMethods
22
- def basic_authentication(user, password)
23
- authentication("Basic #{Base64.strict_encode64("#{user}:#{password}")}")
22
+ def basic_auth(user, password)
23
+ authentication(Authentication::Basic.new(user, password).authenticate)
24
24
  end
25
- alias_method :basic_auth, :basic_authentication
25
+ alias_method :basic_authentication, :basic_auth
26
26
  end
27
27
  end
28
- register_plugin :basic_authentication, BasicAuthentication
28
+ register_plugin :basic_authentication, BasicAuth
29
29
  end
30
30
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "digest"
4
-
5
3
  module HTTPX
6
4
  module Plugins
7
5
  #
@@ -9,9 +7,7 @@ module HTTPX
9
7
  #
10
8
  # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#authentication
11
9
  #
12
- module DigestAuthentication
13
- using RegexpExtensions unless Regexp.method_defined?(:match?)
14
-
10
+ module DigestAuth
15
11
  DigestError = Class.new(Error)
16
12
 
17
13
  class << self
@@ -20,14 +16,13 @@ module HTTPX
20
16
  end
21
17
 
22
18
  def load_dependencies(*)
23
- require "securerandom"
24
- require "digest"
19
+ require_relative "authentication/digest"
25
20
  end
26
21
  end
27
22
 
28
23
  module OptionsMethods
29
24
  def option_digest(value)
30
- raise TypeError, ":digest must be a Digest" unless value.is_a?(Digest)
25
+ raise TypeError, ":digest must be a Digest" unless value.is_a?(Authentication::Digest)
31
26
 
32
27
  value
33
28
  end
@@ -35,7 +30,7 @@ module HTTPX
35
30
 
36
31
  module InstanceMethods
37
32
  def digest_authentication(user, password)
38
- with(digest: Digest.new(user, password))
33
+ with(digest: Authentication::Digest.new(user, password))
39
34
  end
40
35
 
41
36
  alias_method :digest_auth, :digest_authentication
@@ -44,116 +39,25 @@ module HTTPX
44
39
  requests.flat_map do |request|
45
40
  digest = request.options.digest
46
41
 
47
- if digest
48
- probe_response = wrap { super(request).first }
49
-
50
- if digest && !probe_response.is_a?(ErrorResponse) &&
51
- probe_response.status == 401 && probe_response.headers.key?("www-authenticate") &&
52
- /Digest .*/.match?(probe_response.headers["www-authenticate"])
53
-
54
- request.transition(:idle)
55
-
56
- token = digest.generate_header(request, probe_response)
57
- request.headers["authorization"] = "Digest #{token}"
58
-
59
- super(request)
60
- else
61
- probe_response
62
- end
63
- else
42
+ unless digest
64
43
  super(request)
44
+ next
65
45
  end
66
- end
67
- end
68
- end
69
-
70
- class Digest
71
- def initialize(user, password)
72
- @user = user
73
- @password = password
74
- @nonce = 0
75
- end
76
-
77
- def generate_header(request, response, _iis = false)
78
- meth = request.verb.to_s.upcase
79
- www = response.headers["www-authenticate"]
80
-
81
- # discard first token, it's Digest
82
- auth_info = www[/^(\w+) (.*)/, 2]
83
-
84
- uri = request.path
85
-
86
- params = Hash[auth_info.split(/ *, */)
87
- .map { |val| val.split("=") }
88
- .map { |k, v| [k, v.delete("\"")] }]
89
- nonce = params["nonce"]
90
- nc = next_nonce
91
46
 
92
- # verify qop
93
- qop = params["qop"]
47
+ probe_response = wrap { super(request).first }
94
48
 
95
- if params["algorithm"] =~ /(.*?)(-sess)?$/
96
- alg = Regexp.last_match(1)
97
- algorithm = ::Digest.const_get(alg)
98
- raise DigestError, "unknown algorithm \"#{alg}\"" unless algorithm
99
-
100
- sess = Regexp.last_match(2)
101
- params.delete("algorithm")
102
- else
103
- algorithm = ::Digest::MD5
104
- end
105
-
106
- if qop || sess
107
- cnonce = make_cnonce
108
- nc = format("%<nonce>08x", nonce: nc)
109
- end
110
-
111
- a1 = if sess
112
- [algorithm.hexdigest("#{@user}:#{params["realm"]}:#{@password}"),
113
- nonce,
114
- cnonce].join ":"
115
- else
116
- "#{@user}:#{params["realm"]}:#{@password}"
49
+ if probe_response.status == 401 && digest.can_authenticate?(probe_response.headers["www-authenticate"])
50
+ request.transition(:idle)
51
+ request.headers["authorization"] = digest.authenticate(request, probe_response.headers["www-authenticate"])
52
+ super(request)
53
+ else
54
+ probe_response
55
+ end
117
56
  end
118
-
119
- ha1 = algorithm.hexdigest(a1)
120
- ha2 = algorithm.hexdigest("#{meth}:#{uri}")
121
- request_digest = [ha1, nonce]
122
- request_digest.push(nc, cnonce, qop) if qop
123
- request_digest << ha2
124
- request_digest = request_digest.join(":")
125
-
126
- header = [
127
- %(username="#{@user}"),
128
- %(nonce="#{nonce}"),
129
- %(uri="#{uri}"),
130
- %(response="#{algorithm.hexdigest(request_digest)}"),
131
- ]
132
- header << %(realm="#{params["realm"]}") if params.key?("realm")
133
- header << %(algorithm=#{params["algorithm"]}") if params.key?("algorithm")
134
- header << %(opaque="#{params["opaque"]}") if params.key?("opaque")
135
- header << %(cnonce="#{cnonce}") if cnonce
136
- header << %(nc=#{nc})
137
- header << %(qop=#{qop}) if qop
138
- header.join ", "
139
- end
140
-
141
- private
142
-
143
- def make_cnonce
144
- ::Digest::MD5.hexdigest [
145
- Time.now.to_i,
146
- Process.pid,
147
- SecureRandom.random_number(2**32),
148
- ].join ":"
149
- end
150
-
151
- def next_nonce
152
- @nonce += 1
153
57
  end
154
58
  end
155
59
  end
156
60
 
157
- register_plugin :digest_authentication, DigestAuthentication
61
+ register_plugin :digest_authentication, DigestAuth
158
62
  end
159
63
  end
@@ -44,7 +44,7 @@ module HTTPX
44
44
 
45
45
  max_redirects = redirect_request.max_redirects
46
46
 
47
- return response unless REDIRECT_STATUS.include?(response.status)
47
+ return response unless REDIRECT_STATUS.include?(response.status) && response.headers.key?("location")
48
48
  return response unless max_redirects.positive?
49
49
 
50
50
  retry_request = build_redirect_request(redirect_request, response, options)
@@ -86,10 +86,22 @@ module HTTPX
86
86
  redirect_uri = __get_location_from_response(response)
87
87
  max_redirects = request.max_redirects
88
88
 
89
- # redirects are **ALWAYS** GET
90
- retry_options = options.merge(headers: request.headers,
91
- body: request.body,
92
- max_redirects: max_redirects - 1)
89
+ if response.status == 305 && options.respond_to?(:proxy)
90
+ # The requested resource MUST be accessed through the proxy given by
91
+ # the Location field. The Location field gives the URI of the proxy.
92
+ retry_options = options.merge(headers: request.headers,
93
+ proxy: { uri: redirect_uri },
94
+ body: request.body,
95
+ max_redirects: max_redirects - 1)
96
+ redirect_uri = request.url
97
+ else
98
+
99
+ # redirects are **ALWAYS** GET
100
+ retry_options = options.merge(headers: request.headers,
101
+ body: request.body,
102
+ max_redirects: max_redirects - 1)
103
+ end
104
+
93
105
  build_request(:get, redirect_uri, retry_options)
94
106
  end
95
107
 
@@ -5,13 +5,10 @@ module HTTPX
5
5
  #
6
6
  # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#ntlm-authentication
7
7
  #
8
- module NTLMAuthentication
9
- NTLMParams = Struct.new(:user, :domain, :password)
10
-
8
+ module NTLMAuth
11
9
  class << self
12
10
  def load_dependencies(_klass)
13
- require "base64"
14
- require "ntlm"
11
+ require_relative "authentication/ntlm"
15
12
  end
16
13
 
17
14
  def extra_options(options)
@@ -21,7 +18,7 @@ module HTTPX
21
18
 
22
19
  module OptionsMethods
23
20
  def option_ntlm(value)
24
- raise TypeError, ":ntlm must be a #{NTLMParams}" unless value.is_a?(NTLMParams)
21
+ raise TypeError, ":ntlm must be a #{Authentication::Ntlm}" unless value.is_a?(Authentication::Ntlm)
25
22
 
26
23
  value
27
24
  end
@@ -29,7 +26,7 @@ module HTTPX
29
26
 
30
27
  module InstanceMethods
31
28
  def ntlm_authentication(user, password, domain = nil)
32
- with(ntlm: NTLMParams.new(user, domain, password))
29
+ with(ntlm: Authentication::Ntlm.new(user, password, domain: domain))
33
30
  end
34
31
 
35
32
  alias_method :ntlm_auth, :ntlm_authentication
@@ -39,19 +36,12 @@ module HTTPX
39
36
  ntlm = request.options.ntlm
40
37
 
41
38
  if ntlm
42
- request.headers["authorization"] = "NTLM #{NTLM.negotiate(domain: ntlm.domain).to_base64}"
39
+ request.headers["authorization"] = ntlm.negotiate
43
40
  probe_response = wrap { super(request).first }
44
41
 
45
- if !probe_response.is_a?(ErrorResponse) && probe_response.status == 401 &&
46
- probe_response.headers.key?("www-authenticate") &&
47
- (challenge = probe_response.headers["www-authenticate"][/NTLM (.*)/, 1])
48
-
49
- challenge = Base64.decode64(challenge)
50
- ntlm_challenge = NTLM.authenticate(challenge, ntlm.user, ntlm.domain, ntlm.password).to_base64
51
-
42
+ if probe_response.status == 401 && ntlm.can_authenticate?(probe_response.headers["www-authenticate"])
52
43
  request.transition(:idle)
53
-
54
- request.headers["authorization"] = "NTLM #{ntlm_challenge}"
44
+ request.headers["authorization"] = ntlm.authenticate(request, probe_response.headers["www-authenticate"])
55
45
  super(request)
56
46
  else
57
47
  probe_response
@@ -63,6 +53,6 @@ module HTTPX
63
53
  end
64
54
  end
65
55
  end
66
- register_plugin :ntlm_authentication, NTLMAuthentication
56
+ register_plugin :ntlm_authentication, NTLMAuth
67
57
  end
68
58
  end
@@ -6,6 +6,42 @@ module HTTPX
6
6
  module Plugins
7
7
  module Proxy
8
8
  module HTTP
9
+ module InstanceMethods
10
+ def with_proxy_basic_auth(opts)
11
+ with(proxy: opts.merge(scheme: "basic"))
12
+ end
13
+
14
+ def with_proxy_digest_auth(opts)
15
+ with(proxy: opts.merge(scheme: "digest"))
16
+ end
17
+
18
+ def with_proxy_ntlm_auth(opts)
19
+ with(proxy: opts.merge(scheme: "ntlm"))
20
+ end
21
+
22
+ def fetch_response(request, connections, options)
23
+ response = super
24
+
25
+ if response &&
26
+ response.status == 407 &&
27
+ !request.headers.key?("proxy-authorization") &&
28
+ response.headers.key?("proxy-authenticate")
29
+
30
+ connection = find_connection(request, connections, options)
31
+
32
+ if connection.options.proxy.can_authenticate?(response.headers["proxy-authenticate"])
33
+ request.transition(:idle)
34
+ request.headers["proxy-authorization"] =
35
+ connection.options.proxy.authenticate(request, response.headers["proxy-authenticate"])
36
+ connection.send(request)
37
+ return
38
+ end
39
+ end
40
+
41
+ response
42
+ end
43
+ end
44
+
9
45
  module ConnectionMethods
10
46
  def connecting?
11
47
  super || @state == :connecting || @state == :connected
@@ -23,11 +59,27 @@ module HTTPX
23
59
  @io.connect
24
60
  return unless @io.connected?
25
61
 
26
- @parser = registry(@io.protocol).new(@write_buffer, @options.merge(max_concurrent_requests: 1))
27
- @parser.extend(ProxyParser)
28
- @parser.once(:response, &method(:__http_on_connect))
29
- @parser.on(:close) { transition(:closing) }
30
- __http_proxy_connect
62
+ @parser || begin
63
+ @parser = registry(@io.protocol).new(@write_buffer, @options.merge(max_concurrent_requests: 1))
64
+ parser = @parser
65
+ parser.extend(ProxyParser)
66
+ parser.on(:response, &method(:__http_on_connect))
67
+ parser.on(:close) { transition(:closing) }
68
+ parser.on(:reset) do
69
+ if parser.empty?
70
+ reset
71
+ else
72
+ transition(:closing)
73
+ transition(:closed)
74
+ emit(:reset)
75
+
76
+ parser.reset if @parser
77
+ transition(:idle)
78
+ transition(:connecting)
79
+ end
80
+ end
81
+ __http_proxy_connect(parser)
82
+ end
31
83
  return if @state == :connected
32
84
  when :connected
33
85
  return unless @state == :idle || @state == :connecting
@@ -44,13 +96,13 @@ module HTTPX
44
96
  super
45
97
  end
46
98
 
47
- def __http_proxy_connect
99
+ def __http_proxy_connect(parser)
48
100
  req = @pending.first
49
- # if the first request after CONNECT is to an https address, it is assumed that
50
- # all requests in the queue are not only ALL HTTPS, but they also share the certificate,
51
- # and therefore, will share the connection.
52
- #
53
- if req.uri.scheme == "https"
101
+ if req && req.uri.scheme == "https"
102
+ # if the first request after CONNECT is to an https address, it is assumed that
103
+ # all requests in the queue are not only ALL HTTPS, but they also share the certificate,
104
+ # and therefore, will share the connection.
105
+ #
54
106
  connect_request = ConnectRequest.new(req.uri, @options)
55
107
  @inflight += 1
56
108
  parser.send(connect_request)
@@ -59,7 +111,7 @@ module HTTPX
59
111
  end
60
112
  end
61
113
 
62
- def __http_on_connect(_, response)
114
+ def __http_on_connect(request, response)
63
115
  @inflight -= 1
64
116
  if response.status == 200
65
117
  req = @pending.first
@@ -67,6 +119,14 @@ module HTTPX
67
119
  @io = ProxySSL.new(@io, request_uri, @options)
68
120
  transition(:connected)
69
121
  throw(:called)
122
+ elsif response.status == 407 &&
123
+ !request.headers.key?("proxy-authorization") &&
124
+ @options.proxy.can_authenticate?(response.headers["proxy-authenticate"])
125
+
126
+ request.transition(:idle)
127
+ request.headers["proxy-authorization"] = @options.proxy.authenticate(request, response.headers["proxy-authenticate"])
128
+ @parser.send(request)
129
+ @inflight += 1
70
130
  else
71
131
  pending = @pending + @parser.pending
72
132
  while (req = pending.shift)
@@ -88,7 +148,10 @@ module HTTPX
88
148
  extra_headers = super
89
149
 
90
150
  proxy_params = @options.proxy
91
- extra_headers["proxy-authorization"] = "Basic #{proxy_params.token_authentication}" if proxy_params.authenticated?
151
+ if proxy_params.scheme == "basic"
152
+ # opt for basic auth
153
+ extra_headers["proxy-authorization"] = proxy_params.authenticate(extra_headers)
154
+ end
92
155
  extra_headers["proxy-connection"] = extra_headers.delete("connection") if extra_headers.key?("connection")
93
156
  extra_headers
94
157
  end
@@ -18,6 +18,10 @@ module HTTPX
18
18
 
19
19
  Error = Socks5Error
20
20
 
21
+ def self.load_dependencies(*)
22
+ require_relative "../authentication/socks5"
23
+ end
24
+
21
25
  module ConnectionMethods
22
26
  def call
23
27
  super
@@ -156,16 +160,14 @@ module HTTPX
156
160
 
157
161
  def negotiate(parameters)
158
162
  methods = [NOAUTH]
159
- methods << PASSWD if parameters.authenticated?
163
+ methods << PASSWD if parameters.can_authenticate?
160
164
  methods.unshift(methods.size)
161
165
  methods.unshift(VERSION)
162
166
  methods.pack("C*")
163
167
  end
164
168
 
165
169
  def authenticate(parameters)
166
- user = parameters.username
167
- password = parameters.password
168
- [0x01, user.bytesize, user, password.bytesize, password].pack("CCA*CA*")
170
+ parameters.authenticate
169
171
  end
170
172
 
171
173
  def connect(uri)
@@ -19,22 +19,43 @@ module HTTPX
19
19
  PROXY_ERRORS = [TimeoutError, IOError, SystemCallError, Error].freeze
20
20
 
21
21
  class Parameters
22
- attr_reader :uri, :username, :password
22
+ attr_reader :uri, :username, :password, :scheme
23
23
 
24
- def initialize(uri:, username: nil, password: nil)
24
+ def initialize(uri:, scheme: nil, username: nil, password: nil, **extra)
25
25
  @uri = uri.is_a?(URI::Generic) ? uri : URI(uri)
26
26
  @username = username || @uri.user
27
27
  @password = password || @uri.password
28
+
29
+ return unless @username && @password
30
+
31
+ scheme ||= case @uri.scheme
32
+ when "socks5"
33
+ @uri.scheme
34
+ when "http", "https"
35
+ "basic"
36
+ else
37
+ return
38
+ end
39
+
40
+ @scheme = scheme
41
+
42
+ auth_scheme = scheme.to_s.capitalize
43
+
44
+ require_relative "authentication/#{scheme}" unless defined?(Authentication) && Authentication.const_defined?(auth_scheme, false)
45
+
46
+ @authenticator = Authentication.const_get(auth_scheme).new(@username, @password, **extra)
28
47
  end
29
48
 
30
- def authenticated?
31
- @username && @password
49
+ def can_authenticate?(*args)
50
+ return false unless @authenticator
51
+
52
+ @authenticator.can_authenticate?(*args)
32
53
  end
33
54
 
34
- def token_authentication
35
- return unless authenticated?
55
+ def authenticate(*args)
56
+ return unless @authenticator
36
57
 
37
- Base64.strict_encode64("#{@username}:#{@password}")
58
+ @authenticator.authenticate(*args)
38
59
  end
39
60
 
40
61
  def ==(other)
@@ -42,7 +63,8 @@ module HTTPX
42
63
  when Parameters
43
64
  @uri == other.uri &&
44
65
  @username == other.username &&
45
- @password == other.password
66
+ @password == other.password &&
67
+ @scheme == other.scheme
46
68
  when URI::Generic, String
47
69
  proxy_uri = @uri.dup
48
70
  proxy_uri.user = @username
@@ -81,7 +103,11 @@ module HTTPX
81
103
  end
82
104
  uris
83
105
  end
84
- { uri: @_proxy_uris.first } unless @_proxy_uris.empty?
106
+ return if @_proxy_uris.empty?
107
+
108
+ proxy_opts = { uri: @_proxy_uris.first }
109
+ proxy_opts = options.proxy.merge(proxy_opts) if options.proxy
110
+ proxy_opts
85
111
  end
86
112
 
87
113
  def find_connection(request, connections, options)
@@ -37,6 +37,7 @@ module HTTPX::Plugins
37
37
  return unless request.headers.same_headers?(original_request.headers)
38
38
  else
39
39
  return unless vary.split(/ *, */).all? do |cache_field|
40
+ cache_field.downcase!
40
41
  !original_request.headers.key?(cache_field) || request.headers[cache_field] == original_request.headers[cache_field]
41
42
  end
42
43
  end
data/lib/httpx/request.rb CHANGED
@@ -49,7 +49,9 @@ module HTTPX
49
49
  origin = @options.origin
50
50
  raise(Error, "invalid URI: #{@uri}") unless origin
51
51
 
52
- @uri = origin.merge(@uri)
52
+ base_path = @options.base_path
53
+
54
+ @uri = origin.merge("#{base_path}#{@uri}")
53
55
  end
54
56
 
55
57
  raise(Error, "unknown method: #{verb}") unless METHODS.include?(@verb)
data/lib/httpx/session.rb CHANGED
@@ -106,16 +106,21 @@ module HTTPX
106
106
  end
107
107
 
108
108
  def build_altsvc_connection(existing_connection, connections, alt_origin, origin, alt_params, options)
109
+ # do not allow security downgrades on altsvc negotiation
110
+ return if existing_connection.origin.scheme == "https" && alt_origin.scheme != "https"
111
+
109
112
  altsvc = AltSvc.cached_altsvc_set(origin, alt_params.merge("origin" => alt_origin))
110
113
 
111
114
  # altsvc already exists, somehow it wasn't advertised, probably noop
112
115
  return unless altsvc
113
116
 
114
- connection = pool.find_connection(alt_origin, options) || build_connection(alt_origin, options)
117
+ alt_options = options.merge(ssl: options.ssl.merge(hostname: URI(origin).host))
118
+
119
+ connection = pool.find_connection(alt_origin, alt_options) || build_connection(alt_origin, alt_options)
115
120
  # advertised altsvc is the same origin being used, ignore
116
121
  return if connection == existing_connection
117
122
 
118
- set_connection_callbacks(connection, connections, options)
123
+ set_connection_callbacks(connection, connections, alt_options)
119
124
 
120
125
  log(level: 1) { "#{origin} alt-svc: #{alt_origin}" }
121
126
 
data/lib/httpx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "0.19.6"
4
+ VERSION = "0.20.0"
5
5
  end
data/sig/chainable.rbs CHANGED
@@ -13,9 +13,9 @@ module HTTPX
13
13
  | (options) { (Session) -> void } -> void
14
14
 
15
15
  def plugin: (:authentication, ?options) -> Plugins::sessionAuthentication
16
- | (:basic_authentication, ?options) -> Plugins::sessionBasicAuthentication
17
- | (:digest_authentication, ?options) -> Plugins::sessionDigestAuthentication
18
- | (:ntlm_authentication, ?options) -> Plugins::sessionNTLMAuthentication
16
+ | (:basic_authentication, ?options) -> Plugins::sessionBasicAuth
17
+ | (:digest_authentication, ?options) -> Plugins::sessionDigestAuth
18
+ | (:ntlm_authentication, ?options) -> Plugins::sessionNTLMAuth
19
19
  | (:aws_sdk_authentication, ?options) -> Plugins::sessionAwsSdkAuthentication
20
20
  | (:compression, ?options) -> Session
21
21
  | (:cookies, ?options) -> Plugins::sessionCookies
@@ -25,7 +25,7 @@ module HTTPX
25
25
  | (:h2c, ?options) -> Session
26
26
  | (:multipart, ?options) -> Session
27
27
  | (:persistent, ?options) -> Plugins::sessionPersistent
28
- | (:proxy, ?options) -> Plugins::sessionProxy
28
+ | (:proxy, ?options) -> (Plugins::sessionProxy & Plugins::httpProxy)
29
29
  | (:push_promise, ?options) -> Plugins::sessionPushPromise
30
30
  | (:retries, ?options) -> Plugins::sessionRetries
31
31
  | (:rate_limiter, ?options) -> Session
@@ -0,0 +1,19 @@
1
+ module HTTPX
2
+ module Plugins
3
+ module Authentication
4
+ class Basic
5
+ @user: String
6
+ @password: String
7
+
8
+ def can_authenticate?: (String? authenticate) -> boolish
9
+
10
+ def authenticate: (*untyped) -> String
11
+
12
+ private
13
+
14
+ def initialize: (string user, string password, *untyped) -> void
15
+
16
+ end
17
+ end
18
+ end
19
+ end