httpx 1.2.6 → 1.3.1
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/1_3_0.md +18 -0
- data/doc/release_notes/1_3_1.md +17 -0
- data/lib/httpx/adapters/datadog.rb +8 -4
- data/lib/httpx/adapters/faraday.rb +2 -1
- data/lib/httpx/adapters/webmock.rb +1 -1
- data/lib/httpx/connection/http1.rb +11 -7
- data/lib/httpx/connection/http2.rb +15 -11
- data/lib/httpx/connection.rb +51 -24
- data/lib/httpx/io/tcp.rb +1 -1
- data/lib/httpx/io/unix.rb +1 -1
- data/lib/httpx/options.rb +4 -7
- data/lib/httpx/plugins/aws_sdk_authentication.rb +3 -0
- data/lib/httpx/plugins/aws_sigv4.rb +5 -1
- data/lib/httpx/plugins/circuit_breaker.rb +10 -0
- data/lib/httpx/plugins/cookies.rb +9 -6
- data/lib/httpx/plugins/digest_auth.rb +3 -0
- data/lib/httpx/plugins/expect.rb +5 -0
- data/lib/httpx/plugins/follow_redirects.rb +65 -29
- data/lib/httpx/plugins/grpc.rb +2 -2
- data/lib/httpx/plugins/h2c.rb +1 -1
- data/lib/httpx/plugins/oauth.rb +1 -1
- data/lib/httpx/plugins/proxy/http.rb +9 -4
- data/lib/httpx/plugins/proxy/socks4.rb +1 -1
- data/lib/httpx/plugins/proxy/socks5.rb +1 -1
- data/lib/httpx/plugins/proxy.rb +24 -13
- data/lib/httpx/plugins/retries.rb +25 -4
- data/lib/httpx/plugins/ssrf_filter.rb +4 -1
- data/lib/httpx/pool/synch_pool.rb +93 -0
- data/lib/httpx/pool.rb +1 -1
- data/lib/httpx/request/body.rb +37 -41
- data/lib/httpx/request.rb +42 -13
- data/lib/httpx/resolver/https.rb +7 -5
- data/lib/httpx/resolver/native.rb +1 -1
- data/lib/httpx/resolver/resolver.rb +1 -1
- data/lib/httpx/resolver/system.rb +1 -1
- data/lib/httpx/response.rb +2 -2
- data/lib/httpx/session.rb +34 -19
- data/lib/httpx/timers.rb +1 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/chainable.rbs +2 -2
- data/sig/connection/http1.rbs +2 -2
- data/sig/connection/http2.rbs +17 -17
- data/sig/connection.rbs +10 -4
- data/sig/httpx.rbs +3 -3
- data/sig/io/tcp.rbs +1 -1
- data/sig/io/unix.rbs +1 -1
- data/sig/options.rbs +1 -13
- data/sig/plugins/follow_redirects.rbs +1 -1
- data/sig/plugins/proxy/http.rbs +3 -0
- data/sig/plugins/proxy.rbs +2 -0
- data/sig/plugins/push_promise.rbs +3 -3
- data/sig/pool.rbs +1 -1
- data/sig/request/body.rbs +1 -3
- data/sig/request.rbs +2 -1
- data/sig/resolver/resolver.rbs +2 -2
- data/sig/response.rbs +1 -1
- data/sig/session.rbs +11 -6
- metadata +11 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0162427fe818aafee88a35a12a821cf4f1016701f4513835c91556a7e8579e9e
         | 
| 4 | 
            +
              data.tar.gz: f559d77efcdbf0e557c28c9a012cb67f45a95de8f8c2fac521800679ea30dc31
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1dd2fa825bdaef26137e8c5d993dcb426eab7897adc8570a343863e7842f3732948bdc827c58e1e361bb35b2c1d549b02d89051a592a836a51f39afb95a77263
         | 
| 7 | 
            +
              data.tar.gz: 8a64f6fc512fd8fa60d7feeffff6447d3c8a4081fe6494873b4a527f425dad090ca84b810a2a91477b051a4dfeb0bbb12e0563ef37c20e8d5daab05f2a208138
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            # 1.3.0
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ## Dependencies
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            `http-2` v1.0.0 is replacing `http-2-next` as the HTTP/2 parser.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            `http-2-next` was forked from `http-2` 5 years ago; its improvements have been merged back to `http-2` recently though, so `http-2-next` willl therefore no longer be maintained.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## Improvements
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Request-specific options (`:params`, `:form`, `:json` and `:xml`) are now separately kept by the request, which allows them to share `HTTPX::Options`, and reduce the number of copying / allocations.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            This means that `HTTPX::Options` will throw an error if you initialize an object which such keys; this should not happen, as this class is considered internal and you should not be using it directly.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ## Fixes
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            * support for the `datadog` gem v2.0.0 in its adapter has been unblocked, now that the gem has been released.
         | 
