http 5.3.1 → 6.0.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.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +110 -13
  4. data/http.gemspec +32 -29
  5. data/lib/http/base64.rb +11 -1
  6. data/lib/http/chainable/helpers.rb +62 -0
  7. data/lib/http/chainable/verbs.rb +136 -0
  8. data/lib/http/chainable.rb +232 -136
  9. data/lib/http/client.rb +158 -127
  10. data/lib/http/connection/internals.rb +141 -0
  11. data/lib/http/connection.rb +126 -97
  12. data/lib/http/content_type.rb +61 -6
  13. data/lib/http/errors.rb +25 -1
  14. data/lib/http/feature.rb +65 -5
  15. data/lib/http/features/auto_deflate.rb +124 -17
  16. data/lib/http/features/auto_inflate.rb +38 -15
  17. data/lib/http/features/caching/entry.rb +178 -0
  18. data/lib/http/features/caching/in_memory_store.rb +63 -0
  19. data/lib/http/features/caching.rb +216 -0
  20. data/lib/http/features/digest_auth.rb +234 -0
  21. data/lib/http/features/instrumentation.rb +97 -17
  22. data/lib/http/features/logging.rb +183 -5
  23. data/lib/http/features/normalize_uri.rb +17 -0
  24. data/lib/http/features/raise_error.rb +18 -3
  25. data/lib/http/form_data/composite_io.rb +106 -0
  26. data/lib/http/form_data/file.rb +95 -0
  27. data/lib/http/form_data/multipart/param.rb +62 -0
  28. data/lib/http/form_data/multipart.rb +106 -0
  29. data/lib/http/form_data/part.rb +52 -0
  30. data/lib/http/form_data/readable.rb +58 -0
  31. data/lib/http/form_data/urlencoded.rb +175 -0
  32. data/lib/http/form_data/version.rb +8 -0
  33. data/lib/http/form_data.rb +102 -0
  34. data/lib/http/headers/known.rb +3 -0
  35. data/lib/http/headers/normalizer.rb +17 -36
  36. data/lib/http/headers.rb +172 -65
  37. data/lib/http/mime_type/adapter.rb +24 -9
  38. data/lib/http/mime_type/json.rb +19 -4
  39. data/lib/http/mime_type.rb +21 -3
  40. data/lib/http/options/definitions.rb +189 -0
  41. data/lib/http/options.rb +172 -125
  42. data/lib/http/redirector.rb +80 -75
  43. data/lib/http/request/body.rb +87 -6
  44. data/lib/http/request/builder.rb +184 -0
  45. data/lib/http/request/proxy.rb +83 -0
  46. data/lib/http/request/writer.rb +76 -16
  47. data/lib/http/request.rb +214 -98
  48. data/lib/http/response/body.rb +103 -18
  49. data/lib/http/response/inflater.rb +35 -7
  50. data/lib/http/response/parser.rb +98 -4
  51. data/lib/http/response/status/reasons.rb +2 -4
  52. data/lib/http/response/status.rb +141 -31
  53. data/lib/http/response.rb +219 -61
  54. data/lib/http/retriable/delay_calculator.rb +38 -11
  55. data/lib/http/retriable/errors.rb +21 -0
  56. data/lib/http/retriable/performer.rb +82 -38
  57. data/lib/http/session.rb +280 -0
  58. data/lib/http/timeout/global.rb +147 -34
  59. data/lib/http/timeout/null.rb +155 -9
  60. data/lib/http/timeout/per_operation.rb +139 -18
  61. data/lib/http/uri/normalizer.rb +82 -0
  62. data/lib/http/uri/parsing.rb +182 -0
  63. data/lib/http/uri.rb +289 -124
  64. data/lib/http/version.rb +2 -1
  65. data/lib/http.rb +11 -2
  66. data/sig/http.rbs +1619 -0
  67. metadata +36 -171
  68. data/.github/workflows/ci.yml +0 -67
  69. data/.gitignore +0 -15
  70. data/.rspec +0 -1
  71. data/.rubocop/layout.yml +0 -8
  72. data/.rubocop/metrics.yml +0 -4
  73. data/.rubocop/rspec.yml +0 -9
  74. data/.rubocop/style.yml +0 -32
  75. data/.rubocop.yml +0 -11
  76. data/.rubocop_todo.yml +0 -219
  77. data/.yardopts +0 -2
  78. data/CHANGELOG.md +0 -67
  79. data/CHANGES_OLD.md +0 -1002
  80. data/CONTRIBUTING.md +0 -26
  81. data/Gemfile +0 -51
  82. data/Guardfile +0 -18
  83. data/Rakefile +0 -64
  84. data/SECURITY.md +0 -17
  85. data/lib/http/headers/mixin.rb +0 -34
  86. data/lib/http/retriable/client.rb +0 -37
  87. data/logo.png +0 -0
  88. data/spec/lib/http/client_spec.rb +0 -556
  89. data/spec/lib/http/connection_spec.rb +0 -88
  90. data/spec/lib/http/content_type_spec.rb +0 -47
  91. data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
  92. data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
  93. data/spec/lib/http/features/instrumentation_spec.rb +0 -81
  94. data/spec/lib/http/features/logging_spec.rb +0 -65
  95. data/spec/lib/http/features/raise_error_spec.rb +0 -62
  96. data/spec/lib/http/headers/mixin_spec.rb +0 -36
  97. data/spec/lib/http/headers/normalizer_spec.rb +0 -52
  98. data/spec/lib/http/headers_spec.rb +0 -527
  99. data/spec/lib/http/options/body_spec.rb +0 -15
  100. data/spec/lib/http/options/features_spec.rb +0 -33
  101. data/spec/lib/http/options/form_spec.rb +0 -15
  102. data/spec/lib/http/options/headers_spec.rb +0 -24
  103. data/spec/lib/http/options/json_spec.rb +0 -15
  104. data/spec/lib/http/options/merge_spec.rb +0 -68
  105. data/spec/lib/http/options/new_spec.rb +0 -30
  106. data/spec/lib/http/options/proxy_spec.rb +0 -20
  107. data/spec/lib/http/options_spec.rb +0 -13
  108. data/spec/lib/http/redirector_spec.rb +0 -530
  109. data/spec/lib/http/request/body_spec.rb +0 -211
  110. data/spec/lib/http/request/writer_spec.rb +0 -121
  111. data/spec/lib/http/request_spec.rb +0 -234
  112. data/spec/lib/http/response/body_spec.rb +0 -85
  113. data/spec/lib/http/response/parser_spec.rb +0 -74
  114. data/spec/lib/http/response/status_spec.rb +0 -253
  115. data/spec/lib/http/response_spec.rb +0 -262
  116. data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
  117. data/spec/lib/http/retriable/performer_spec.rb +0 -302
  118. data/spec/lib/http/uri/normalizer_spec.rb +0 -95
  119. data/spec/lib/http/uri_spec.rb +0 -71
  120. data/spec/lib/http_spec.rb +0 -535
  121. data/spec/regression_specs.rb +0 -24
  122. data/spec/spec_helper.rb +0 -89
  123. data/spec/support/black_hole.rb +0 -13
  124. data/spec/support/capture_warning.rb +0 -10
  125. data/spec/support/dummy_server/servlet.rb +0 -203
  126. data/spec/support/dummy_server.rb +0 -44
  127. data/spec/support/fakeio.rb +0 -21
  128. data/spec/support/fuubar.rb +0 -21
  129. data/spec/support/http_handling_shared.rb +0 -190
  130. data/spec/support/proxy_server.rb +0 -39
  131. data/spec/support/servers/config.rb +0 -11
  132. data/spec/support/servers/runner.rb +0 -19
  133. data/spec/support/simplecov.rb +0 -19
  134. data/spec/support/ssl_helper.rb +0 -104
