httpx 0.21.0 → 0.22.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +53 -35
  3. data/doc/release_notes/0_10_0.md +2 -2
  4. data/doc/release_notes/0_11_0.md +3 -5
  5. data/doc/release_notes/0_12_0.md +5 -5
  6. data/doc/release_notes/0_13_0.md +4 -4
  7. data/doc/release_notes/0_14_0.md +2 -2
  8. data/doc/release_notes/0_16_0.md +3 -3
  9. data/doc/release_notes/0_17_0.md +1 -1
  10. data/doc/release_notes/0_18_0.md +4 -4
  11. data/doc/release_notes/0_18_2.md +1 -1
  12. data/doc/release_notes/0_19_0.md +1 -1
  13. data/doc/release_notes/0_20_0.md +1 -1
  14. data/doc/release_notes/0_21_0.md +7 -5
  15. data/doc/release_notes/0_21_1.md +12 -0
  16. data/doc/release_notes/0_22_0.md +13 -0
  17. data/doc/release_notes/0_22_1.md +11 -0
  18. data/doc/release_notes/0_22_2.md +5 -0
  19. data/doc/release_notes/0_22_3.md +55 -0
  20. data/doc/release_notes/0_22_4.md +6 -0
  21. data/lib/httpx/adapters/datadog.rb +1 -1
  22. data/lib/httpx/adapters/faraday.rb +12 -4
  23. data/lib/httpx/adapters/sentry.rb +6 -2
  24. data/lib/httpx/connection/http2.rb +1 -1
  25. data/lib/httpx/connection.rb +34 -6
  26. data/lib/httpx/errors.rb +2 -0
  27. data/lib/httpx/extensions.rb +10 -1
  28. data/lib/httpx/io/tcp.rb +2 -1
  29. data/lib/httpx/io/udp.rb +4 -5
  30. data/lib/httpx/options.rb +2 -2
  31. data/lib/httpx/plugins/authentication.rb +1 -1
  32. data/lib/httpx/plugins/aws_sigv4.rb +2 -2
  33. data/lib/httpx/plugins/basic_authentication.rb +1 -1
  34. data/lib/httpx/plugins/circuit_breaker/circuit.rb +1 -1
  35. data/lib/httpx/plugins/circuit_breaker.rb +1 -1
  36. data/lib/httpx/plugins/compression/gzip.rb +1 -1
  37. data/lib/httpx/plugins/compression.rb +4 -4
  38. data/lib/httpx/plugins/cookies.rb +1 -1
  39. data/lib/httpx/plugins/digest_authentication.rb +3 -1
  40. data/lib/httpx/plugins/expect.rb +4 -3
  41. data/lib/httpx/plugins/follow_redirects.rb +8 -1
  42. data/lib/httpx/plugins/grpc/message.rb +1 -1
  43. data/lib/httpx/plugins/grpc.rb +1 -1
  44. data/lib/httpx/plugins/h2c.rb +1 -1
  45. data/lib/httpx/plugins/multipart/decoder.rb +7 -57
  46. data/lib/httpx/plugins/multipart.rb +2 -2
  47. data/lib/httpx/plugins/ntlm_authentication.rb +3 -1
  48. data/lib/httpx/plugins/persistent.rb +1 -1
  49. data/lib/httpx/plugins/proxy/http.rb +4 -2
  50. data/lib/httpx/plugins/proxy.rb +1 -1
  51. data/lib/httpx/plugins/push_promise.rb +1 -1
  52. data/lib/httpx/plugins/rate_limiter.rb +3 -1
  53. data/lib/httpx/plugins/response_cache.rb +1 -1
  54. data/lib/httpx/plugins/retries.rb +3 -2
  55. data/lib/httpx/plugins/stream.rb +0 -2
  56. data/lib/httpx/plugins/upgrade.rb +3 -1
  57. data/lib/httpx/plugins/webdav.rb +2 -0
  58. data/lib/httpx/pool.rb +41 -2
  59. data/lib/httpx/request.rb +1 -1
  60. data/lib/httpx/resolver/https.rb +16 -2
  61. data/lib/httpx/resolver/native.rb +28 -26
  62. data/lib/httpx/resolver/resolver.rb +9 -8
  63. data/lib/httpx/resolver.rb +8 -0
  64. data/lib/httpx/response.rb +8 -0
  65. data/lib/httpx/transcoder/xml.rb +0 -2
  66. data/lib/httpx/transcoder.rb +1 -1
  67. data/lib/httpx/utils.rb +30 -0
  68. data/lib/httpx/version.rb +1 -1
  69. data/lib/httpx.rb +6 -0
  70. data/sig/connection.rbs +3 -1
  71. data/sig/plugins/multipart.rbs +0 -2
  72. data/sig/pool.rbs +3 -1
  73. data/sig/resolver/https.rbs +3 -2
  74. data/sig/resolver/native.rbs +2 -1
  75. data/sig/resolver/resolver.rbs +3 -1
  76. data/sig/resolver.rbs +1 -1
  77. data/sig/response.rbs +4 -1
  78. data/sig/utils.rbs +2 -0
  79. metadata +21 -9