| 18 | 
            +
            * loading the `:cookies` plugin was making the `Session#build_request` private.
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            # 1.3.1
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            ## Improvements
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            * `:request_timeout` will be applied to all HTTP interactions until the final responses returned to the caller. That includes:
         | 
| 6 | 
            +
              * all redirect requests/responses (when using the `:follow_redirects` plugin)
         | 
| 7 | 
            +
              * all retried requests/responses (when using the `:retries` plugin)
         | 
| 8 | 
            +
              * intermediate requests (such as "100-continue")
         | 
| 9 | 
            +
            * faraday adapter: allow further plugins of internal session (ex: `builder.adapter(:httpx) { |sess| sess.plugin(:follow_redirects) }...`)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## Bugfixes
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            * fix connection leak on proxy auth failed (407) handling
         | 
| 14 | 
            +
            * fix busy loop on deferred requests for the duration interval
         | 
| 15 | 
            +
            * do not further enqueue deferred requests if they have terminated meanwhile.
         | 
| 16 | 
            +
            * fix busy loop caused by coalescing connections when one of them is on the DNS resolution phase still.
         | 
| 17 | 
            +
            * faraday adapter: on parallel mode, skip calling `on_complete` when not defined.
         | 
| @@ -142,7 +142,7 @@ module Datadog::Tracing | |
| 142 142 | 
             
                        @configuration ||= Datadog.configuration.tracing[:httpx, @request.uri.host]
         | 
| 143 143 | 
             
                      end
         | 