data/lib/http/uri.rb CHANGED
@@ -1,211 +1,376 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "addressable/uri"
3
+ require "uri"
4
4
 
5
5
  module HTTP
6
+ # HTTP URI with scheme, authority, path, query, and fragment components
7
+ #
8
+ # Stores URI components as instance variables. Addressable is only used
9
+ # when parsing non-ASCII (IRI) strings; ASCII URIs use stdlib's URI.parse.
6
10
  class URI
7
- extend Forwardable
8
-
9
- def_delegators :@uri, :scheme, :normalized_scheme, :scheme=
10
- def_delegators :@uri, :user, :normalized_user, :user=
11
- def_delegators :@uri, :password, :normalized_password, :password=
12
- def_delegators :@uri, :authority, :normalized_authority, :authority=
13
- def_delegators :@uri, :origin, :origin=
14
- def_delegators :@uri, :normalized_port, :port=
15
- def_delegators :@uri, :path, :normalized_path, :path=
16
- def_delegators :@uri, :query, :normalized_query, :query=
17
- def_delegators :@uri, :query_values, :query_values=
18
- def_delegators :@uri, :request_uri, :request_uri=
19
- def_delegators :@uri, :fragment, :normalized_fragment, :fragment=
20
- def_delegators :@uri, :omit, :join, :normalize
21
-
22
- # Host, either a domain name or IP address. If the host is an IPv6 address, it will be returned
23
- # without brackets surrounding it.
24
- #
25
- # @return [String] The host of the URI
11
+ # The URI given was not valid
12
+ class InvalidError < HTTP::RequestError; end
13
+
14
+ # URI scheme (e.g. "http", "https")
15
+ #
16
+ # @example
17
+ # uri.scheme # => "http"
18
+ #
19
+ # @api public
20
+ # @return [String, nil] The URI scheme
21
+ attr_reader :scheme
22
+
23
+ # User component for authentication
24
+ #
25
+ # @example
26
+ # uri.user # => "admin"
27
+ #
28
+ # @api public
29
+ # @return [String, nil] The user component
30
+ attr_reader :user
31
+
32
+ # Password component for authentication
33
+ #
34
+ # @example
35
+ # uri.password # => "secret"
36
+ #
37
+ # @api public
38
+ # @return [String, nil] The password component
39
+ attr_reader :password
40
+
41
+ # Host, either a domain name or IP address
42
+ #
43
+ # @example
44
+ # uri.host # => "example.com"
45
+ #
46
+ # @api public
47
+ # @return [String, nil] The host of the URI
26
48
  attr_reader :host
