httpx 0.21.0 → 0.21.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c62cb1d027ee7e62770de459b00411614372578117ea56354df0d9114cf4397b
4
- data.tar.gz: 18275725fc8adeac596f02f83f034dfcfe24a7e4c96ec34bc11400e8ca0e9567
3
+ metadata.gz: 1195773336c2fb0b92ed10abfafa8a99c7cfd19af31b932dbfff72d073ed3f47
4
+ data.tar.gz: 634e9e62edcd8184d014b1870cbc303cdfcc8035e0c76431b10c1e9143bdbb23
5
5
  SHA512:
6
- metadata.gz: 840bf59a4cbbb45d26a836ccd4060007470d380314b4aedea58e49cb434b050a8252f7db3823daf9c2dfdb5d54075215e4ee1216c80852afbb7abfd57e1dfea2
7
- data.tar.gz: 35a666b92236240e8ccd09b1dc29a2ccf83061222b0511d35eee6fb7f3794dc737ca86ac9ca7d87ba01e03d8e648b07e6e52290b02b25674bd783b7f9d2cfbce
6
+ metadata.gz: bee27d21eef64771e054b4517e99371462cc28fb1c5cad4353137e111e96a4d22131d573aa5c31fe6b86c7007466feec5d1181ae6787a3a6ef87459468d911c8
7
+ data.tar.gz: 15fa97c4456ce2d8f875590075c9ceb778096aca70d27a793c5cafa026f038331439ac62fd823210290013c0466c072a2eff5c1a0a06b1c880254e542d3f9e16
data/README.md CHANGED
@@ -19,13 +19,17 @@ And also:
19
19
 
20
20
  * Compression (gzip, deflate, brotli)
21
21
  * Streaming Requests
22
- * Authentication (Basic Auth, Digest Auth)
22
+ * Authentication (Basic Auth, Digest Auth, NTLM)
23
23
  * Expect 100-continue
24
24
  * Multipart Requests
25
- * Cookies
25
+ * Advanced Cookie handling
26
26
  * HTTP/2 Server Push
27
- * H2C Upgrade
27
+ * HTTP/1.1 Upgrade (support for "h2c", "h2")
28
28
  * Automatic follow redirects
29
+ * GRPC
30
+ * WebDAV
31
+ * Circuit Breaker
32
+ * HTTP-based response cache
29
33
  * International Domain Names
30
34
 
31
35
  ## How
@@ -36,7 +40,14 @@ Here are some simple examples:
36
40
  HTTPX.get("https://nghttp2.org").to_s #=> "<!DOCT...."