@@ -63,7 +63,11 @@ module HTTPX::Plugins
63
63
 
64
64
  request_info = extract_request_info(req)
65
65
  sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
66
- sentry_span.set_data(:status, res.status)
66
+ if res.is_a?(HTTPX::ErrorResponse)
67
+ sentry_span.set_data(:error, res.message)
68
+ else
69
+ sentry_span.set_data(:status, res.status)
70
+ end
67
71
  sentry_span.set_timestamp(::Sentry.utc_now.to_f)
68
72
  end
69
73
 
@@ -95,7 +99,7 @@ module HTTPX::Plugins
95
99
  end
96
100
 
97
101
  Sentry.register_patch do
98
- sentry_session = ::HTTPX.plugin(HTTPX::Plugins::Sentry)
102
+ sentry_session = HTTPX.plugin(HTTPX::Plugins::Sentry)
99
103
 
100
104
  HTTPX.send(:remove_const, :Session)
101
105
  HTTPX.send(:const_set, :Session, sentry_session.class)
@@ -365,7 +365,7 @@ module HTTPX
365
365
  ex.set_backtrace(caller)
366
366
  handle_error(ex)
367
367
  end
368
- return unless is_connection_closed && @streams.size.zero?
368
+ return unless is_connection_closed && @streams.empty?
369
369
 
370
370
  emit(:close, is_connection_closed)
371
371
  end
@@ -45,10 +45,12 @@ module HTTPX
45
45
 
46
46
  def_delegator :@write_buffer, :empty?
47
47
 
48
- attr_reader :io, :origin, :origins, :state, :pending, :options
48
+ attr_reader :type, :io, :origin, :origins, :state, :pending, :options
49
49
 
50
50
  attr_writer :timers
51
51
 
52
+ attr_accessor :family
53
+
52
54
  def initialize(type, uri, options)
53
55
  @type = type
54
56
  @origins = [uri.origin]
@@ -114,7 +116,10 @@ module HTTPX
114
116
 
115
117
  return false unless connection.addresses
116
118
 
117
- !(@io.addresses & connection.addresses).empty? && @options == connection.options
119
+ (
120
+ (open? && @origin == connection.origin) ||
121
+ !(@io.addresses & connection.addresses).empty?
122
+ ) && @options == connection.options
118
123
  end
119
124
 
120
125
  # coalescable connections need to be mergeable!
@@ -219,6 +224,14 @@ module HTTPX
219
224
  @parser.close if @parser
220
225
  end
221
226
 
227
+ # bypasses the state machine to force closing of connections still connecting.
228
+ # **only** used for Happy Eyeballs v2.
229
+ def force_reset
230
+ @state = :closing
231
+ transition(:closed)
232
+ emit(:close)
233
+ end
234
+
222
235
  def reset
223
236
  transition(:closing)
224
237
  transition(:closed)
@@ -309,7 +322,7 @@ module HTTPX
309
322
  # * the number of inflight requests
310
323
  # * the number of pending requests
311
324
  # * whether the write buffer has bytes (i.e. for close handshake)
312
- if @pending.size.zero? && @inflight.zero? && @write_buffer.empty?
325
+ if @pending.empty? && @inflight.zero? && @write_buffer.empty?
313
326
  log(level: 3) { "NO MORE REQUESTS..." }