27
49
 
28
- # Normalized host, either a domain name or IP address. If the host is an IPv6 address, it will
29
- # be returned without brackets surrounding it.
50
+ # Normalized host
51
+ #
52
+ # @example
53
+ # uri.normalized_host # => "example.com"
30
54
  #
31
- # @return [String] The normalized host of the URI
55
+ # @api public
56
+ # @return [String, nil] The normalized host of the URI
32
57
  attr_reader :normalized_host
33
58
 
59
+ # URI path component
60
+ #
61
+ # @example
62
+ # uri.path # => "/foo"
63
+ #
64
+ # @api public
65
+ # @return [String] The path component
66
+ attr_accessor :path
67
+
68
+ # URI query string
69
+ #
70
+ # @example
71
+ # uri.query # => "q=1"
72
+ #
73
+ # @api public
74
+ # @return [String, nil] The query component
75
+ attr_accessor :query
76
+
77
+ # URI fragment
78
+ #
79
+ # @example
80
+ # uri.fragment # => "section1"
81
+ #
82
+ # @api public
83
+ # @return [String, nil] The fragment component
84
+ attr_reader :fragment
85
+
86
+ # HTTP scheme string
34
87
  # @private
35
88
  HTTP_SCHEME = "http"
36
89
 
90
+ # HTTPS scheme string
37
91
  # @private
38
92
  HTTPS_SCHEME = "https"
39
93
 
94
+ # Pattern matching characters requiring percent-encoding
40
95
  # @private
41
- PERCENT_ENCODE = /[^\x21-\x7E]+/.freeze
96
+ PERCENT_ENCODE = /[^\x21-\x7E]+/
42
97
 
98
+ # Default ports for supported URI schemes
43
99
  # @private
