httpx 0.10.0 → 0.11.2
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/README.md +11 -3
- data/doc/release_notes/0_10_1.md +37 -0
- data/doc/release_notes/0_10_2.md +5 -0
- data/doc/release_notes/0_11_0.md +76 -0
- data/doc/release_notes/0_11_1.md +1 -0
- data/doc/release_notes/0_11_2.md +5 -0
- data/lib/httpx/adapters/datadog.rb +205 -0
- data/lib/httpx/adapters/faraday.rb +0 -2
- data/lib/httpx/adapters/webmock.rb +123 -0
- data/lib/httpx/chainable.rb +8 -7
- data/lib/httpx/connection.rb +4 -15
- data/lib/httpx/connection/http1.rb +14 -1
- data/lib/httpx/connection/http2.rb +15 -16
- data/lib/httpx/domain_name.rb +1 -3
- data/lib/httpx/errors.rb +3 -1
- data/lib/httpx/headers.rb +1 -0
- data/lib/httpx/io/ssl.rb +4 -8
- data/lib/httpx/io/udp.rb +4 -3
- data/lib/httpx/plugins/compression.rb +1 -1
- data/lib/httpx/plugins/cookies/set_cookie_parser.rb +1 -1
- data/lib/httpx/plugins/expect.rb +33 -8
- data/lib/httpx/plugins/multipart.rb +42 -23
- data/lib/httpx/plugins/multipart/encoder.rb +115 -0
- data/lib/httpx/plugins/multipart/mime_type_detector.rb +64 -0
- data/lib/httpx/plugins/multipart/part.rb +34 -0
- data/lib/httpx/plugins/proxy.rb +16 -2
- data/lib/httpx/plugins/proxy/socks4.rb +14 -16
- data/lib/httpx/plugins/proxy/socks5.rb +3 -2
- data/lib/httpx/plugins/push_promise.rb +2 -2
- data/lib/httpx/pool.rb +8 -14
- data/lib/httpx/request.rb +22 -12
- data/lib/httpx/resolver.rb +7 -6
- data/lib/httpx/resolver/https.rb +18 -23
- data/lib/httpx/resolver/native.rb +22 -19
- data/lib/httpx/resolver/resolver_mixin.rb +4 -2
- data/lib/httpx/resolver/system.rb +3 -3
- data/lib/httpx/selector.rb +9 -13
- data/lib/httpx/session.rb +24 -21
- data/lib/httpx/transcoder.rb +20 -0
- data/lib/httpx/transcoder/form.rb +9 -1
- data/lib/httpx/version.rb +1 -1
- data/sig/connection.rbs +84 -1
- data/sig/connection/http1.rbs +66 -0
- data/sig/connection/http2.rbs +73 -0
- data/sig/headers.rbs +3 -0
- data/sig/httpx.rbs +1 -0
- data/sig/options.rbs +3 -3
- data/sig/plugins/basic_authentication.rbs +1 -1
- data/sig/plugins/compression.rbs +1 -1
- data/sig/plugins/compression/brotli.rbs +1 -1
- data/sig/plugins/compression/deflate.rbs +1 -1
- data/sig/plugins/compression/gzip.rbs +1 -1
- data/sig/plugins/h2c.rbs +1 -1
- data/sig/plugins/multipart.rbs +29 -4
- data/sig/plugins/persistent.rbs +1 -1
- data/sig/plugins/proxy.rbs +2 -2
- data/sig/plugins/proxy/ssh.rbs +1 -1
- data/sig/plugins/rate_limiter.rbs +1 -1
- data/sig/pool.rbs +36 -2
- data/sig/request.rbs +2 -2
- data/sig/resolver.rbs +26 -0
- data/sig/resolver/https.rbs +51 -0
- data/sig/resolver/native.rbs +60 -0
- data/sig/resolver/resolver_mixin.rbs +27 -0
- data/sig/resolver/system.rbs +17 -0
- data/sig/response.rbs +2 -2
- data/sig/selector.rbs +20 -0
- data/sig/session.rbs +3 -3
- data/sig/transcoder.rbs +4 -2
- data/sig/transcoder/body.rbs +2 -0
- data/sig/transcoder/form.rbs +8 -2
- data/sig/transcoder/json.rbs +3 -1
- metadata +47 -48
- data/lib/httpx/resolver/options.rb +0 -25
- data/sig/missing.rbs +0 -12
- data/sig/test.rbs +0 -9
    
        data/lib/httpx/resolver/https.rb
    CHANGED
    
    | @@ -21,6 +21,7 @@ module HTTPX | |