| 144 144 |  | 
| 145 | 
            -
                      if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("2.0.0 | 
| 145 | 
            +
                      if Gem::Version.new(DATADOG_VERSION::STRING) >= Gem::Version.new("2.0.0")
         | 
| 146 146 | 
             
                        def propagate_trace_http(digest, headers)
         | 
| 147 147 | 
             
                          Datadog::Tracing::Contrib::HTTP.inject(digest, headers)
         | 
| 148 148 | 
             
                        end
         | 
| @@ -195,15 +195,19 @@ module Datadog::Tracing | |
| 195 195 | 
             
                      # that the tracing logic hasn't been injected yet; in such cases, the approximate
         | 
| 196 196 | 
             
                      # initial resolving time is collected from the connection, and used as span start time,
         | 
| 197 197 | 
             
                      # and the tracing object in inserted before the on response callback is called.
         | 
| 198 | 
            -
                      def handle_error(error)
         | 
| 198 | 
            +
                      def handle_error(error, request = nil)
         | 
| 199 199 | 
             
                        return super unless Datadog::Tracing.enabled?
         | 
| 200 200 |  | 
| 201 201 | 
             
                        return super unless error.respond_to?(:connection)
         | 
| 202 202 |  | 
| 203 | 
            -
                        @pending.each do | | 
| 204 | 
            -
                           | 
| 203 | 
            +
                        @pending.each do |req|
         | 
| 204 | 
            +
                          next if request and request == req
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                          RequestTracer.new(req).call(error.connection.init_time)
         | 
| 205 207 | 
             
                        end
         | 
| 206 208 |  | 
| 209 | 
            +
                        RequestTracer.new(request).call(error.connection.init_time) if request
         | 
| 210 | 
            +
             | 
| 207 211 | 
             
                        super
         | 
| 208 212 | 
             
                      end
         | 
| 209 213 | 
             
                    end
         | 
| @@ -30,6 +30,7 @@ module Faraday | |
| 30 30 | 
             
                      end
         | 
| 31 31 | 
             
                      @connection = @connection.plugin(OnDataPlugin) if env.request.stream_response?
         | 
| 32 32 |  | 
| 33 | 
            +
                      @connection = @config_block.call(@connection) || @connection if @config_block
         | 
| 33 34 | 
             
                      @connection
         | 
| 34 35 | 
             
                    end
         | 
| 35 36 |  | 
| @@ -212,7 +213,7 @@ module Faraday | |
| 212 213 | 
             
                        Array(responses).each_with_index do |response, index|
         | 
| 213 214 | 
             
                          handler = @handlers[index]
         | 
| 214 215 | 
             
                          handler.on_response.call(response)
         | 
| 215 | 
            -
                          handler.on_complete.call(handler.env)
         | 
| 216 | 
            +
                          handler.on_complete.call(handler.env) if handler.on_complete
         | 
| 216 217 | 
             
                        end
         | 
| 217 218 | 
             
                      end
         | 
| 218 219 | 
             
                    rescue ::HTTPX::TimeoutError => e
         | 
| @@ -15,7 +15,7 @@ module HTTPX | |
| 15 15 | 
             
                attr_accessor :max_concurrent_requests
         | 
| 16 16 |  | 
| 17 17 | 
             
                def initialize(buffer, options)
         | 
| 18 | 
            -
                  @options =  | 
| 18 | 
            +
                  @options = options
         | 
| 19 19 | 
             
                  @max_concurrent_requests = @options.max_concurrent_requests || MAX_REQUESTS
         | 
| 20 20 | 
             
                  @max_requests = @options.max_requests
         | 
| 21 21 | 
             
                  @parser = Parser::HTTP1.new(self)
         | 
| @@ -146,7 +146,7 @@ module HTTPX | |
| 146 146 |  | 
| 147 147 | 
             
                  response << chunk
         | 
| 148 148 | 
             
                rescue StandardError => e
         | 
| 149 | 
            -
                  error_response = ErrorResponse.new(request, e | 
| 149 | 
            +
                  error_response = ErrorResponse.new(request, e)
         | 
| 150 150 | 
             
                  request.response = error_response
         | 
| 151 151 | 
             
                  dispatch
         | 
| 152 152 | 
             
                end
         | 
| @@ -197,7 +197,7 @@ module HTTPX | |
| 197 197 | 
             
                  end
         | 
| 198 198 | 
             
                end
         | 
| 199 199 |  | 
| 200 | 
            -
                def handle_error(ex)
         | 
| 200 | 
            +
                def handle_error(ex, request = nil)
         | 
| 201 201 | 
             
                  if (ex.is_a?(EOFError) || ex.is_a?(TimeoutError)) && @request && @request.response &&
         | 
| 202 202 | 
             
                     !@request.response.headers.key?("content-length") &&
         | 
| 203 203 | 
             
                     !@request.response.headers.key?("transfer-encoding")
         | 
| @@ -211,11 +211,15 @@ module HTTPX | |
| 211 211 | 
             
                  if @pipelining
         | 
| 212 212 | 
             
                    catch(:called) { disable }
         | 
| 213 213 | 
             
                  else
         | 
| 214 | 
            -
                    @requests.each do | | 
| 215 | 
            -
                       | 
| 214 | 
            +
                    @requests.each do |req|
         | 
| 215 | 
            +
                      next if request && request == req
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                      emit(:error, req, ex)
         | 
| 216 218 | 
             
                    end
         | 
| 217 | 
            -
                    @pending.each do | | 
| 218 | 
            -
                       | 
| 219 | 
            +
                    @pending.each do |req|
         | 
| 220 | 
            +
                      next if request && request == req
         | 
| 221 | 
            +
             | 
| 222 | 
            +
                      emit(:error, req, ex)
         | 
| 219 223 | 
             
                    end
         | 
| 220 224 | 
             
                  end
         | 
| 221 225 | 
             
                end
         | 
| @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require "securerandom"
         | 
| 4 | 
            -
            require "http/2 | 
| 4 | 
            +
            require "http/2"
         | 
| 5 5 |  | 
| 6 6 | 
             
            module HTTPX
         | 
| 7 7 | 
             
              class Connection::HTTP2
         | 
| 8 8 | 
             
                include Callbacks
         | 
| 9 9 | 
             
                include Loggable
         | 
| 10 10 |  | 
| 11 | 
            -
                MAX_CONCURRENT_REQUESTS =  | 
| 11 | 
            +
                MAX_CONCURRENT_REQUESTS = ::HTTP2::DEFAULT_MAX_CONCURRENT_STREAMS
         | 
| 12 12 |  | 
| 13 13 | 
             
                class Error < Error
         | 
| 14 14 | 
             
                  def initialize(id, code)
         | 
| @@ -25,7 +25,7 @@ module HTTPX | |
| 25 25 | 
             
                attr_reader :streams, :pending
         | 
| 26 26 |  | 
| 27 27 | 
             
                def initialize(buffer, options)
         | 
| 28 | 
            -
                  @options =  | 
| 28 | 
            +
                  @options = options
         | 
| 29 29 | 
             
                  @settings = @options.http2_settings
         | 
| 30 30 | 
             
                  @pending = []
         | 
| 31 31 | 
             
                  @streams = {}
         | 
| @@ -111,7 +111,7 @@ module HTTPX | |
| 111 111 | 
             
                  end
         | 
| 112 112 | 
             
                  handle(request, stream)
         | 
| 113 113 | 
             
                  true
         | 
| 114 | 
            -
                rescue  | 
| 114 | 
            +
                rescue ::HTTP2::Error::StreamLimitExceeded
         | 
| 115 115 | 
             
                  @pending.unshift(request)
         | 
| 116 116 | 
             
                end
         | 
| 117 117 |  | 
| @@ -123,7 +123,7 @@ module HTTPX | |
| 123 123 | 
             
                  end
         | 
| 124 124 | 
             
                end
         | 
| 125 125 |  | 
| 126 | 
            -
                def handle_error(ex)
         | 
| 126 | 
            +
                def handle_error(ex, request = nil)
         | 
| 127 127 | 
             
                  if ex.instance_of?(TimeoutError) && !@handshake_completed && @connection.state != :closed
         | 
| 128 128 | 
             
                    @connection.goaway(:settings_timeout, "closing due to settings timeout")
         | 
| 129 129 | 
             
                    emit(:close_handshake)
         | 
| @@ -131,11 +131,15 @@ module HTTPX | |
| 131 131 | 
             
                    settings_ex.set_backtrace(ex.backtrace)
         | 
| 132 132 | 
             
                    ex = settings_ex
         | 
| 133 133 | 
             
                  end
         | 
| 134 | 
            -
                  @streams.each_key do | | 
| 135 | 
            -
                     | 
| 134 | 
            +
                  @streams.each_key do |req|
         | 
| 135 | 
            +
                    next if request && request == req
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                    emit(:error, req, ex)
         | 
| 136 138 | 
             
                  end
         | 
| 137 | 
            -
                  @pending.each do | | 
| 138 | 
            -
                     | 
| 139 | 
            +
                  @pending.each do |req|
         | 
| 140 | 
            +
                    next if request && request == req
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                    emit(:error, req, ex)
         | 
| 139 143 | 
             
                  end
         | 
| 140 144 | 
             
                end
         | 
| 141 145 |  | 
| @@ -168,7 +172,7 @@ module HTTPX | |
| 168 172 | 
             
                end
         | 
| 169 173 |  | 
| 170 174 | 
             
                def init_connection
         | 
| 171 | 
            -
                  @connection =  | 
| 175 | 
            +
                  @connection = ::HTTP2::Client.new(@settings)
         | 
| 172 176 | 
             
                  @connection.on(:frame, &method(:on_frame))
         | 
| 173 177 | 
             
                  @connection.on(:frame_sent, &method(:on_frame_sent))
         | 
| 174 178 | 
             
                  @connection.on(:frame_received, &method(:on_frame_received))
         | 
| @@ -309,7 +313,7 @@ module HTTPX | |
| 309 313 | 
             
                  if error
         | 
| 310 314 | 
             
                    ex = Error.new(stream.id, error)
         | 
| 311 315 | 
             
                    ex.set_backtrace(caller)
         | 
| 312 | 
            -
                    response = ErrorResponse.new(request, ex | 
| 316 | 
            +
                    response = ErrorResponse.new(request, ex)
         | 
| 313 317 | 
             
                    request.response = response
         | 
| 314 318 | 
             
                    emit(:response, request, response)
         | 
| 315 319 | 
             
                  else
         | 
    
        data/lib/httpx/connection.rb
    CHANGED
    
    | @@ -48,6 +48,8 @@ module HTTPX | |
| 48 48 | 
             
                attr_accessor :family
         | 
| 49 49 |  | 
| 50 50 | 
             
                def initialize(uri, options)
         | 
| 51 | 
            +
                  @origins = [uri.origin]
         | 
| 52 | 
            +
                  @origin = Utils.to_uri(uri.origin)
         | 
| 51 53 | 
             
                  @options = Options.new(options)
         | 
| 52 54 | 
             
                  @type = initialize_type(uri, @options)
         | 
| 53 55 | 
             
                  @origins = [uri.origin]
         | 
| @@ -337,7 +339,7 @@ module HTTPX | |
| 337 339 | 
             
                      #
         | 
| 338 340 | 
             
                      loop do
         | 
| 339 341 | 
             
                        siz = @io.read(@window_size, @read_buffer)
         | 
| 340 | 
            -
                        log(level: 3, color: :cyan) { "IO READ: #{siz} bytes..." }
         | 
| 342 | 
            +
                        log(level: 3, color: :cyan) { "IO READ: #{siz} bytes... (wsize: #{@window_size}, rbuffer: #{@read_buffer.bytesize})" }
         | 
| 341 343 | 
             
                        unless siz
         | 
| 342 344 | 
             
                          ex = EOFError.new("descriptor closed")
         | 
| 343 345 | 
             
                          ex.set_backtrace(caller)
         | 
| @@ -504,7 +506,7 @@ module HTTPX | |
| 504 506 | 
             
                    when MisdirectedRequestError
         | 
| 505 507 | 
             
                      emit(:misdirected, request)
         | 
| 506 508 | 
             
                    else
         | 
| 507 | 
            -
                      response = ErrorResponse.new(request, ex | 
| 509 | 
            +
                      response = ErrorResponse.new(request, ex)
         | 
| 508 510 | 
             
                      request.response = response
         | 
| 509 511 | 
             
                      request.emit(:response, response)
         | 
| 510 512 | 
             
                    end
         | 
| @@ -530,7 +532,7 @@ module HTTPX | |
| 530 532 | 
             
                  connecting? && callbacks_for?(:connect_error) ? emit(:connect_error, error) : handle_error(error)
         | 
| 531 533 | 
             
                  @state = :closed
         | 
| 532 534 | 
             
                  emit(:close)
         | 
| 533 | 
            -
                rescue TLSError,  | 
| 535 | 
            +
                rescue TLSError, ::HTTP2::Error::ProtocolError, ::HTTP2::Error::HandshakeError => e
         | 
| 534 536 | 
             
                  # connect errors, exit gracefully
         | 
| 535 537 | 
             
                  handle_error(e)
         | 
| 536 538 | 
             
                  connecting? && callbacks_for?(:connect_error) ? emit(:connect_error, e) : handle_error(e)
         | 
| @@ -560,6 +562,9 @@ module HTTPX | |
| 560 562 | 
             
                    emit(:open)
         | 
| 561 563 | 
             
                  when :inactive
         | 
| 562 564 | 
             
                    return unless @state == :open
         | 
| 565 | 
            +
             | 
| 566 | 
            +
                    # do not deactivate connection in use
         | 
| 567 | 
            +
                    return if @inflight.positive?
         | 
| 563 568 | 
             
                  when :closing
         | 
| 564 569 | 
             
                    return unless @state == :idle || @state == :open
         | 
| 565 570 |  | 
| @@ -636,7 +641,7 @@ module HTTPX | |
| 636 641 | 
             
                  end
         | 
| 637 642 | 
             
                end
         | 
| 638 643 |  | 
| 639 | 
            -
                def on_error(error)
         | 
| 644 | 
            +
                def on_error(error, request = nil)
         | 
| 640 645 | 
             
                  if error.instance_of?(TimeoutError)
         | 
| 641 646 |  | 
| 642 647 | 
             
                    # inactive connections do not contribute to the select loop, therefore
         | 
| @@ -650,39 +655,59 @@ module HTTPX | |
| 650 655 |  | 
| 651 656 | 
             
                    error = error.to_connection_error if connecting?
         | 
| 652 657 | 
             
                  end
         | 
| 653 | 
            -
                  handle_error(error)
         | 
| 658 | 
            +
                  handle_error(error, request)
         | 
| 654 659 | 
             
                  reset
         | 
| 655 660 | 
             
                end
         | 
| 656 661 |  | 
| 657 | 
            -
                def handle_error(error)
         | 
| 658 | 
            -
                  parser.handle_error(error) if @parser && parser.respond_to?(:handle_error)
         | 
| 659 | 
            -
                  while ( | 
| 660 | 
            -
                     | 
| 661 | 
            -
             | 
| 662 | 
            -
                     | 
| 662 | 
            +
                def handle_error(error, request = nil)
         | 
| 663 | 
            +
                  parser.handle_error(error, request) if @parser && parser.respond_to?(:handle_error)
         | 
| 664 | 
            +
                  while (req = @pending.shift)
         | 
| 665 | 
            +
                    next if request && req == request
         | 
| 666 | 
            +
             | 
| 667 | 
            +
                    response = ErrorResponse.new(req, error)
         | 
| 668 | 
            +
                    req.response = response
         | 
| 669 | 
            +
                    req.emit(:response, response)
         | 
| 663 670 | 
             
                  end
         | 
| 671 | 
            +
             | 
| 672 | 
            +
                  return unless request
         | 
| 673 | 
            +
             | 
| 674 | 
            +
                  response = ErrorResponse.new(request, error)
         | 
| 675 | 
            +
                  request.response = response
         | 
| 676 | 
            +
                  request.emit(:response, response)
         | 
| 664 677 | 
             
                end
         | 
| 665 678 |  | 
| 666 679 | 
             
                def set_request_timeouts(request)
         | 
| 667 | 
            -
                   | 
| 680 | 
            +
                  set_request_write_timeout(request)
         | 
| 681 | 
            +
                  set_request_read_timeout(request)
         | 
| 682 | 
            +
                  set_request_request_timeout(request)
         | 
| 683 | 
            +
                end
         | 
| 684 | 
            +
             | 
| 685 | 
            +
                def set_request_read_timeout(request)
         | 
| 668 686 | 
             
                  read_timeout = request.read_timeout
         | 
| 669 | 
            -
                  request_timeout = request.request_timeout
         | 
| 670 687 |  | 
| 671 | 
            -
                   | 
| 672 | 
            -
             | 
| 673 | 
            -
             | 
| 674 | 
            -
                     | 
| 688 | 
            +
                  return if read_timeout.nil? || read_timeout.infinite?
         | 
| 689 | 
            +
             | 
| 690 | 
            +
                  set_request_timeout(request, read_timeout, :done, :response) do
         | 
| 691 | 
            +
                    read_timeout_callback(request, read_timeout)
         | 
| 675 692 | 
             
                  end
         | 
| 693 | 
            +
                end
         | 
| 676 694 |  | 
| 677 | 
            -
             | 
| 678 | 
            -
             | 
| 679 | 
            -
             | 
| 680 | 
            -
             | 
| 695 | 
            +
                def set_request_write_timeout(request)
         | 
| 696 | 
            +
                  write_timeout = request.write_timeout
         | 
| 697 | 
            +
             | 
| 698 | 
            +
                  return if write_timeout.nil? || write_timeout.infinite?
         | 
| 699 | 
            +
             | 
| 700 | 
            +
                  set_request_timeout(request, write_timeout, :headers, %i[done response]) do
         | 
| 701 | 
            +
                    write_timeout_callback(request, write_timeout)
         | 
| 681 702 | 
             
                  end
         | 
| 703 | 
            +
                end
         | 
| 704 | 
            +
             | 
| 705 | 
            +
                def set_request_request_timeout(request)
         | 
| 706 | 
            +
                  request_timeout = request.request_timeout
         | 
| 682 707 |  | 
| 683 708 | 
             
                  return if request_timeout.nil? || request_timeout.infinite?
         | 
| 684 709 |  | 
| 685 | 
            -
                  set_request_timeout(request, request_timeout, :headers, : | 
| 710 | 
            +
                  set_request_timeout(request, request_timeout, :headers, :complete) do
         | 
| 686 711 | 
             
                    read_timeout_callback(request, request_timeout, RequestTimeoutError)
         | 
| 687 712 | 
             
                  end
         | 
| 688 713 | 
             
                end
         | 
| @@ -692,7 +717,8 @@ module HTTPX | |
| 692 717 |  | 
| 693 718 | 
             
                  @write_buffer.clear
         | 
| 694 719 | 
             
                  error = WriteTimeoutError.new(request, nil, write_timeout)
         | 
| 695 | 
            -
             | 
| 720 | 
            +
             | 
| 721 | 
            +
                  on_error(error, request)
         | 
| 696 722 | 
             
                end
         | 
| 697 723 |  | 
| 698 724 | 
             
                def read_timeout_callback(request, read_timeout, error_type = ReadTimeoutError)
         | 
| @@ -702,7 +728,8 @@ module HTTPX | |
| 702 728 |  | 
| 703 729 | 
             
                  @write_buffer.clear
         | 
| 704 730 | 
             
                  error = error_type.new(request, request.response, read_timeout)
         | 
| 705 | 
            -
             | 
| 731 | 
            +
             | 
| 732 | 
            +
                  on_error(error, request)
         | 
| 706 733 | 
             
                end
         | 
| 707 734 |  | 
| 708 735 | 
             
                def set_request_timeout(request, timeout, start_event, finish_events, &callback)
         | 
    
        data/lib/httpx/io/tcp.rb
    CHANGED
    
    
    
        data/lib/httpx/io/unix.rb
    CHANGED
    
    
    
        data/lib/httpx/options.rb
    CHANGED
    
    | @@ -91,7 +91,7 @@ module HTTPX | |
| 91 91 | 
             
                # :debug :: an object which log messages are written to (must respond to <tt><<</tt>)
         | 
| 92 92 | 
             
                # :debug_level :: the log level of messages (can be 1, 2, or 3).
         | 
| 93 93 | 
             
                # :ssl :: a hash of options which can be set as params of OpenSSL::SSL::SSLContext (see HTTPX::IO::SSL)
         | 
| 94 | 
            -
                # :http2_settings :: a hash of options to be passed to a  | 
| 94 | 
            +
                # :http2_settings :: a hash of options to be passed to a HTTP2::Connection (ex: <tt>{ max_concurrent_streams: 2 }</tt>)
         | 
| 95 95 | 
             
                # :fallback_protocol :: version of HTTP protocol to use by default in the absence of protocol negotiation
         | 
| 96 96 | 
             
                #                       like ALPN (defaults to <tt>"http/1.1"</tt>)
         | 
| 97 97 | 
             
                # :supported_compression_formats :: list of compressions supported by the transcoder layer (defaults to <tt>%w[gzip deflate]</tt>).
         | 
| @@ -124,10 +124,6 @@ module HTTPX | |
| 124 124 | 
             
                # :base_path :: path to prefix given relative paths with (ex: "/v2")
         | 
| 125 125 | 
             
                # :max_concurrent_requests :: max number of requests which can be set concurrently
         | 
| 126 126 | 
             
                # :max_requests :: max number of requests which can be made on socket before it reconnects.
         | 
| 127 | 
            -
                # :params :: hash or array of key-values which will be encoded and set in the query string of request uris.
         | 
| 128 | 
            -
                # :form :: hash of array of key-values which will be form-or-multipart-encoded in requests body payload.
         | 
| 129 | 
            -
                # :json :: hash of array of key-values which will be JSON-encoded in requests body payload.
         | 
| 130 | 
            -
                # :xml :: Nokogiri XML nodes which will be encoded in requests body payload.
         | 
| 131 127 | 
             
                #
         | 
| 132 128 | 
             
                # This list of options are enhanced with each loaded plugin, see the plugin docs for details.
         | 
| 133 129 | 
             
                def initialize(options = {})
         | 
| @@ -216,7 +212,7 @@ module HTTPX | |
| 216 212 | 
             
                end
         | 
| 217 213 |  | 
| 218 214 | 
             
                %i[
         | 
| 219 | 
            -
                   | 
| 215 | 
            +
                  ssl http2_settings
         | 
| 220 216 | 
             
                  request_class response_class headers_class request_body_class
         | 
| 221 217 | 
             
                  response_body_class connection_class options_class
         | 
| 222 218 | 
             
                  io fallback_protocol debug debug_level resolver_class resolver_options
         | 
| @@ -224,11 +220,12 @@ module HTTPX | |
| 224 220 | 
             
                  persistent
         | 
| 225 221 | 
             
                ].each do |method_name|
         | 
| 226 222 | 
             
                  class_eval(<<-OUT, __FILE__, __LINE__ + 1)
         | 
| 223 | 
            +
                    # sets +v+ as the value of #{method_name}
         | 
| 227 224 | 
             
                    def option_#{method_name}(v); v; end # def option_smth(v); v; end
         | 
| 228 225 | 
             
                  OUT
         | 
| 229 226 | 
             
                end
         | 
| 230 227 |  | 
| 231 | 
            -
                REQUEST_BODY_IVARS = %i[@headers | 
| 228 | 
            +
                REQUEST_BODY_IVARS = %i[@headers].freeze
         | 
| 232 229 |  | 
| 233 230 | 
             
                def ==(other)
         | 
| 234 231 | 
             
                  super || options_equals?(other)
         | 
| @@ -12,6 +12,7 @@ module HTTPX | |
| 12 12 | 
             
                module AWSSigV4
         | 
| 13 13 | 
             
                  Credentials = Struct.new(:username, :password, :security_token)
         | 
| 14 14 |  | 
| 15 | 
            +
                  # Signs requests using the AWS sigv4 signing.
         | 
| 15 16 | 
             
                  class Signer
         | 
| 16 17 | 
             
                    def initialize(
         | 
| 17 18 | 
             
                      service:,
         | 
| @@ -149,6 +150,9 @@ module HTTPX | |
| 149 150 | 
             
                    end
         | 
| 150 151 | 
             
                  end
         | 
| 151 152 |  | 
| 153 | 
            +
                  # adds support for the following options:
         | 
| 154 | 
            +
                  #
         | 
| 155 | 
            +
                  # :sigv4_signer :: instance of HTTPX::Plugins::AWSSigV4 used to sign requests.
         | 
| 152 156 | 
             
                  module OptionsMethods
         | 
| 153 157 | 
             
                    def option_sigv4_signer(value)
         | 
| 154 158 | 
             
                      value.is_a?(Signer) ? value : Signer.new(value)
         | 
| @@ -160,7 +164,7 @@ module HTTPX | |
| 160 164 | 
             
                      with(sigv4_signer: Signer.new(**options))
         | 
| 161 165 | 
             
                    end
         | 
| 162 166 |  | 
| 163 | 
            -
                    def build_request( | 
| 167 | 
            +
                    def build_request(*)
         | 
| 164 168 | 
             
                      request = super
         | 
| 165 169 |  | 
| 166 170 | 
             
                      return request if request.headers.key?("authorization")
         | 
| @@ -97,6 +97,16 @@ module HTTPX | |
| 97 97 | 
             
                    end
         | 
| 98 98 | 
             
                  end
         | 
| 99 99 |  | 
| 100 | 
            +
                  # adds support for the following options:
         | 
| 101 | 
            +
                  #
         | 
| 102 | 
            +
                  # :circuit_breaker_max_attempts :: the number of attempts the circuit allows, before it is opened (defaults to <tt>3</tt>).
         | 
| 103 | 
            +
                  # :circuit_breaker_reset_attempts_in :: the time a circuit stays open at most, before it resets (defaults to <tt>60</tt>).
         | 
| 104 | 
            +
                  # :circuit_breaker_break_on :: callable defining an alternative rule for a response to break
         | 
| 105 | 
            +
                  #                              (i.e. <tt>->(res) { res.status == 429 } </tt>)
         | 
| 106 | 
            +
                  # :circuit_breaker_break_in :: the time that must elapse before an open circuit can transit to the half-open state
         | 
| 107 | 
            +
                  #                              (defaults to <tt><60</tt>).
         | 
| 108 | 
            +
                  # :circuit_breaker_half_open_drip_rate :: the rate of requests a circuit allows to be performed when in an half-open state
         | 
| 109 | 
            +
                  #                                         (defaults to <tt>1</tt>).
         | 
| 100 110 | 
             
                  module OptionsMethods
         | 
| 101 111 | 
             
                    def option_circuit_breaker_max_attempts(value)
         | 
| 102 112 | 
             
                      attempts = Integer(value)
         | 
| @@ -40,6 +40,12 @@ module HTTPX | |
| 40 40 | 
             
                      end
         | 
| 41 41 | 
             
                    end
         | 
| 42 42 |  | 
| 43 | 
            +
                    def build_request(*)
         | 
| 44 | 
            +
                      request = super
         | 
| 45 | 
            +
                      request.headers.set_cookie(request.options.cookies[request.uri])
         | 
| 46 | 
            +
                      request
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
             | 
| 43 49 | 
             
                    private
         | 
| 44 50 |  | 
| 45 51 | 
             
                    def on_response(_request, response)
         | 
| @@ -52,12 +58,6 @@ module HTTPX | |
| 52 58 |  | 
| 53 59 | 
             
                      super
         | 
| 54 60 | 
             
                    end
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    def build_request(*, _)
         | 
| 57 | 
            -
                      request = super
         | 
| 58 | 
            -
                      request.headers.set_cookie(request.options.cookies[request.uri])
         | 
| 59 | 
            -
                      request
         | 
| 60 | 
            -
                    end
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 |  | 
| 63 63 | 
             
                  module HeadersMethods
         | 
| @@ -70,6 +70,9 @@ module HTTPX | |
| 70 70 | 
             
                    end
         | 
| 71 71 | 
             
                  end
         | 
| 72 72 |  | 
| 73 | 
            +
                  # adds support for the following options:
         | 
| 74 | 
            +
                  #
         | 
| 75 | 
            +
                  # :cookies :: cookie jar for the session (can be a Hash, an Array, an instance of HTTPX::Plugins::Cookies::CookieJar)
         | 
| 73 76 | 
             
                  module OptionsMethods
         | 
| 74 77 | 
             
                    def option_headers(*)
         | 
| 75 78 | 
             
                      value = super
         | 
| @@ -20,6 +20,9 @@ module HTTPX | |
| 20 20 | 
             
                    end
         | 
| 21 21 | 
             
                  end
         | 
| 22 22 |  | 
| 23 | 
            +
                  # adds support for the following options:
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # :digest :: instance of HTTPX::Plugins::Authentication::Digest, used to authenticate requests in the session.
         | 
| 23 26 | 
             
                  module OptionsMethods
         | 
| 24 27 | 
             
                    def option_digest(value)
         | 
| 25 28 | 
             
                      raise TypeError, ":digest must be a #{Authentication::Digest}" unless value.is_a?(Authentication::Digest)
         | 
    
        data/lib/httpx/plugins/expect.rb
    CHANGED
    
    | @@ -20,6 +20,11 @@ module HTTPX | |
| 20 20 | 
             
                    end
         | 
| 21 21 | 
             
                  end
         | 
| 22 22 |  | 
| 23 | 
            +
                  # adds support for the following options:
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # :expect_timeout :: time (in seconds) to wait for a 100-expect response,
         | 
| 26 | 
            +
                  #                    before retrying without the Expect header (defaults to <tt>2</tt>).
         | 
| 27 | 
            +
                  # :expect_threshold_size :: min threshold (in bytes) of the request payload to enable the 100-continue negotiation on.
         | 
| 23 28 | 
             
                  module OptionsMethods
         | 
| 24 29 | 
             
                    def option_expect_timeout(value)
         | 
| 25 30 | 
             
                      seconds = Float(value)
         |