44
- NORMALIZER = lambda do |uri|
45
- uri = HTTP::URI.parse uri
46
-
47
- HTTP::URI.new(
48
- :scheme => uri.normalized_scheme,
49
- :authority => uri.normalized_authority,
50
- :path => uri.path.empty? ? "/" : percent_encode(Addressable::URI.normalize_path(uri.path)),
51
- :query => percent_encode(uri.query),
52
- :fragment => uri.normalized_fragment
53
- )
54
- end
100
+ DEFAULT_PORTS = {
101
+ "http" => 80,
102
+ "https" => 443,
103
+ "ws" => 80,
104
+ "wss" => 443
105
+ }.freeze
55
106
 
56
- # Parse the given URI string, returning an HTTP::URI object
107
+ # Pattern for characters that stdlib's URI.parse silently modifies
108
+ # @private
109
+ NEEDS_ADDRESSABLE = /[^\x20-\x7E]/
110
+
111
+ # Creates an HTTP::URI instance from the given keyword arguments
112
+ #
113
+ # @example
114
+ # HTTP::URI.new(scheme: "http", host: "example.com")
57
115
  #
58
- # @param [HTTP::URI, String, #to_str] uri to parse
116
+ # @param [String, nil] scheme URI scheme
117
+ # @param [String, nil] user for basic authentication
118
+ # @param [String, nil] password for basic authentication
119
+ # @param [String, nil] host name component (IPv6 addresses must be bracketed)
120
+ # @param [Integer, nil] port network port to connect to
121
+ # @param [String, nil] path component to request
122
+ # @param [String, nil] query component distinct from path
123
+ # @param [String, nil] fragment component at the end of the URI
59
124
  #
125
+ # @api public
60
126
  # @return [HTTP::URI] new URI instance
61
- def self.parse(uri)
62
- return uri if uri.is_a?(self)
63
-
64
- new(Addressable::URI.parse(uri))
127
+ def initialize(scheme: nil, user: nil, password: nil, host: nil,
128
+ port: nil, path: nil, query: nil, fragment: nil)
129
+ @scheme = scheme
130
+ @user = user
131
+ @password = password
132
+ @raw_host = host
133
+ @host = process_ipv6_brackets(host)
134
+ @normalized_host = normalize_host(@host)
135
+ @port = port
136
+ @path = path || ""
137
+ @query = query
138
+ @fragment = fragment
65
139
  end
66
140
 
67
- # Encodes key/value pairs as application/x-www-form-urlencoded
141
+ # Are these URI objects equal after normalization
142
+ #
143
+ # @example
144
+ # HTTP::URI.parse("http://example.com") == HTTP::URI.parse("http://example.com")
68
145
  #
69
- # @param [#to_hash, #to_ary] form_values to encode
70
- # @param [TrueClass, FalseClass] sort should key/value pairs be sorted first?
146
+ # @param [Object] other URI to compare this one with
71
147
  #
72
- # @return [String] encoded value
73
- def self.form_encode(form_values, sort = false)
74
- Addressable::URI.form_encode(form_values, sort)
148
+ # @api public
149
+ # @return [TrueClass, FalseClass] are the URIs equivalent (after normalization)?
150
+ def ==(other)
151
+ other.is_a?(URI) && String(normalize).eql?(String(other.normalize))
75
152
  end
76
153
 
77
- # Percent-encode all characters matching a regular expression.
154
+ # Are these URI objects equal without normalization
78
155
  #
79
- # @param [String] string raw string
156
+ # @example
157
+ # uri = HTTP::URI.parse("http://example.com")
158
+ # uri.eql?(HTTP::URI.parse("http://example.com"))
80
159
  #
81
- # @return [String] encoded value
160
+ # @param [Object] other URI to compare this one with
82
161
  #
83
- # @private
84
- def self.percent_encode(string)
85
- string&.gsub(PERCENT_ENCODE) do |substr|
86
- substr.encode(Encoding::UTF_8).bytes.map { |c| format("%%%02X", c) }.join
87
- end
162
+ # @api public
163
+ # @return [TrueClass, FalseClass] are the URIs equivalent?
164
+ def eql?(other)
165
+ other.is_a?(URI) && String(self).eql?(String(other))
88
166
  end