| 21 21 | 
             
                DEFAULTS = {
         | 
| 22 22 | 
             
                  uri: NAMESERVER,
         | 
| 23 23 | 
             
                  use_get: false,
         | 
| 24 | 
            +
                  record_types: RECORD_TYPES.keys,
         | 
| 24 25 | 
             
                }.freeze
         | 
| 25 26 |  | 
| 26 27 | 
             
                def_delegator :@connections, :empty?
         | 
| @@ -29,27 +30,29 @@ module HTTPX | |
| 29 30 |  | 
| 30 31 | 
             
                def initialize(options)
         | 
| 31 32 | 
             
                  @options = Options.new(options)
         | 
| 32 | 
            -
                  @resolver_options =  | 
| 33 | 
            -
                  @_record_types = Hash.new { |types, host| types[host] =  | 
| 33 | 
            +
                  @resolver_options = DEFAULTS.merge(@options.resolver_options)
         | 
| 34 | 
            +
                  @_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
         | 
| 34 35 | 
             
                  @queries = {}
         | 
| 35 36 | 
             
                  @requests = {}
         | 
| 36 37 | 
             
                  @connections = []
         | 
| 37 | 
            -
                  @uri = URI(@resolver_options | 
| 38 | 
            +
                  @uri = URI(@resolver_options[:uri])
         | 
| 38 39 | 
             
                  @uri_addresses = nil
         | 
| 40 | 
            +
                  @resolver = Resolv::DNS.new
         | 
| 41 | 
            +
                  @resolver.timeouts = @resolver_options.fetch(:timeouts, Resolver::RESOLVE_TIMEOUT)
         | 
| 39 42 | 
             
                end
         | 
| 40 43 |  | 
| 41 44 | 
             
                def <<(connection)
         | 
| 42 45 | 
             
                  return if @uri.origin == connection.origin.to_s
         | 
| 43 46 |  | 
| 44 | 
            -
                  @uri_addresses ||=  | 
| 47 | 
            +
                  @uri_addresses ||= ip_resolve(@uri.host) || system_resolve(@uri.host) || @resolver.getaddresses(@uri.host)
         | 
| 45 48 |  | 
| 46 49 | 
             
                  if @uri_addresses.empty?
         | 
| 47 | 
            -
                    ex = ResolveError.new("Can't resolve #{ | 
| 50 | 
            +
                    ex = ResolveError.new("Can't resolve DNS server #{@uri.host}")
         | 
| 48 51 | 
             
                    ex.set_backtrace(caller)
         | 
| 49 | 
            -
                     | 
| 50 | 
            -
                  else
         | 
| 51 | 
            -
                    early_resolve(connection) || resolve(connection)
         | 
| 52 | 
            +
                    throw(:resolve_error, ex)
         | 
| 52 53 | 
             
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  early_resolve(connection) || resolve(connection)
         | 
| 53 56 | 
             
                end
         | 
| 54 57 |  | 
| 55 58 | 
             
                def timeout
         | 
| @@ -70,12 +73,6 @@ module HTTPX | |
| 70 73 |  | 
| 71 74 | 
             
                private
         | 
| 72 75 |  | 
| 73 | 
            -
                def connect
         | 
| 74 | 
            -
                  return if @queries.empty?
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                  resolver_connection.__send__(__method__)
         | 
| 77 | 
            -
                end
         | 
| 78 | 
            -
             | 
| 79 76 | 
             
                def pool
         | 
| 80 77 | 
             
                  Thread.current[:httpx_connection_pool] ||= Pool.new
         | 
| 81 78 | 
             
                end
         | 
| @@ -100,10 +97,12 @@ module HTTPX | |
| 100 97 | 
             
                    hostname = connection.origin.host
         | 
| 101 98 | 
             
                    log { "resolver: resolve IDN #{connection.origin.non_ascii_hostname} as #{hostname}" } if connection.origin.non_ascii_hostname
         | 
| 102 99 | 
             
                  end
         | 
| 103 | 
            -
                  type = @_record_types[hostname].first
         | 
| 100 | 
            +
                  type = @_record_types[hostname].first || "A"
         | 
| 104 101 | 
             
                  log { "resolver: query #{type} for #{hostname}" }
         | 
| 105 102 | 
             
                  begin
         | 
| 106 103 | 
             
                    request = build_request(hostname, type)
         | 
| 104 | 
            +
                    request.on(:response, &method(:on_response).curry(2)[request])
         | 
| 105 | 
            +
                    request.on(:promise, &method(:on_promise))
         | 
| 107 106 | 
             
                    @requests[request] = connection
         | 
| 108 107 | 
             
                    resolver_connection.send(request)
         | 
| 109 108 | 
             
                    @queries[hostname] = connection
         | 
| @@ -118,9 +117,7 @@ module HTTPX | |
| 118 117 | 
             
                rescue StandardError => e
         | 
| 119 118 | 
             
                  connection = @requests[request]
         | 
| 120 119 | 
             
                  hostname = @queries.key(connection)
         | 
| 121 | 
            -
                   | 
| 122 | 
            -
                  error.set_backtrace(e.backtrace)
         | 
| 123 | 
            -
                  emit(:error, connection, error)
         | 
| 120 | 
            +
                  emit_resolve_error(connection, hostname, e)
         | 
| 124 121 | 
             
                else
         | 
| 125 122 | 
             
                  parse(response)
         | 
| 126 123 | 
             
                ensure
         | 
| @@ -143,7 +140,7 @@ module HTTPX | |
| 143 140 | 
             
                      return
         | 
| 144 141 | 
             
                    end
         | 
| 145 142 | 
             
                  end
         | 
| 146 | 
            -
                  if answers.empty?
         | 
| 143 | 
            +
                  if answers.nil? || answers.empty?
         | 
| 147 144 | 
             
                    host, connection = @queries.first
         | 
| 148 145 | 
             
                    @_record_types[host].shift
         | 
| 149 146 | 
             
                    if @_record_types[host].empty?
         | 
| @@ -177,7 +174,7 @@ module HTTPX | |
| 177 174 | 
             
                      next unless connection # probably a retried query for which there's an answer
         | 
| 178 175 |  | 
| 179 176 | 
             
                      @connections.delete(connection)
         | 
| 180 | 
            -
                      Resolver.cached_lookup_set(hostname, addresses) if @resolver_options | 
| 177 | 
            +
                      Resolver.cached_lookup_set(hostname, addresses) if @resolver_options[:cache]
         | 
| 181 178 | 
             
                      emit_addresses(connection, addresses.map { |addr| addr["data"] })
         | 
| 182 179 | 
             
                    end
         | 
| 183 180 | 
             
                  end
         | 
| @@ -191,7 +188,7 @@ module HTTPX | |
| 191 188 | 
             
                  rklass = @options.request_class
         | 
| 192 189 | 
             
                  payload = Resolver.encode_dns_query(hostname, type: RECORD_TYPES[type])
         | 
| 193 190 |  | 
| 194 | 
            -
                  if @resolver_options | 
| 191 | 
            +
                  if @resolver_options[:use_get]
         | 
| 195 192 | 
             
                    params = URI.decode_www_form(uri.query.to_s)
         | 
| 196 193 | 
             
                    params << ["type", type]
         | 
| 197 194 | 
             
                    params << ["dns", Base64.urlsafe_encode64(payload, padding: false)]
         | 
| @@ -202,8 +199,6 @@ module HTTPX | |
| 202 199 | 
             
                    request.headers["content-type"] = "application/dns-message"
         | 
| 203 200 | 
             
                  end
         | 
| 204 201 | 
             
                  request.headers["accept"] = "application/dns-message"
         | 
| 205 | 
            -
                  request.on(:response, &method(:on_response).curry[request])
         | 
| 206 | 
            -
                  request.on(:promise, &method(:on_promise))
         | 
| 207 202 | 
             
                  request
         | 
| 208 203 | 
             
                end
         | 
| 209 204 |  | 
| @@ -9,18 +9,16 @@ module HTTPX | |
| 9 9 | 
             
                include Resolver::ResolverMixin
         | 
| 10 10 | 
             
                using URIExtensions
         | 
| 11 11 |  | 
| 12 | 
            -
                RESOLVE_TIMEOUT = 5
         | 
| 13 12 | 
             
                RECORD_TYPES = {
         | 
| 14 13 | 
             
                  "A" => Resolv::DNS::Resource::IN::A,
         | 
| 15 14 | 
             
                  "AAAA" => Resolv::DNS::Resource::IN::AAAA,
         | 
| 16 15 | 
             
                }.freeze
         | 
| 17 16 |  | 
| 18 | 
            -
                # :nocov:
         | 
| 19 17 | 
             
                DEFAULTS = if RUBY_VERSION < "2.2"
         | 
| 20 18 | 
             
                  {
         | 
| 21 19 | 
             
                    **Resolv::DNS::Config.default_config_hash,
         | 
| 22 20 | 
             
                    packet_size: 512,
         | 
| 23 | 
            -
                    timeouts: RESOLVE_TIMEOUT,
         | 
| 21 | 
            +
                    timeouts: Resolver::RESOLVE_TIMEOUT,
         | 
| 24 22 | 
             
                    record_types: RECORD_TYPES.keys,
         | 
| 25 23 | 
             
                  }.freeze
         | 
| 26 24 | 
             
                else
         | 
| @@ -28,7 +26,7 @@ module HTTPX | |
| 28 26 | 
             
                    nameserver: nil,
         | 
| 29 27 | 
             
                    **Resolv::DNS::Config.default_config_hash,
         | 
| 30 28 | 
             
                    packet_size: 512,
         | 
| 31 | 
            -
                    timeouts: RESOLVE_TIMEOUT,
         | 
| 29 | 
            +
                    timeouts: Resolver::RESOLVE_TIMEOUT,
         | 
| 32 30 | 
             
                    record_types: RECORD_TYPES.keys,
         | 
| 33 31 | 
             
                  }.freeze
         | 
| 34 32 | 
             
                end
         | 
| @@ -44,7 +42,6 @@ module HTTPX | |
| 44 42 | 
             
                    false
         | 
| 45 43 | 
             
                  end
         | 
| 46 44 | 
             
                end if DEFAULTS[:nameserver]
         | 
| 47 | 
            -
                # :nocov:
         | 
| 48 45 |  | 
| 49 46 | 
             
                DNS_PORT = 53
         | 
| 50 47 |  | 
| @@ -53,15 +50,15 @@ module HTTPX | |
| 53 50 | 
             
                def initialize(options)
         | 
| 54 51 | 
             
                  @options = Options.new(options)
         | 
| 55 52 | 
             
                  @ns_index = 0
         | 
| 56 | 
            -
                  @resolver_options =  | 
| 57 | 
            -
                  @nameserver = @resolver_options | 
| 58 | 
            -
                  @_timeouts = Array(@resolver_options | 
| 53 | 
            +
                  @resolver_options = DEFAULTS.merge(@options.resolver_options)
         | 
| 54 | 
            +
                  @nameserver = @resolver_options[:nameserver]
         | 
| 55 | 
            +
                  @_timeouts = Array(@resolver_options[:timeouts])
         | 
| 59 56 | 
             
                  @timeouts = Hash.new { |timeouts, host| timeouts[host] = @_timeouts.dup }
         | 
| 60 | 
            -
                  @_record_types = Hash.new { |types, host| types[host] = @resolver_options | 
| 57 | 
            +
                  @_record_types = Hash.new { |types, host| types[host] = @resolver_options[:record_types].dup }
         | 
| 61 58 | 
             
                  @connections = []
         | 
| 62 59 | 
             
                  @queries = {}
         | 
| 63 60 | 
             
                  @read_buffer = "".b
         | 
| 64 | 
            -
                  @write_buffer = Buffer.new(@resolver_options | 
| 61 | 
            +
                  @write_buffer = Buffer.new(@resolver_options[:packet_size])
         | 
| 65 62 | 
             
                  @state = :idle
         | 
| 66 63 | 
             
                end
         | 
| 67 64 |  | 
| @@ -111,9 +108,9 @@ module HTTPX | |
| 111 108 | 
             
                  return if early_resolve(connection)
         | 
| 112 109 |  | 
| 113 110 | 
             
                  if @nameserver.nil?
         | 
| 114 | 
            -
                    ex = ResolveError.new(" | 
| 111 | 
            +
                    ex = ResolveError.new("No available nameserver")
         | 
| 115 112 | 
             
                    ex.set_backtrace(caller)
         | 
| 116 | 
            -
                     | 
| 113 | 
            +
                    throw(:resolve_error, ex)
         | 
| 117 114 | 
             
                  else
         | 
| 118 115 | 
             
                    @connections << connection
         | 
| 119 116 | 
             
                    resolve
         | 
| @@ -150,21 +147,26 @@ module HTTPX | |
| 150 147 | 
             
                      queries[h] = connection
         | 
| 151 148 | 
             
                      next
         | 
| 152 149 | 
             
                    end
         | 
| 150 | 
            +
             | 
| 153 151 | 
             
                    @timeouts[host].shift
         | 
| 154 152 | 
             
                    if @timeouts[host].empty?
         | 
| 155 153 | 
             
                      @timeouts.delete(host)
         | 
| 156 154 | 
             
                      @connections.delete(connection)
         | 
| 157 | 
            -
                       | 
| 155 | 
            +
                      # This loop_time passed to the exception is bogus. Ideally we would pass the total
         | 
| 156 | 
            +
                      # resolve timeout, including from the previous retries.
         | 
| 157 | 
            +
                      raise ResolveTimeoutError.new(loop_time, "Timed out")
         | 
| 158 | 
            +
                      # raise NativeResolveError.new(connection, host)
         | 
| 158 159 | 
             
                    else
         | 
| 160 | 
            +
                      log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
         | 
| 159 161 | 
             
                      connections << connection
         | 
| 160 | 
            -
                       | 
| 162 | 
            +
                      queries[h] = connection
         | 
| 161 163 | 
             
                    end
         | 
| 162 164 | 
             
                  end
         | 
| 163 165 | 
             
                  @queries = queries
         | 
| 164 166 | 
             
                  connections.each { |ch| resolve(ch) }
         | 
| 165 167 | 
             
                end
         | 
| 166 168 |  | 
| 167 | 
            -
                def dread(wsize = @resolver_options | 
| 169 | 
            +
                def dread(wsize = @resolver_options[:packet_size])
         | 
| 168 170 | 
             
                  loop do
         | 
| 169 171 | 
             
                    siz = @io.read(wsize, @read_buffer)
         | 
| 170 172 | 
             
                    return unless siz && siz.positive?
         | 
| @@ -199,13 +201,14 @@ module HTTPX | |
| 199 201 | 
             
                    end
         | 
| 200 202 | 
             
                  end
         | 
| 201 203 |  | 
| 202 | 
            -
                  if addresses.empty?
         | 
| 204 | 
            +
                  if addresses.nil? || addresses.empty?
         | 
| 203 205 | 
             
                    hostname, connection = @queries.first
         | 
| 204 206 | 
             
                    @_record_types[hostname].shift
         | 
| 205 207 | 
             
                    if @_record_types[hostname].empty?
         | 
| 206 208 | 
             
                      @queries.delete(hostname)
         | 
| 207 209 | 
             
                      @_record_types.delete(hostname)
         | 
| 208 210 | 
             
                      @connections.delete(connection)
         | 
| 211 | 
            +
             | 
| 209 212 | 
             
                      raise NativeResolveError.new(connection, hostname)
         | 
| 210 213 | 
             
                    end
         | 
| 211 214 | 
             
                  else
         | 
| @@ -223,7 +226,7 @@ module HTTPX | |
| 223 226 | 
             
                      end
         | 
| 224 227 | 
             
                    else
         | 
| 225 228 | 
             
                      @connections.delete(connection)
         | 
| 226 | 
            -
                      Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options | 
| 229 | 
            +
                      Resolver.cached_lookup_set(connection.origin.host, addresses) if @resolver_options[:cache]
         | 
| 227 230 | 
             
                      emit_addresses(connection, addresses.map { |addr| addr["data"] })
         | 
| 228 231 | 
             
                    end
         | 
| 229 232 | 
             
                  end
         | 
| @@ -243,7 +246,7 @@ module HTTPX | |
| 243 246 | 
             
                    log { "resolver: resolve IDN #{connection.origin.non_ascii_hostname} as #{hostname}" } if connection.origin.non_ascii_hostname
         | 
| 244 247 | 
             
                  end
         | 
| 245 248 | 
             
                  @queries[hostname] = connection
         | 
| 246 | 
            -
                  type = @_record_types[hostname].first
         | 
| 249 | 
            +
                  type = @_record_types[hostname].first || "A"
         | 
| 247 250 | 
             
                  log { "resolver: query #{type} for #{hostname}" }
         | 
| 248 251 | 
             
                  begin
         | 
| 249 252 | 
             
                    @write_buffer << Resolver.encode_dns_query(hostname, type: RECORD_TYPES[type])
         | 
| @@ -280,7 +283,7 @@ module HTTPX | |
| 280 283 | 
             
                    @io.connect
         | 
| 281 284 | 
             
                    return unless @io.connected?
         | 
| 282 285 |  | 
| 283 | 
            -
                    resolve if @queries.empty?
         | 
| 286 | 
            +
                    resolve if @queries.empty? && !@connections.empty?
         | 
| 284 287 | 
             
                  when :closed
         | 
| 285 288 | 
             
                    return unless @state == :open
         | 
| 286 289 |  | 
| @@ -38,7 +38,7 @@ module HTTPX | |
| 38 38 | 
             
                  def early_resolve(connection, hostname: connection.origin.host)
         | 
| 39 39 | 
             
                    addresses = connection.addresses ||
         | 
| 40 40 | 
             
                                ip_resolve(hostname) ||
         | 
| 41 | 
            -
                                (@resolver_options | 
| 41 | 
            +
                                (@resolver_options[:cache] && Resolver.cached_lookup(hostname)) ||
         | 
| 42 42 | 
             
                                system_resolve(hostname)
         | 
| 43 43 | 
             
                    return unless addresses
         | 
| 44 44 |  | 
| @@ -57,11 +57,13 @@ module HTTPX | |
| 57 57 | 
             
                    ips.map { |ip| IPAddr.new(ip) }
         | 
| 58 58 | 
             
                  end
         | 
| 59 59 |  | 
| 60 | 
            -
                  def emit_resolve_error(connection, hostname, ex = nil)
         | 
| 60 | 
            +
                  def emit_resolve_error(connection, hostname = connection.origin.host, ex = nil)
         | 
| 61 61 | 
             
                    emit(:error, connection, resolve_error(hostname, ex))
         | 
| 62 62 | 
             
                  end
         | 
| 63 63 |  | 
| 64 64 | 
             
                  def resolve_error(hostname, ex = nil)
         | 
| 65 | 
            +
                    return ex if ex.is_a?(ResolveError)
         | 
| 66 | 
            +
             | 
| 65 67 | 
             
                    message = ex ? ex.message : "Can't resolve #{hostname}"
         | 
| 66 68 | 
             
                    error = ResolveError.new(message)
         | 
| 67 69 | 
             
                    error.set_backtrace(ex ? ex.backtrace : caller)
         | 
| @@ -14,13 +14,13 @@ module HTTPX | |
| 14 14 |  | 
| 15 15 | 
             
                def initialize(options)
         | 
| 16 16 | 
             
                  @options = Options.new(options)
         | 
| 17 | 
            -
                  @resolver_options =  | 
| 17 | 
            +
                  @resolver_options = @options.resolver_options
         | 
| 18 18 | 
             
                  @state = :idle
         | 
| 19 | 
            -
                  resolv_options = @resolver_options. | 
| 19 | 
            +
                  resolv_options = @resolver_options.dup
         | 
| 20 20 | 
             
                  timeouts = resolv_options.delete(:timeouts)
         | 
| 21 21 | 
             
                  resolv_options.delete(:cache)
         | 
| 22 22 | 
             
                  @resolver = Resolv::DNS.new(resolv_options.empty? ? nil : resolv_options)
         | 
| 23 | 
            -
                  @resolver.timeouts = timeouts  | 
| 23 | 
            +
                  @resolver.timeouts = timeouts || Resolver::RESOLVE_TIMEOUT
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 26 | 
             
                def closed?
         | 
    
        data/lib/httpx/selector.rb
    CHANGED
    
    | @@ -4,19 +4,14 @@ require "io/wait" | |
| 4 4 |  | 
| 5 5 | 
             
            module IOExtensions
         | 
| 6 6 | 
             
              refine IO do
         | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
                    return unless r || w
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                    self
         | 
| 19 | 
            -
                  end
         | 
| 7 | 
            +
                # provides a fallback for rubies where IO#wait isn't implemented,
         | 
| 8 | 
            +
                # but IO#wait_readable and IO#wait_writable are.
         | 
| 9 | 
            +
                def wait(timeout = nil, _mode = :read_write)
         | 
| 10 | 
            +
                  r, w = IO.select([self], [self], nil, timeout)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  return unless r || w
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  self
         | 
| 20 15 | 
             
                end
         | 
| 21 16 | 
             
              end
         | 
| 22 17 | 
             
            end
         | 
| @@ -122,6 +117,7 @@ class HTTPX::Selector | |
| 122 117 | 
             
                yield io
         | 
| 123 118 | 
             
              rescue IOError, SystemCallError
         | 
| 124 119 | 
             
                @selectables.reject!(&:closed?)
         | 
| 120 | 
            +
                raise unless @selectables.empty?
         | 
| 125 121 | 
             
              end
         | 
| 126 122 |  | 
| 127 123 | 
             
              def select(interval, &block)
         | 
    
        data/lib/httpx/session.rb
    CHANGED
    
    | @@ -41,7 +41,7 @@ module HTTPX | |
| 41 41 | 
             
                def build_request(verb, uri, options = EMPTY_HASH)
         | 
| 42 42 | 
             
                  rklass = @options.request_class
         | 
| 43 43 | 
             
                  request = rklass.new(verb, uri, @options.merge(options).merge(persistent: @persistent))
         | 
| 44 | 
            -
                  request.on(:response, &method(:on_response).curry[request])
         | 
| 44 | 
            +
                  request.on(:response, &method(:on_response).curry(2)[request])
         | 
| 45 45 | 
             
                  request.on(:promise, &method(:on_promise))
         | 
| 46 46 | 
             
                  request
         | 
| 47 47 | 
             
                end
         | 
| @@ -77,10 +77,16 @@ module HTTPX | |
| 77 77 | 
             
                end
         | 
| 78 78 |  | 
| 79 79 | 
             
                def set_connection_callbacks(connection, connections, options)
         | 
| 80 | 
            -
                  connection.on(: | 
| 81 | 
            -
                    other_connection =  | 
| 80 | 
            +
                  connection.on(:misdirected) do |misdirected_request|
         | 
| 81 | 
            +
                    other_connection = connection.create_idle(ssl: { alpn_protocols: %w[http/1.1] })
         | 
| 82 | 
            +
                    other_connection.merge(connection)
         | 
| 83 | 
            +
                    catch(:coalesced) do
         | 
| 84 | 
            +
                      pool.init_connection(other_connection, options)
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
                    set_connection_callbacks(other_connection, connections, options)
         | 
| 82 87 | 
             
                    connections << other_connection
         | 
| 83 | 
            -
                     | 
| 88 | 
            +
                    misdirected_request.transition(:idle)
         | 
| 89 | 
            +
                    other_connection.send(misdirected_request)
         | 
| 84 90 | 
             
                  end
         | 
| 85 91 | 
             
                  connection.on(:altsvc) do |alt_origin, origin, alt_params|
         | 
| 86 92 | 
             
                    other_connection = build_altsvc_connection(connection, connections, alt_origin, origin, alt_params, options)
         | 
| @@ -130,23 +136,20 @@ module HTTPX | |
| 130 136 | 
             
                def build_requests(*args, options)
         | 
| 131 137 | 
             
                  request_options = @options.merge(options)
         | 
| 132 138 |  | 
| 133 | 
            -
                  requests =  | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
                               end
         | 
| 148 | 
            -
                             else
         | 
| 149 | 
            -
                               raise ArgumentError, "unsupported number of arguments"
         | 
| 139 | 
            +
                  requests = if args.size == 1
         | 
| 140 | 
            +
                    reqs = args.first
         | 
| 141 | 
            +
                    reqs.map do |verb, uri, opts = EMPTY_HASH|
         | 
| 142 | 
            +
                      build_request(verb, uri, request_options.merge(opts))
         | 
| 143 | 
            +
                    end
         | 
| 144 | 
            +
                  else
         | 
| 145 | 
            +
                    verb, uris = args
         | 
| 146 | 
            +
                    if uris.respond_to?(:each)
         | 
| 147 | 
            +
                      uris.enum_for(:each).map do |uri, opts = EMPTY_HASH|
         | 
| 148 | 
            +
                        build_request(verb, uri, request_options.merge(opts))
         | 
| 149 | 
            +
                      end
         | 
| 150 | 
            +
                    else
         | 
| 151 | 
            +
                      [build_request(verb, uris, request_options)]
         | 
| 152 | 
            +
                    end
         | 
| 150 153 | 
             
                  end
         | 
| 151 154 | 
             
                  raise ArgumentError, "wrong number of URIs (given 0, expect 1..+1)" if requests.empty?
         | 
| 152 155 |  | 
    
        data/lib/httpx/transcoder.rb
    CHANGED
    
    | @@ -3,6 +3,26 @@ | |
| 3 3 | 
             
            module HTTPX
         | 
| 4 4 | 
             
              module Transcoder
         | 
| 5 5 | 
             
                extend Registry
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def self.normalize_keys(key, value, cond = nil, &block)
         | 
| 8 | 
            +
                  if (cond && cond.call(value))
         | 
| 9 | 
            +
                    block.call(key.to_s, value)
         | 
| 10 | 
            +
                  elsif value.respond_to?(:to_ary)
         | 
| 11 | 
            +
                    if value.empty?
         | 
| 12 | 
            +
                      block.call("#{key}[]")
         | 
| 13 | 
            +
                    else
         | 
| 14 | 
            +
                      value.to_ary.each do |element|
         | 
| 15 | 
            +
                        normalize_keys("#{key}[]", element, cond, &block)
         | 
| 16 | 
            +
                      end
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  elsif value.respond_to?(:to_hash)
         | 
| 19 | 
            +
                    value.to_hash.each do |child_key, child_value|
         | 
| 20 | 
            +
                      normalize_keys("#{key}[#{child_key}]", child_value, cond, &block)
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    block.call(key.to_s, value)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 6 26 | 
             
              end
         | 
| 7 27 | 
             
            end
         | 
| 8 28 |  | 
| @@ -12,10 +12,18 @@ module HTTPX::Transcoder | |
| 12 12 |  | 
| 13 13 | 
             
                  def_delegator :@raw, :to_s
         | 
| 14 14 |  | 
| 15 | 
            +
                  def_delegator :@raw, :to_str
         | 
| 16 | 
            +
             | 
| 15 17 | 
             
                  def_delegator :@raw, :bytesize
         | 
| 16 18 |  | 
| 17 19 | 
             
                  def initialize(form)
         | 
| 18 | 
            -
                    @raw =  | 
| 20 | 
            +
                    @raw = form.each_with_object("".b) do |(key, val), buf|
         | 
| 21 | 
            +
                      HTTPX::Transcoder.normalize_keys(key, val) do |k, v|
         | 
| 22 | 
            +
                        buf << "&" unless buf.empty?
         | 
| 23 | 
            +
                        buf << URI.encode_www_form_component(k)
         | 
| 24 | 
            +
                        buf << "=#{URI.encode_www_form_component(v.to_s)}" unless v.nil?
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                    end
         | 
| 19 27 | 
             
                  end
         | 
| 20 28 |  | 
| 21 29 | 
             
                  def content_type
         |