Compare commits

...

10 Commits

Author SHA1 Message Date
HoneyryderChuck
9c765385a5 bump version to 0.22.2 2022-12-23 18:32:47 +00:00
HoneyryderChuck
06274364ef Merge branch 'check-response-class' 2022-12-23 18:31:01 +00:00
HoneyryderChuck
42a35e65d2 added response class checks to not needlessly call .status 2022-12-23 18:22:57 +00:00
HoneyryderChuck
9f224ae389 follow: check that response is not an error response before calling .status 2022-12-23 17:53:00 +00:00
HoneyryderChuck
6723fca484 bump version to 0.22.1 2022-12-23 17:36:47 +00:00
HoneyryderChuck
73326672f4 Merge branch 'issues' into 'master'
bugfix: point Request#response to last response in the folloe redirects

See merge request os85/httpx!226
2022-12-23 17:20:08 +00:00
HoneyryderChuck
d86b780d1a improvement: raise ConnectError on tcp connetion handshake
this is onnly for errors which are not timeouts.
2022-12-23 15:12:01 +00:00
HoneyryderChuck
2cbcd72722 request should not handle 100-continue handshake unless request specifically initiated it 2022-12-23 00:03:04 +00:00
HoneyryderChuck
5937e36f03 bugfix: :stream plugin #request must be public
It already is in the session. This causes code using the stream plugin
to fail when `#request` is called.
2022-12-23 00:01:19 +00:00
HoneyryderChuck
f38573e4e0 bugfix: point Request#response to last response in the folloe redirects
While this API may be accidentally exposed publicly but users aren't
suggeste to use it, internally this is used. for instance, in the
`:stream` plugin, to know whether a response is available; in such a
case, we don't want it to get stuck in the middle.
2022-12-22 23:58:21 +00:00
19 changed files with 68 additions and 15 deletions

View File

@ -0,0 +1,11 @@
# 0.22.1
## Bugfixes
* `:retries` plugin: fix `HTTPX::Response#response to point to last possible response in the redirection chain.
* `:stream` plugin: Make `HTTPX::Session#request` public (as it is inn the main class) .
* return 100 responses if the request didn't specifically ask for "100-continue" negotiation (via the "expect" header).
## Improvements
Wrap low-level socket errors in a `HTTPX::ConnectionError` exception.

View File

@ -0,0 +1,5 @@
# 0.22.1
## Chore
Checking response class before calling `.status`, as this was being called in some places on error responses, thereby triggering the deprecation warning.

View File

@ -242,7 +242,8 @@ module Faraday
Errno::EHOSTUNREACH, Errno::EHOSTUNREACH,
Errno::EINVAL, Errno::EINVAL,
Errno::ENETUNREACH, Errno::ENETUNREACH,
Errno::EPIPE => e Errno::EPIPE,
::HTTPX::ConnectionError => e
raise CONNECTION_FAILED_ERROR, e raise CONNECTION_FAILED_ERROR, e
end end

View File

@ -63,7 +63,11 @@ module HTTPX::Plugins
request_info = extract_request_info(req) request_info = extract_request_info(req)
sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}") sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
sentry_span.set_data(:status, res.status) if res.is_a?(HTTPX::ErrorResponse)
sentry_span.set_data(:error, res.message)
else
sentry_span.set_data(:status, res.status)
end
sentry_span.set_timestamp(::Sentry.utc_now.to_f) sentry_span.set_timestamp(::Sentry.utc_now.to_f)
end end

View File

@ -526,8 +526,14 @@ module HTTPX
Errno::EHOSTUNREACH, Errno::EHOSTUNREACH,
Errno::EINVAL, Errno::EINVAL,
Errno::ENETUNREACH, Errno::ENETUNREACH,
Errno::EPIPE, Errno::EPIPE => e
TLSError => e # connect errors, exit gracefully
error = ConnectionError.new(e.message)
error.set_backtrace(e.backtrace)
handle_error(error)
@state = :closed
emit(:close)
rescue TLSError => e
# connect errors, exit gracefully # connect errors, exit gracefully
handle_error(e) handle_error(e)
@state = :closed @state = :closed

View File

@ -5,6 +5,8 @@ module HTTPX
class UnsupportedSchemeError < Error; end class UnsupportedSchemeError < Error; end
class ConnectionError < Error; end
class TimeoutError < Error class TimeoutError < Error
attr_reader :timeout attr_reader :timeout

View File

@ -74,8 +74,13 @@ module HTTPX
try_connect try_connect
rescue Errno::ECONNREFUSED, rescue Errno::ECONNREFUSED,
Errno::EADDRNOTAVAIL, Errno::EADDRNOTAVAIL,
Errno::EHOSTUNREACH => e Errno::EHOSTUNREACH,
raise e if @ip_index <= 0 SocketError => e
if @ip_index <= 0
error = ConnectionError.new(e.message)
error.set_backtrace(e.backtrace)
raise error
end
log { "failed connecting to #{@ip} (#{e.message}), trying next..." } log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
@ip_index -= 1 @ip_index -= 1

View File

@ -46,6 +46,8 @@ module HTTPX
probe_response = wrap { super(request).first } probe_response = wrap { super(request).first }
return probe_response unless probe_response.is_a?(Response)
if probe_response.status == 401 && digest.can_authenticate?(probe_response.headers["www-authenticate"]) if probe_response.status == 401 && digest.can_authenticate?(probe_response.headers["www-authenticate"])
request.transition(:idle) request.transition(:idle)
request.headers["authorization"] = digest.authenticate(request, probe_response.headers["www-authenticate"]) request.headers["authorization"] = digest.authenticate(request, probe_response.headers["www-authenticate"])

View File