89
167
 
90
- # Creates an HTTP::URI instance from the given options
168
+ # Hash value based off the normalized form of a URI
91
169
  #
92
- # @param [Hash, Addressable::URI] options_or_uri
170
+ # @example
171
+ # HTTP::URI.parse("http://example.com").hash
93
172
  #
94
- # @option options_or_uri [String, #to_str] :scheme URI scheme
95
- # @option options_or_uri [String, #to_str] :user for basic authentication
96
- # @option options_or_uri [String, #to_str] :password for basic authentication
97
- # @option options_or_uri [String, #to_str] :host name component
98
- # @option options_or_uri [String, #to_str] :port network port to connect to
99
- # @option options_or_uri [String, #to_str] :path component to request
100
- # @option options_or_uri [String, #to_str] :query component distinct from path
101
- # @option options_or_uri [String, #to_str] :fragment component at the end of the URI
173
+ # @api public
174
+ # @return [Integer] A hash of the URI
175
+ def hash
176
+ @hash ||= [self.class, String(self)].hash
177
+ end
178
+
179
+ # Sets the host component for the URI
102
180
  #
103
- # @return [HTTP::URI] new URI instance
104
- def initialize(options_or_uri = {})
105
- case options_or_uri
106
- when Hash
107
- @uri = Addressable::URI.new(options_or_uri)
108
- when Addressable::URI
109
- @uri = options_or_uri
110
- else
111
- raise TypeError, "expected Hash for options, got #{options_or_uri.class}"
112
- end
181
+ # @example
182
+ # uri = HTTP::URI.parse("http://example.com")
183
+ # uri.host = "other.com"
184
+ #
185
+ # @param [String, #to_str] new_host The new host component
186
+ # @api public
187
+ # @return [void]
188
+ def host=(new_host)
189
+ @raw_host = process_ipv6_brackets(new_host, brackets: true)
190
+ @host = process_ipv6_brackets(@raw_host)
191
+ @normalized_host = normalize_host(@host)
192
+ end
113
193
 
114
- @host = process_ipv6_brackets(@uri.host)
115
- @normalized_host = process_ipv6_brackets(@uri.normalized_host)
194
+ # Port number, either as specified or the default
195
+ #
196
+ # @example
197
+ # HTTP::URI.parse("http://example.com").port
198
+ #
199
+ # @api public
200
+ # @return [Integer, nil] port number
201
+ def port
202
+ @port || default_port
116
203
  end
117
204
 
118
- # Are these URI objects equal? Normalizes both URIs prior to comparison
205
+ # Default port for the URI scheme
119
206
  #
120
- # @param [Object] other URI to compare this one with
207
+ # @example
208
+ # HTTP::URI.parse("http://example.com").default_port # => 80
121
209
  #
122
- # @return [TrueClass, FalseClass] are the URIs equivalent (after normalization)?
123
- def ==(other)
124
- other.is_a?(URI) && normalize.to_s == other.normalize.to_s
210
+ # @api public
211
+ # @return [Integer, nil] default port or nil for unknown schemes
212
+ def default_port
213
+ DEFAULT_PORTS[@scheme&.downcase]
125
214
  end
126
215
 
127
- # Are these URI objects equal? Does NOT normalizes both URIs prior to comparison
216
+ # The origin (scheme + host + port) per RFC 6454
128
217
  #
129
- # @param [Object] other URI to compare this one with
218
+ # @example
219
+ # HTTP::URI.parse("http://example.com").origin # => "http://example.com"
130
220
  #
131
- # @return [TrueClass, FalseClass] are the URIs equivalent?
132
- def eql?(other)
133
- other.is_a?(URI) && to_s == other.to_s
221
+ # @api public
222
+ # @return [String] origin of the URI
223
+ def origin
224
+ port_suffix = ":#{port}" unless port.eql?(default_port)
225
+ "#{String(@scheme).downcase}://#{String(@raw_host).downcase}#{port_suffix}"
134
226
  end
135
227
 