37
41
  ```
38
42
 
39
- And that's the simplest one there is.
43
+ And that's the simplest one there is. But you can also do:
44
+
45
+ ```ruby
46
+ HTTPX.post("http://example.com", form: { user: "john", password: "pass" })
47
+
48
+ http = HTTPX.with(headers: { "x-my-name" => "joe" })
49
+ http.patch(("http://example.com/file", body: File.open("path/to/file")) # request body is streamed
50
+ ```
40
51
 
41
52
  If you want to do some more things with the response, you can get an `HTTPX::Response`:
42
53
 
@@ -50,7 +61,7 @@ puts body #=> #<HTTPX::Response ...
50
61
  You can also send as many requests as you want simultaneously:
51
62
 
52
63
  ```ruby
53
- page1, page2, page3 = HTTPX.get("https://news.ycombinator.com/news", "https://news.ycombinator.com/news?p=2", "https://news.ycombinator.com/news?p=3")
64
+ page1, page2, page3 =`HTTPX.get("https://news.ycombinator.com/news", "https://news.ycombinator.com/news?p=2", "https://news.ycombinator.com/news?p=3")
54
65
  ```
55
66
 
56
67
  ## Installation
@@ -73,43 +84,53 @@ and then just require it in your program:
73
84
  require "httpx"
74
85
  ```
75
86
 
76
- ## Why Should I care?
87
+ ## What makes it the best ruby HTTP client
77
88
 
78
- In Ruby, HTTP client implementations are a known cheap commodity. Why this one?
79
89
 
80
- ### Concurrency
90
+ ### Concurrency, HTTP/2 support
81
91
 
82
- This library supports HTTP/2 seamlessly (which means, if the request is secure, and the server support ALPN negotiation AND HTTP/2, the request will be made through HTTP/2). If you pass multiple URIs, and they can utilize the same connection, they will run concurrently in it.
92
+ `httpx` supports HTTP/2 (for "https" requests, it'll automatically do ALPN negotiation). However if the server supports HTTP/1.1, it will use HTTP pipelining, falling back to 1 request at a time if the server doesn't support it either (and it'll use Keep-Alive connections, unless the server does not support).
83
93
 
84
- However if the server supports HTTP/1.1, it will try to use HTTP pipelining, falling back to 1 request at a time if the server doesn't support it (if the server support Keep-Alive connections, it will reuse the same connection).
94
+ If you passed multiple URIs, it'll perform all of the requests concurrently, by mulitplexing on the necessary sockets (and it'll batch requests to the same socket when the origin is the same):
95
+
96
+ ```ruby
97
+ HTTPX.get(
98
+ "https://news.ycombinator.com/news",
99
+ "https://news.ycombinator.com/news?p=2",
100
+ "https://google.com/q=me"
101
+ ) # first two requests will be multiplexed on the same socket.
102
+ ```
85
103
 
86
104
  ### Clean API
87
105
 
88
106
  `httpx` builds all functions around the `HTTPX` module, so that all calls can compose of each other. Here are a few examples:
89
107
 
90
108
  ```ruby
91
- response = HTTPX.get("https://www.google.com")
92
- response = HTTPX.post("https://www.nghttp2.org/httpbin/post", params: {name: "John", age: "22"})
109
+ response = HTTPX.get("https://www.google.com", params: { q: "me" })
110
+ response = HTTPX.post("https://www.nghttp2.org/httpbin/post", form: {name: "John", age: "22"})
93
111
  response = HTTPX.plugin(:basic_authentication)
94
112
  .basic_authentication("user", "pass")
95
113
  .get("https://www.google.com")
114
+
115
+ # more complex client objects can be cached, and are thread-safe
116
+ http = HTTPX.plugin(:compression).plugin(:expect).with(headers: { "x-pvt-token" => "TOKEN"})
117
+ http.get("https://example.com") # the above options will apply
118
+ http.post("https://example2.com", form: {name: "John", age: "22"}) # same, plus the form POST body
96
119
  ```
97
120
 
98
121
  ### Lightweight
99
122
 
100
- It ships with a plugin system similar to the ones used by [sequel](https://github.com/jeremyevans/sequel), [roda](https://github.com/jeremyevans/roda) or [shrine](https://github.com/janko-m/shrine).
101
-
102
- It means that it loads the bare minimum to perform requests, and the user has to explicitly load the plugins, in order to get the features he/she needs.
123
+ It ships with most features published as a plugin, making vanilla `httpx` lightweight and dependency-free, while allowing you to "pay for what you use"
103
124
 
104
- It also means that it ships with the minimum amount of dependencies.
125
+ The plugin system is similar to the ones used by [sequel](https://github.com/jeremyevans/sequel), [roda](https://github.com/jeremyevans/roda) or [shrine](https://github.com/janko-m/shrine).
105
126
 
106
- ### DNS-over-HTTPS
127
+ ### Advanced DNS features
107
128
 
108
- `HTTPX` ships with custom DNS resolver implementations, including a DNS-over-HTTPS resolver.
129
+ `HTTPX` ships with custom DNS resolver implementations, including a native Happy Eyeballs resolver immplementation, and a DNS-over-HTTPS resolver.
109
130
 
110
- ## Easy to test
131
+ ## User-driven test suite
111
132
 
112
- The test suite runs against [httpbin proxied over nghttp2](https://nghttp2.org/httpbin/), so there are no mocking/stubbing false positives. The test suite uses [minitest](https://github.com/seattlerb/minitest), but its matchers usage is (almost) limited to `#assert` (`assert` is all you need).
133
+ The test suite runs against [httpbin proxied over nghttp2](https://nghttp2.org/httpbin/), so actual requests are performed during tests.
113
134
 
114
135
  ## Supported Rubies
115
136
 
@@ -122,18 +143,15 @@ All Rubies greater or equal to 2.1, and always latest JRuby and Truffleruby.
122
143
  | ------------- | --------------------------------------------------- |
123
144
  | Website | https://honeyryderchuck.gitlab.io/httpx/ |
124
145
  | Documentation | https://honeyryderchuck.gitlab.io/httpx/rdoc/ |
125
- | Wiki | https://gitlab.com/honeyryderchuck/httpx/wikis/home |
146
+ | Wiki | https://honeyryderchuck.gitlab.io/httpx/wiki/home.html |
126
147
  | CI | https://gitlab.com/honeyryderchuck/httpx/pipelines |
148
+ | Rubygems | https://rubygems.org/gems/httpx |
127
149
 
128
150
  ## Caveats
129
151
 
130
152
  ### ALPN support
131
153
 
132
- `HTTPS` TLS backend is ruby's own `openssl` gem.
133
-
134
- If your requirement is to run requests over HTTP/2 and TLS, make sure you run a version of the gem which compiles OpenSSL 1.0.2 (Ruby 2.3 and higher are guaranteed to).
135
-
136
- In order to use HTTP/2 under JRuby, [check this link](https://gitlab.com/honeyryderchuck/httpx/-/wikis/JRuby-Truffleruby-Other-Rubies) to know what to do.
154
+ ALPN negotiation is required for "auto" HTTP/2 "https" requests. This is available in ruby since version 2.3 .
137
155
 
138
156
  ### Known bugs
139
157
 
@@ -9,7 +9,7 @@ https://gitlab.com/honeyryderchuck/httpx/-/wikis/Timeouts
9
9
  The following timeouts are now supported:
10
10
 
11
11
  * `:write_timeout`: total time (in seconds) to write a request to the server;
12
- * `:read_timeout`: total time (in seconds) to read aa response from the server;
12
+ * `:read_timeout`: total time (in seconds) to read a response from the server;
13
13
  * `:request_timeout`: tracks both of the above (time to write the request and read a response);
14
14
 
15
15
  ```ruby
@@ -26,6 +26,8 @@ https://gitlab.com/honeyryderchuck/httpx/-/wikis/Circuit-Breaker
26
26
 
27
27
  The `:circuit_breaker` plugin wraps around errors happening when performing HTTP requests, and support options for setting maximum number of attempts before circuit opens (`:circuit_breaker_max_attempts`), period after which attempts should be reset (`:circuit_breaker_reset_attempts_in`), timespan until circuit half-opens (`circuit_breaker_break_in`), respective half-open drip rate (`:circuit_breaker_half_open_drip_rate`), and a callback to do your own check on whether a response has failed, in case you want HTTP level errors to be marked as failed attempts (`:circuit_breaker_break_on`).
28
28
 
29
+ Read the wiki for more info about the defaults.
30
+
29
31
  ```ruby
30
32
  http = HTTPX.plugin(:circuit_breaker)
31
33
  # that's it!
@@ -49,7 +51,7 @@ res = webdav.copy("/file.html", "/newdir/copy.html")
49
51
 
50
52
  ### XML transcoder, `:xml` option and `response.xml`
51
53
 
52
- A new transcoder was added fot the XML mime type, which requires `"nokogiri"` to be installed; it can both serialize Nokogiri nodes in a request, and parse response content into nokogiri nodes:
54
+ A new transcoder was added fot the XML mime type, which requires `"nokogiri"` to be installed. It can both serialize Nokogiri nodes in a request, and parse response content into nokogiri nodes:
53
55
 
54
56
  ```ruby
55
57
  response = HTTPX.post("https://xml-server.com", xml: Nokogiri::XML("<xml ..."))
@@ -0,0 +1,12 @@
1
+ # 0.21.1
2
+
3
+ ## Bugfixes
4
+
5
+ * fix: protecting tcp connect phase against low-level syscall errors
6
+ * such as network unreachable, which can happen if connectivity is lost meanwhile.
7
+ * native resolver: fix for nameserver switch not happening in case of DNS timeout.
8
+ * when more than a nameserver was advertised by the system.
9
+
10
+ ## Chore
11
+
12
+ * Removing usage of deprecated `Random::DEFAULT.rand` (using `Random.rand` instead)-
@@ -512,9 +512,14 @@ module HTTPX
512
512
 
513
513
  def transition(nextstate)
514
514
  handle_transition(nextstate)
515
- rescue Errno::ECONNREFUSED,
515
+ rescue Errno::ECONNABORTED,
516
+ Errno::ECONNREFUSED,
517
+ Errno::ECONNRESET,
516
518
  Errno::EADDRNOTAVAIL,
517
519
  Errno::EHOSTUNREACH,
520
+ Errno::EINVAL,
521
+ Errno::ENETUNREACH,
522
+ Errno::EPIPE,
518
523
  TLSError => e
519
524
  # connect errors, exit gracefully
520
525
  handle_error(e)
@@ -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
@@ -13,14 +13,14 @@ module HTTPX
13
13
  **Resolv::DNS::Config.default_config_hash,
14
14
  packet_size: 512,
15
15
  timeouts: Resolver::RESOLVE_TIMEOUT,
16
- }.freeze
16
+ }
17
17
  else
18
18
  {
19
19
  nameserver: nil,
20
20
  **Resolv::DNS::Config.default_config_hash,
21
21
  packet_size: 512,
22
22
  timeouts: Resolver::RESOLVE_TIMEOUT,
23
- }.freeze
23
+ }
24
24
  end
25
25
 
26
26
  # nameservers for ipv6 are misconfigured in certain systems;
@@ -35,6 +35,8 @@ module HTTPX
35
35
  end
36
36
  end if DEFAULTS[:nameserver]
37
37
 
38
+ DEFAULTS.freeze
39
+
38
40
  DNS_PORT = 53
39
41
 
40
42
  def_delegator :@connections, :empty?
@@ -152,10 +154,21 @@ module HTTPX
152
154
  host = connection.origin.host
153
155
  timeout = (@timeouts[host][0] -= loop_time)
154
156
 
155
- return unless timeout.negative?
157
+ return unless timeout <= 0
156
158
 
157
159
  @timeouts[host].shift
158
- if @timeouts[host].empty?
160
+
161
+ if !@timeouts[host].empty?
162
+ log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
163
+ resolve(connection)
164
+ elsif @ns_index + 1 < @nameserver.size
165
+ # try on the next nameserver
166
+ @ns_index += 1
167
+ log { "resolver: failed resolving #{host} on nameserver #{@nameserver[@ns_index - 1]} (timeout error)" }
168
+ transition(:idle)
169
+ resolve(connection)
170
+ else
171
+
159
172
  @timeouts.delete(host)
160
173
  @queries.delete(h)
161
174
 
@@ -165,9 +178,6 @@ module HTTPX
165
178
  # This loop_time passed to the exception is bogus. Ideally we would pass the total
166
179
  # resolve timeout, including from the previous retries.
167
180
  raise ResolveTimeoutError.new(loop_time, "Timed out while resolving #{connection.origin.host}")
168
- else
169
- log { "resolver: timeout after #{timeout}s, retry(#{@timeouts[host].first}) #{host}..." }
170
- resolve(connection)
171
181
  end
172
182
  end
173
183
 
data/lib/httpx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTTPX
4
- VERSION = "0.21.0"
4
+ VERSION = "0.21.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: httpx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.21.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-14 00:00:00.000000000 Z
11
+ date: 2022-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-2-next
@@ -87,6 +87,7 @@ extra_rdoc_files:
87
87
  - doc/release_notes/0_20_4.md
88
88
  - doc/release_notes/0_20_5.md
89
89
  - doc/release_notes/0_21_0.md
90
+ - doc/release_notes/0_21_1.md
90
91
  - doc/release_notes/0_2_0.md
91
92
  - doc/release_notes/0_2_1.md
92
93
  - doc/release_notes/0_3_0.md
@@ -166,6 +167,7 @@ files:
166
167
  - doc/release_notes/0_20_4.md
167
168
  - doc/release_notes/0_20_5.md
168
169
  - doc/release_notes/0_21_0.md
170
+ - doc/release_notes/0_21_1.md
169
171
  - doc/release_notes/0_2_0.md
170
172
  - doc/release_notes/0_2_1.md
171
173
  - doc/release_notes/0_3_0.md
@@ -378,7 +380,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
378
380
  - !ruby/object:Gem::Version
379
381
  version: '0'
380
382
  requirements: []
381
- rubygems_version: 3.3.7
383
+ rubygems_version: 3.2.32
382
384
  signing_key:
383
385
  specification_version: 4
384
386
  summary: HTTPX, to the future, and beyond