@ -50,7 +50,8 @@ module HTTPX
end end
def response=(response) def response=(response)
if response && response.status == 100 && if response.is_a?(Response) &&
response.status == 100 &&
!@headers.key?("expect") && !@headers.key?("expect") &&
(@state == :body || @state == :done) (@state == :body || @state == :done)
@ -92,7 +93,7 @@ module HTTPX
response = @responses.delete(request) response = @responses.delete(request)
return unless response return unless response
if response.status == 417 && request.headers.key?("expect") if response.is_a?(Response) && response.status == 417 && request.headers.key?("expect")
response.close response.close
request.headers.delete("expect") request.headers.delete("expect")
request.transition(:idle) request.transition(:idle)

View File

@ -44,6 +44,7 @@ module HTTPX
max_redirects = redirect_request.max_redirects max_redirects = redirect_request.max_redirects
return response unless response.is_a?(Response)
return response unless REDIRECT_STATUS.include?(response.status) && response.headers.key?("location") return response unless REDIRECT_STATUS.include?(response.status) && response.headers.key?("location")
return response unless max_redirects.positive? return response unless max_redirects.positive?
@ -121,6 +122,12 @@ module HTTPX
@redirect_request || self @redirect_request || self
end end
def response
return super unless @redirect_request
@redirect_request.response
end
def max_redirects def max_redirects
@options.max_redirects || MAX_REDIRECTS @options.max_redirects || MAX_REDIRECTS
end end

View File

@ -39,6 +39,8 @@ module HTTPX
request.headers["authorization"] = ntlm.negotiate request.headers["authorization"] = ntlm.negotiate
probe_response = wrap { super(request).first } probe_response = wrap { super(request).first }
return probe_response unless probe_response.is_a?(Response)
if probe_response.status == 401 && ntlm.can_authenticate?(probe_response.headers["www-authenticate"]) if probe_response.status == 401 && ntlm.can_authenticate?(probe_response.headers["www-authenticate"])
request.transition(:idle) request.transition(:idle)
request.headers["authorization"] = ntlm.authenticate(request, probe_response.headers["www-authenticate"]) request.headers["authorization"] = ntlm.authenticate(request, probe_response.headers["www-authenticate"])

View File

@ -23,6 +23,7 @@ module HTTPX
response = super response = super
if response && if response &&
response.is_a?(Response) &&
response.status == 407 && response.status == 407 &&
!request.headers.key?("proxy-authorization") && !request.headers.key?("proxy-authorization") &&
response.headers.key?("proxy-authenticate") response.headers.key?("proxy-authenticate")
@ -113,13 +114,14 @@ module HTTPX
def __http_on_connect(request, response) def __http_on_connect(request, response)
@inflight -= 1 @inflight -= 1
if response.status == 200 if response.is_a?(Response) && response.status == 200
req = @pending.first req = @pending.first
request_uri = req.uri request_uri = req.uri
@io = ProxySSL.new(@io, request_uri, @options) @io = ProxySSL.new(@io, request_uri, @options)
transition(:connected) transition(:connected)
throw(:called) throw(:called)
elsif response.status == 407 && elsif response.is_a?(Response) &&
response.status == 407 &&
!request.headers.key?("proxy-authorization") && !request.headers.key?("proxy-authorization") &&
@options.proxy.can_authenticate?(response.headers["proxy-authenticate"]) @options.proxy.can_authenticate?(response.headers["proxy-authenticate"])

View File

@ -23,6 +23,8 @@ module HTTPX
end end
def retry_on_rate_limited_response(response) def retry_on_rate_limited_response(response)
return false unless response.is_a?(Response)
status = response.status status = response.status
RATE_LIMIT_CODES.include?(status) RATE_LIMIT_CODES.include?(status)

View File

@ -23,6 +23,7 @@ module HTTPX
Parser::Error, Parser::Error,
TLSError, TLSError,
TimeoutError, TimeoutError,
ConnectionError,
Connection::HTTP2::GoawayError, Connection::HTTP2::GoawayError,
].freeze ].freeze
DEFAULT_JITTER = ->(interval) { interval * (0.5 * (1 + rand)) } DEFAULT_JITTER = ->(interval) { interval * (0.5 * (1 + rand)) }

View File

@ -95,8 +95,6 @@ module HTTPX
# #
module Stream module Stream
module InstanceMethods module InstanceMethods
private
def request(*args, stream: false, **options) def request(*args, stream: false, **options)
return super(*args, **options) unless stream return super(*args, **options) unless stream

View File

@ -35,7 +35,9 @@ module HTTPX
response = super response = super
if response if response
return response unless response.respond_to?(:headers) && response.headers.key?("upgrade") return response unless response.is_a?(Response)
return response unless response.headers.key?("upgrade")
upgrade_protocol = response.headers["upgrade"].split(/ *, */).first upgrade_protocol = response.headers["upgrade"].split(/ *, */).first

View File

@ -32,6 +32,8 @@ module HTTPX
"</D:lockinfo>" "</D:lockinfo>"
response = request(:lock, path, headers: headers, xml: xml) response = request(:lock, path, headers: headers, xml: xml)
return response unless response.is_a?(Response)
return response unless blk && response.status == 200 return response unless blk && response.status == 200
lock_token = response.headers["lock-token"] lock_token = response.headers["lock-token"]

View File

@ -86,7 +86,7 @@ module HTTPX
def response=(response) def response=(response)
return unless response return unless response
if response.is_a?(Response) && response.status == 100 if response.is_a?(Response) && response.status == 100 && @headers.key?("expect")
@informational_status = response.status @informational_status = response.status
return return
end end

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module HTTPX module HTTPX
VERSION = "0.22.0" VERSION = "0.22.2"
end end