136
- # Hash value based off the normalized form of a URI
228
+ # The path and query for use in an HTTP request line
137
229
  #
138
- # @return [Integer] A hash of the URI
139
- def hash
140
- @hash ||= to_s.hash * -1
230
+ # @example
231
+ # HTTP::URI.parse("http://example.com/path?q=1").request_uri # => "/path?q=1"
232
+ #
233
+ # @api public
234
+ # @return [String] request URI string
235
+ def request_uri
236
+ "#{'/' if @path.empty?}#{@path}#{"?#{@query}" if @query}"
141
237
  end
142
238
 
143
- # Sets the host component for the URI.
239
+ # Returns a new URI with the specified components removed
144
240
  #
145
- # @param [String, #to_str] new_host The new host component.
146
- # @return [void]
147
- def host=(new_host)
148
- @uri.host = process_ipv6_brackets(new_host, :brackets => true)
241
+ # @example
242
+ # HTTP::URI.parse("http://example.com#frag").omit(:fragment)
243
+ #
244
+ # @param components [Symbol] URI components to remove
245
+ # @api public
246
+ # @return [HTTP::URI] new URI without the specified components
247
+ def omit(*components)
248
+ self.class.new(
249
+ **{ scheme: @scheme, user: @user, password: @password, host: @raw_host,
250
+ port: @port, path: @path, query: @query, fragment: @fragment }.except(*components)
251
+ )
252
+ end
149
253
 
150
- @host = process_ipv6_brackets(@uri.host)
151
- @normalized_host = process_ipv6_brackets(@uri.normalized_host)
254
+ # Resolves another URI against this one per RFC 3986
255
+ #
256
+ # @example
257
+ # HTTP::URI.parse("http://example.com/foo/").join("bar")
258
+ #
259
+ # @param [String, URI] other the URI to resolve
260
+ #
261
+ # @api public
262
+ # @return [HTTP::URI] resolved URI
263
+ def join(other)
264
+ base = self.class.percent_encode(String(self))
265
+ ref = self.class.percent_encode(String(other))
266
+ self.class.parse(::URI.join(base, ref))
152
267
  end
153
268
 
154
- # Port number, either as specified or the default if unspecified
269
+ # Returns a normalized copy of the URI
155
270
  #
156
- # @return [Integer] port number
157
- def port
158
- @uri.port || @uri.default_port
271
+ # Lowercases scheme and host, strips default port. Used by {#==}
272
+ # to compare URIs for equivalence.
273
+ #
274
+ # @example
275
+ # HTTP::URI.parse("HTTP://EXAMPLE.COM:80").normalize
276
+ #
277
+ # @api public
278
+ # @return [HTTP::URI] normalized URI
279
+ def normalize
280
+ self.class.new(
281
+ scheme: @scheme&.downcase,
282
+ user: @user,
283
+ password: @password,
284
+ host: @raw_host&.downcase,
285
+ port: (@port unless port.eql?(default_port)),
286
+ path: @path.empty? && @raw_host ? "/" : @path,
287
+ query: @query,
288
+ fragment: @fragment
289
+ )
159
290
  end
160
291
 
292
+ # Checks whether the URI scheme is HTTP
293
+ #
294
+ # @example
295
+ # HTTP::URI.parse("http://example.com").http?
296
+ #
297
+ # @api public
161
298
  # @return [True] if URI is HTTP
162
299
  # @return [False] otherwise
163
300
  def http?
164
- HTTP_SCHEME == scheme
301
+ HTTP_SCHEME.eql?(@scheme)
165
302
  end
166
303
 
304
+ # Checks whether the URI scheme is HTTPS
305
+ #
306
+ # @example
307
+ # HTTP::URI.parse("https://example.com").https?
308
+ #
309
+ # @api public
167
310
  # @return [True] if URI is HTTPS
168
311
  # @return [False] otherwise
169
312
  def https?
170
- HTTPS_SCHEME == scheme
313
+ HTTPS_SCHEME.eql?(@scheme)
171
314
  end
172
315
 