314
327
  return
315
328
  end
@@ -353,7 +366,7 @@ module HTTPX
353
366
  break if @state == :closing || @state == :closed
354
367
 
355
368
  # exit #consume altogether if all outstanding requests have been dealt with
356
- return if @pending.size.zero? && @inflight.zero?
369
+ return if @pending.empty? && @inflight.zero?
357
370
  end unless ((ints = interests).nil? || ints == :w || @state == :closing) && !epiped
358
371
 
359
372
  #
@@ -512,10 +525,23 @@ module HTTPX
512
525
 
513
526
  def transition(nextstate)
514
527
  handle_transition(nextstate)
515
- rescue Errno::ECONNREFUSED,
528
+ rescue Errno::ECONNABORTED,
529
+ Errno::ECONNREFUSED,
530
+ Errno::ECONNRESET,
516
531
  Errno::EADDRNOTAVAIL,
517
532
  Errno::EHOSTUNREACH,
518
- TLSError => e
533
+ Errno::EINVAL,
534
+ Errno::ENETUNREACH,
535
+ Errno::EPIPE,
536
+ Errno::ENOENT,
537
+ SocketError => e
538
+ # connect errors, exit gracefully
539
+ error = ConnectionError.new(e.message)
540
+ error.set_backtrace(e.backtrace)
541
+ connecting? && callbacks(:connect_error).any? ? emit(:connect_error, error) : handle_error(error)
542
+ @state = :closed
543
+ emit(:close)
544
+ rescue TLSError => e
519
545
  # connect errors, exit gracefully
520
546
  handle_error(e)
521
547
  @state = :closed
@@ -531,6 +557,8 @@ module HTTPX
531
557
  return if @state == :closed
532
558
 
533
559
  @io.connect
560
+ emit(:tcp_open, self) if @io.state == :connected
561
+
534
562
  return unless @io.connected?
535
563
 
536
564
  @connected_at = Utils.now
data/lib/httpx/errors.rb CHANGED
@@ -5,6 +5,8 @@ module HTTPX
5
5
 
6
6
  class UnsupportedSchemeError < Error; end
7
7
 
8
+ class ConnectionError < Error; end
9
+
8
10
  class TimeoutError < Error
9
11
  attr_reader :timeout
10
12
 
@@ -55,6 +55,7 @@ module HTTPX
55
55
  end
56
56
 
57
57
  module NumericExtensions
58
+ # Ruby 2.4 backport
58
59
  refine Numeric do
59
60
  def infinite?
60
61
  self == Float::INFINITY
@@ -64,6 +65,7 @@ module HTTPX
64
65
 
65
66
  module StringExtensions
66
67
  refine String do
68
+ # Ruby 2.5 backport
67
69
  def delete_suffix!(suffix)
68
70
  suffix = Backports.coerce_to_str(suffix)
69
71
  chomp! if frozen?
@@ -80,6 +82,7 @@ module HTTPX
80
82
 
81
83
  module HashExtensions
82
84
  refine Hash do
85
+ # Ruby 2.4 backport
83
86
  def compact
84
87
  h = {}
85
88
  each do |key, value|
@@ -93,7 +96,7 @@ module HTTPX
93
96
  module ArrayExtensions
94
97
  module FilterMap
95
98
  refine Array do
96
-
99
+ # Ruby 2.7 backport
97
100
  def filter_map
98
101
  return to_enum(:filter_map) unless block_given?
99
102
 
@@ -107,6 +110,7 @@ module HTTPX
107
110
 
108
111
  module Sum
109
112
  refine Array do
113
+ # Ruby 2.6 backport
110
114
  def sum(accumulator = 0, &block)
111
115
  values = block_given? ? map(&block) : self
112
116
  values.inject(accumulator, :+)
@@ -116,6 +120,7 @@ module HTTPX
116
120
 
117
121
  module Intersect
118
122
  refine Array do
123
+ # Ruby 3.1 backport
119
124
  def intersect?(arr)
120
125
  if size < arr.size
121
126
  smaller = self
@@ -130,6 +135,7 @@ module HTTPX
130
135
 
131
136
  module IOExtensions
132
137
  refine IO do
138
+ # Ruby 2.3 backport
133
139
  # provides a fallback for rubies where IO#wait isn't implemented,
134
140
  # but IO#wait_readable and IO#wait_writable are.
135
141
  def wait(timeout = nil, _mode = :read_write)
@@ -144,6 +150,7 @@ module HTTPX
144
150
 
145
151
  module RegexpExtensions
146
152
  refine(Regexp) do
153
+ # Ruby 2.4 backport
147
154
  def match?(*args)
148
155
  !match(*args).nil?
149
156
  end
@@ -151,7 +158,9 @@ module HTTPX
151
158
  end
152
159
 
153
160
  module URIExtensions
161
+ # uri 0.11 backport, ships with ruby 3.1
154
162
  refine URI::Generic do
163
+
155
164
  def non_ascii_hostname
156
165
  @non_ascii_hostname
157
166
  end
data/lib/httpx/io/tcp.rb CHANGED
@@ -74,7 +74,8 @@ module HTTPX
74
74
  try_connect
75
75
  rescue Errno::ECONNREFUSED,
76
76
  Errno::EADDRNOTAVAIL,
77
- Errno::EHOSTUNREACH => e
77
+ Errno::EHOSTUNREACH,
78
+ SocketError => e
78
79
  raise e if @ip_index <= 0
79
80
 
80
81
  log { "failed connecting to #{@ip} (#{e.message}), trying next..." }
data/lib/httpx/io/udp.rb CHANGED
@@ -6,11 +6,10 @@ module HTTPX
6
6
  class UDP
7
7
  include Loggable
8
8
 
9
- def initialize(uri, _, options)
10
- ip = IPAddr.new(uri.host)
11
- @host = ip.to_s
12
- @port = uri.port
13
- @io = UDPSocket.new(ip.family)
9
+ def initialize(ip, port, options)
10
+ @host = ip
11
+ @port = port
12
+ @io = UDPSocket.new(IPAddr.new(ip).family)
14
13
  @options = options
15
14
  end
16
15
 
data/lib/httpx/options.rb CHANGED
@@ -15,7 +15,7 @@ module HTTPX
15
15
  # https://github.com/ruby/resolv/blob/095f1c003f6073730500f02acbdbc55f83d70987/lib/resolv.rb#L408
16
16
  ip_address_families = begin
17
17
  list = Socket.ip_address_list
18
- if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? }
18
+ if list.any? { |a| a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal? && !a.ipv6_unique_local? }
19
19
  [Socket::AF_INET6, Socket::AF_INET]
20
20
  else
21
21
  [Socket::AF_INET]
@@ -100,7 +100,7 @@ module HTTPX
100
100
  end
101
101
 
102
102
  def def_option(optname, *args, &block)
103
- if args.size.zero? && !block
103
+ if args.empty? && !block
104
104
  class_eval(<<-OUT, __FILE__, __LINE__ + 1)
105
105
  def option_#{optname}(v); v; end # def option_smth(v); v; end
106
106
  OUT
@@ -6,7 +6,7 @@ module HTTPX
6
6
  # This plugin adds a shim +authentication+ method to the session, which will fill
7
7
  # the HTTP Authorization header.
8
8
  #
9
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#authentication
9
+ # https://gitlab.com/os85/httpx/wikis/Authentication#authentication
10
10
  #
11
11
  module Authentication
12
12
  module InstanceMethods
@@ -7,7 +7,7 @@ module HTTPX
7
7
  #
8
8
  # https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
9
9
  #
10
- # https://gitlab.com/honeyryderchuck/httpx/wikis/AWS-SigV4
10
+ # https://gitlab.com/os85/httpx/wikis/AWS-SigV4
11
11
  #
12
12
  module AWSSigV4
13
13
  Credentials = Struct.new(:username, :password, :security_token)
@@ -115,7 +115,7 @@ module HTTPX
115
115
  elsif value.respond_to?(:each)
116
116
  digest = OpenSSL::Digest.new(@algorithm)
117
117
 