173
- # @return [Object] duplicated URI
316
+ # Duplicates the URI object
317
+ #
318
+ # @example
319
+ # HTTP::URI.parse("http://example.com").dup
320
+ #
321
+ # @api public
322
+ # @return [HTTP::URI] duplicated URI
174
323
  def dup
175
- self.class.new @uri.dup
324
+ self.class.new(
325
+ scheme: @scheme, user: @user, password: @password, host: @raw_host,
326
+ port: @port, path: @path, query: @query, fragment: @fragment
327
+ )
176
328
  end
177
329
 
178
330
  # Convert an HTTP::URI to a String
179
331
  #
332
+ # @example
333
+ # HTTP::URI.parse("http://example.com").to_s
334
+ #
335
+ # @api public
180
336
  # @return [String] URI serialized as a String
181
337
  def to_s
182
- @uri.to_s
338
+ str = +""
339
+ str << "#{@scheme}:" if @scheme
340
+ str << authority_string if @raw_host
341
+ str << @path
342
+ str << "?#{@query}" if @query
343
+ str << "##{@fragment}" if @fragment
344
+ str
183
345
  end
184
346
  alias to_str to_s
185
347
 
348
+ # Returns human-readable representation of URI
349
+ #
350
+ # @example
351
+ # HTTP::URI.parse("http://example.com").inspect
352
+ #
353
+ # @api public
186
354
  # @return [String] human-readable representation of URI
187
355
  def inspect
188
- format("#<%s:0x%014x URI:%s>", self.class.name, object_id << 1, to_s)
356
+ format("#<%s:0x%014x URI:%s>", self.class, object_id << 1, self)
189
357
  end
190
358
 
191
- private
192
-
193
- # Process a URI host, adding or removing surrounding brackets if the host is an IPv6 address.
359
+ # Pattern matching interface
194
360
  #
195
- # @param [Boolean] brackets When true, brackets will be added to IPv6 addresses if missing. When
196
- # false, they will be removed if present.
361
+ # @example
362
+ # uri.deconstruct_keys(%i[scheme host])
197
363
  #
198
- # @return [String] Host with IPv6 address brackets added or removed
199
- def process_ipv6_brackets(raw_host, brackets: false)
200
- ip = IPAddr.new(raw_host)
201
-
202
- if ip.ipv6?
203
- brackets ? "[#{ip}]" : ip.to_s
204
- else
205
- raw_host
206
- end
207
- rescue IPAddr::Error
208
- raw_host
364
+ # @param keys [Array<Symbol>, nil] keys to extract, or nil for all
365
+ # @return [Hash{Symbol => Object}]
366
+ # @api public
367
+ def deconstruct_keys(keys)
368
+ hash = { scheme: @scheme, host: @host, port: port, path: @path,
369
+ query: @query, fragment: @fragment, user: @user, password: @password }
370
+ keys ? hash.slice(*keys) : hash
209
371
  end
210
372
  end
211
373
  end
374
+
375
+ require "http/uri/parsing"
376
+ require "http/uri/normalizer"
data/lib/http/version.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTP
4
- VERSION = "5.3.1"
4
+ # Current library version
5
+ VERSION = "6.0.1"
5
6
  end
data/lib/http.rb CHANGED
@@ -5,8 +5,8 @@ require "http/timeout/null"
5
5
  require "http/timeout/per_operation"
6
6
  require "http/timeout/global"
7
7
  require "http/chainable"
8
+ require "http/session"
8
9
  require "http/client"
9
- require "http/retriable/client"
10
10
  require "http/connection"
11
11
  require "http/options"
12
12
  require "http/feature"
@@ -21,7 +21,16 @@ module HTTP
21
21
  extend Chainable
22
22
 
23
23
  class << self
24
- # HTTP[:accept => 'text/html'].get(...)
24
+ # Set default headers and return a chainable session
25
+ #
26
+ # @example
27
+ # HTTP[:accept => "text/html"].get("https://example.com")
28
+ #
29
+ # @param headers [Hash] headers to set
30
+ #
31
+ # @return [HTTP::Session]
32
+ #
33
+ # @api public
25
34
  alias [] headers
26
35
  end
27
36
  end