118
- mb_buffer = value.each.each_with_object("".b) do |chunk, buffer|
118
+ mb_buffer = value.each.with_object("".b) do |chunk, buffer|
119
119
  buffer << chunk
120
120
  break if buffer.bytesize >= 1024 * 1024
121
121
  end
@@ -5,7 +5,7 @@ module HTTPX
5
5
  #
6
6
  # This plugin adds helper methods to implement HTTP Basic Auth (https://tools.ietf.org/html/rfc7617)
7
7
  #
8
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#basic-authentication
8
+ # https://gitlab.com/os85/httpx/wikis/Authentication#basic-authentication
9
9
  #
10
10
  module BasicAuth
11
11
  class << self
@@ -28,7 +28,7 @@ module HTTPX
28
28
  nil
29
29
  when :half_open
30
30
  # return nothing or smth based on ratio
31
- return if Random::DEFAULT.rand >= @circuit_breaker_half_open_drip_rate
31
+ return if Random.rand >= @circuit_breaker_half_open_drip_rate
32
32
 
33
33
  @response
34
34
  when :open
@@ -5,7 +5,7 @@ module HTTPX
5
5
  #
6
6
  # This plugin implements a circuit breaker around connection errors.
7
7
  #
8
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Circuit-Breaker
8
+ # https://gitlab.com/os85/httpx/wikis/Circuit-Breaker
9
9
  #
10
10
  module CircuitBreaker
11
11
  using URIExtensions
@@ -56,7 +56,7 @@ module HTTPX
56
56
 
57
57
  class Inflater
58
58
  def initialize(bytesize)
59
- @inflater = Zlib::Inflate.new(32 + Zlib::MAX_WBITS)
59
+ @inflater = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
60
60
  @bytesize = bytesize
61
61
  @buffer = nil
62
62
  end
@@ -10,7 +10,7 @@ module HTTPX
10
10
  #
11
11
  # It supports both *gzip* and *deflate*.
12
12
  #
13
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Compression
13
+ # https://gitlab.com/os85/httpx/wikis/Compression
14
14
  #
15
15
  module Compression
16
16
  class << self
@@ -30,7 +30,7 @@ module HTTPX
30
30
  module OptionsMethods
31
31
  def option_compression_threshold_size(value)
32
32
  bytes = Integer(value)
33
- raise TypeError, ":expect_threshold_size must be positive" unless bytes.positive?
33
+ raise TypeError, ":compression_threshold_size must be positive" unless bytes.positive?
34
34
 
35
35
  bytes
36
36
  end
@@ -138,7 +138,7 @@ module HTTPX
138
138
  def each(&blk)
139
139
  return enum_for(__method__) unless blk
140
140
 
141
- return deflate(&blk) if @buffer.size.zero?
141
+ return deflate(&blk) if @buffer.size.zero? # rubocop:disable Style/ZeroLengthPredicate
142
142
 
143
143
  @buffer.rewind
144
144
  @buffer.each(&blk)
@@ -152,7 +152,7 @@ module HTTPX
152
152
  private
153
153
 
154
154
  def deflate(&blk)
155
- return unless @buffer.size.zero?
155
+ return unless @buffer.size.zero? # rubocop:disable Style/ZeroLengthPredicate
156
156
 
157
157
  @body.rewind
158
158
  @deflater.deflate(@body, @buffer, chunk_size: 16_384, &blk)
@@ -9,7 +9,7 @@ module HTTPX
9
9
  #
10
10
  # It also adds a *#cookies* helper, so that you can pre-fill the cookies of a session.
11
11
  #
12
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Cookies
12
+ # https://gitlab.com/os85/httpx/wikis/Cookies
13
13
  #
14
14
  module Cookies
15
15
  def self.load_dependencies(*)
@@ -5,7 +5,7 @@ module HTTPX
5
5
  #
6
6
  # This plugin adds helper methods to implement HTTP Digest Auth (https://tools.ietf.org/html/rfc7616)
7
7
  #
8
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#authentication
8
+ # https://gitlab.com/os85/httpx/wikis/Authentication#authentication
9
9
  #
10
10
  module DigestAuth
11
11
  DigestError = Class.new(Error)
@@ -46,6 +46,8 @@ module HTTPX
46
46
 
47
47
  probe_response = wrap { super(request).first }
48
48
 
49
+ return probe_response unless probe_response.is_a?(Response)
50
+
49
51
  if probe_response.status == 401 && digest.can_authenticate?(probe_response.headers["www-authenticate"])
50
52
  request.transition(:idle)
51
53
  request.headers["authorization"] = digest.authenticate(request, probe_response.headers["www-authenticate"])
@@ -5,7 +5,7 @@ module HTTPX
5
5
  #
6
6
  # This plugin makes all HTTP/1.1 requests with a body send the "Expect: 100-continue".
7
7
  #
8
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Expect#expect
8
+ # https://gitlab.com/os85/httpx/wikis/Expect#expect
9
9
  #
10
10
  module Expect
11
11
  EXPECT_TIMEOUT = 2
@@ -50,7 +50,8 @@ module HTTPX
50
50
  end
51
51
 
52
52
  def response=(response)
53
- if response && response.status == 100 &&
53
+ if response.is_a?(Response) &&
54
+ response.status == 100 &&
54
55
  !@headers.key?("expect") &&
55
56
  (@state == :body || @state == :done)
56
57
 
@@ -92,7 +93,7 @@ module HTTPX
92
93
  response = @responses.delete(request)
93
94
  return unless response
94
95
 
95
- if response.status == 417 && request.headers.key?("expect")
96
+ if response.is_a?(Response) && response.status == 417 && request.headers.key?("expect")
96
97
  response.close
97
98
  request.headers.delete("expect")
98
99
  request.transition(:idle)
@@ -11,7 +11,7 @@ module HTTPX
11
11
  #
12
12
  # It also doesn't follow insecure redirects (https -> http) by default (see *follow_insecure_redirects*).
13
13
  #
14
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Follow-Redirects
14
+ # https://gitlab.com/os85/httpx/wikis/Follow-Redirects
15
15
  #
16
16
  module FollowRedirects
17
17
  MAX_REDIRECTS = 3
@@ -44,6 +44,7 @@ module HTTPX
44
44
 
45
45
  max_redirects = redirect_request.max_redirects
46
46
 
47
+ return response unless response.is_a?(Response)
47
48
  return response unless REDIRECT_STATUS.include?(response.status) && response.headers.key?("location")
48
49
  return response unless max_redirects.positive?
49
50
 
@@ -121,6 +122,12 @@ module HTTPX
121
122
  @redirect_request || self
122
123
  end
123
124
 
125
+ def response
126
+ return super unless @redirect_request
127
+
128
+ @redirect_request.response
129
+ end
130
+
124
131
  def max_redirects
125
132
  @options.max_redirects || MAX_REDIRECTS
126
133
  end
@@ -57,7 +57,7 @@ module HTTPX
57
57
 
58
58
  yield data
59
59
 
60
- message = message.byteslice((5 + size)..-1)
60
+ message = message.byteslice((size + 5)..-1)
61
61
  end
62
62
  end
63
63
 
@@ -16,7 +16,7 @@ module HTTPX
16
16
  #
17
17
  # This plugin adds DSL to build GRPC interfaces.
18
18
  #
19
- # https://gitlab.com/honeyryderchuck/httpx/wikis/GRPC
19
+ # https://gitlab.com/os85/httpx/wikis/GRPC
20
20
  #
21
21
  module GRPC
22
22
  unless String.method_defined?(:underscore)
@@ -6,7 +6,7 @@ module HTTPX
6
6
  # This plugin adds support for upgrading a plaintext HTTP/1.1 connection to HTTP/2
7
7
  # (https://tools.ietf.org/html/rfc7540#section-3.2)
8
8
  #
9
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Upgrade#h2c
9
+ # https://gitlab.com/os85/httpx/wikis/Upgrade#h2c
10
10
  #
11
11
  module H2C
12
12
  VALID_H2C_VERBS = %i[get options head].freeze
@@ -5,10 +5,6 @@ require "delegate"
5
5
 
6
6
  module HTTPX::Plugins
7
7
  module Multipart
8
- using HTTPX::RegexpExtensions unless Regexp.method_defined?(:match?)
9
-
10
- CRLF = "\r\n"
11
-
12
8
  class FilePart < SimpleDelegator
13
9
  attr_reader :original_filename, :content_type
14
10
 
@@ -20,32 +16,14 @@ module HTTPX::Plugins
20
16
  end
21
17
  end
22
18
 
23
- TOKEN = %r{[^\s()<>,;:\\"/\[\]?=]+}.freeze
24
- VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/.freeze
25
- CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i.freeze
26
- BROKEN_QUOTED = /^#{CONDISP}.*;\s*filename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i.freeze
27
- BROKEN_UNQUOTED = /^#{CONDISP}.*;\s*filename=(#{TOKEN})/i.freeze
28
- MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{CRLF}/ni.freeze
29
- MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni.freeze
30
- MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{CRLF}]*)/ni.freeze
31
- # Updated definitions from RFC 2231
32
- ATTRIBUTE_CHAR = %r{[^ \t\v\n\r)(><@,;:\\"/\[\]?='*%]}.freeze
33
- ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/.freeze
34
- SECTION = /\*[0-9]+/.freeze
35
- REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/.freeze
36
- REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/.freeze
37
- EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/.freeze
38
- EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/.freeze
39
- EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/.freeze
40
- EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/.freeze
41
- EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/.freeze
42
- EXTENDED_INITIAL_PARAMETER = /(#{EXTENDED_INITIAL_NAME})=(#{EXTENDED_INITIAL_VALUE})/.freeze
43
- EXTENDED_PARAMETER = /#{EXTENDED_INITIAL_PARAMETER}|#{EXTENDED_OTHER_PARAMETER}/.freeze
44
- DISPPARM = /;\s*(?:#{REGULAR_PARAMETER}|#{EXTENDED_PARAMETER})\s*/.freeze
45
- RFC2183 = /^#{CONDISP}(#{DISPPARM})+$/i.freeze
46
-
47
19
  class Decoder
20
+ include HTTPX::Utils
21
+
22
+ CRLF = "\r\n"
48
23
  BOUNDARY_RE = /;\s*boundary=([^;]+)/i.freeze
24
+ MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{CRLF}/ni.freeze
25
+ MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni.freeze
26
+ MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{CRLF}]*)/ni.freeze
49
27
  WINDOW_SIZE = 2 << 14
50
28
 
51
29
  def initialize(response)
@@ -102,7 +80,7 @@ module HTTPX::Plugins
102
80
  name = head[MULTIPART_CONTENT_ID, 1]
103
81
  end
104
82
 
105
- filename = get_filename(head)
83
+ filename = HTTPX::Utils.get_filename(head)
106
84
 
107
85
  name = filename || +"#{content_type || "text/plain"}[]" if name.nil? || name.empty?
108
86
 
@@ -154,34 +132,6 @@ module HTTPX::Plugins
154
132
  raise Error, "parsing should have been over by now"
155
133
  end until @buffer.empty?
156
134
  end
157
-
158
- def get_filename(head)
159
- filename = nil
160
- case head
161
- when RFC2183
162
- params = Hash[*head.scan(DISPPARM).flat_map(&:compact)]
163
-
164
- if (filename = params["filename"])
165
- filename = Regexp.last_match(1) if filename =~ /^"(.*)"$/
166
- elsif (filename = params["filename*"])
167
- encoding, _, filename = filename.split("'", 3)
168
- end
169
- when BROKEN_QUOTED, BROKEN_UNQUOTED
170
- filename = Regexp.last_match(1)
171
- end
172
-
173
- return unless filename
174
-
175
- filename = URI::DEFAULT_PARSER.unescape(filename) if filename.scan(/%.?.?/).all? { |s| /%[0-9a-fA-F]{2}/.match?(s) }
176
-
177
- filename.scrub!
178
-
179
- filename = filename.gsub(/\\(.)/, '\1') unless /\\[^\\"]/.match?(filename)
180
-
181
- filename.force_encoding ::Encoding.find(encoding) if encoding
182
-
183
- filename
184
- end
185
135
  end
186
136
  end
187
137
  end
@@ -7,7 +7,7 @@ module HTTPX
7
7
  #
8
8
  # HTTPX.post(URL, form: form: { image: HTTP::FormData::File.new("path/to/file")})
9
9
  #
10
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Multipart-Uploads
10
+ # https://gitlab.com/os85/httpx/wikis/Multipart-Uploads
11
11
  #
12
12
  module Multipart
13
13
  MULTIPART_VALUE_COND = lambda do |value|
@@ -29,7 +29,7 @@ module HTTPX
29
29
  # in order not to break legacy code, we'll keep loading http/form_data for them.
30
30
  require "http/form_data"
31
31
  warn "httpx: http/form_data is no longer a requirement to use HTTPX :multipart plugin. See migration instructions under" \
32
- "https://honeyryderchuck.gitlab.io/httpx/wiki/Multipart-Uploads.html#notes. \n\n" \
32
+ "https://os85.gitlab.io/httpx/wiki/Multipart-Uploads.html#notes. \n\n" \
33
33
  "If you'd like to stop seeing this message, require 'http/form_data' yourself."
34
34
  end
35
35
  rescue LoadError
@@ -3,7 +3,7 @@
3
3
  module HTTPX
4
4
  module Plugins
5
5
  #
6
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Authentication#ntlm-authentication
6
+ # https://gitlab.com/os85/httpx/wikis/Authentication#ntlm-authentication
7
7
  #
8
8
  module NTLMAuth
9
9
  class << self
@@ -39,6 +39,8 @@ module HTTPX
39
39
  request.headers["authorization"] = ntlm.negotiate
40
40
  probe_response = wrap { super(request).first }
41
41
 
42
+ return probe_response unless probe_response.is_a?(Response)
43
+
42
44
  if probe_response.status == 401 && ntlm.can_authenticate?(probe_response.headers["www-authenticate"])
43
45
  request.transition(:idle)
44
46
  request.headers["authorization"] = ntlm.authenticate(request, probe_response.headers["www-authenticate"])
@@ -15,7 +15,7 @@ module HTTPX
15
15
  # This plugin is also not recommendable when connecting to >9000 (like, a lot) different origins.
16
16
  # So when you use this, make sure that you don't fall into this trap.
17
17
  #
18
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Persistent
18
+ # https://gitlab.com/os85/httpx/wikis/Persistent
19
19
  #
20
20
  module Persistent
21
21
  def self.load_dependencies(klass)
@@ -23,6 +23,7 @@ module HTTPX
23
23
  response = super
24
24
 
25
25
  if response &&
26
+ response.is_a?(Response) &&
26
27
  response.status == 407 &&
27
28
  !request.headers.key?("proxy-authorization") &&
28
29
  response.headers.key?("proxy-authenticate")
@@ -113,13 +114,14 @@ module HTTPX
113
114
 
114
115
  def __http_on_connect(request, response)
115
116
  @inflight -= 1
116
- if response.status == 200
117
+ if response.is_a?(Response) && response.status == 200
117
118
  req = @pending.first
118
119
  request_uri = req.uri
119
120
  @io = ProxySSL.new(@io, request_uri, @options)
120
121
  transition(:connected)
121
122
  throw(:called)
122
- elsif response.status == 407 &&
123
+ elsif response.is_a?(Response) &&
124
+ response.status == 407 &&
123
125
  !request.headers.key?("proxy-authorization") &&
124
126
  @options.proxy.can_authenticate?(response.headers["proxy-authenticate"])
125
127
 
@@ -12,7 +12,7 @@ module HTTPX
12
12
  # * Socks4/4a proxies
13
13
  # * Socks5 proxies
14
14
  #
15
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Proxy
15
+ # https://gitlab.com/os85/httpx/wikis/Proxy
16
16
  #
17
17
  module Proxy
18
18
  Error = HTTPProxyError
@@ -8,7 +8,7 @@ module HTTPX
8
8
  # In order to benefit from this, requests are sent one at a time, so that
9
9
  # no push responses are received after corresponding request has been sent.
10
10
  #
11
- # https://gitlab.com/honeyryderchuck/httpx/wikis/Server-Push
11
+ # https://gitlab.com/os85/httpx/wikis/Server-Push
12
12
  #
13
13
  module PushPromise
14
14
  def self.extra_options(options)