Bump httpx from 1.8.0 to 1.8.1#1025
Open
dependabot[bot] wants to merge 1 commit into
Open
Conversation
Bumps [httpx](https://gitlab.com/os85/httpx) from 1.8.0 to 1.8.1. - [Commits](https://gitlab.com/os85/httpx/compare/v1.8.0...v1.8.1) --- updated-dependencies: - dependency-name: httpx dependency-version: 1.8.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Contributor
4 similar comments
Contributor
Contributor
Contributor
Contributor
Contributor
gem compare http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT version:
1.2.0: 1.2.0
1.2.1: 1.2.1
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb +0/-1
lib/http/2/extensions.rb +9/-2
lib/http/2/version.rb +1/-1 |
4 similar comments
Contributor
gem compare http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT version:
1.2.0: 1.2.0
1.2.1: 1.2.1
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb +0/-1
lib/http/2/extensions.rb +9/-2
lib/http/2/version.rb +1/-1 |
Contributor
gem compare http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT version:
1.2.0: 1.2.0
1.2.1: 1.2.1
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb +0/-1
lib/http/2/extensions.rb +9/-2
lib/http/2/version.rb +1/-1 |
Contributor
gem compare http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT version:
1.2.0: 1.2.0
1.2.1: 1.2.1
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb +0/-1
lib/http/2/extensions.rb +9/-2
lib/http/2/version.rb +1/-1 |
Contributor
gem compare http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT version:
1.2.0: 1.2.0
1.2.1: 1.2.1
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb +0/-1
lib/http/2/extensions.rb +9/-2
lib/http/2/version.rb +1/-1 |
Contributor
gem compare --diff http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb
--- /tmp/d20260724-485-1dk78n/http-2-1.2.0/lib/http/2/connection.rb 2026-07-24 02:33:19.155393044 +0000
+++ /tmp/d20260724-485-1dk78n/http-2-1.2.1/lib/http/2/connection.rb 2026-07-24 02:33:19.161393029 +0000
@@ -402 +401,0 @@
- stream = @streams_recently_closed[stream_id]
lib/http/2/extensions.rb
--- /tmp/d20260724-485-1dk78n/http-2-1.2.0/lib/http/2/extensions.rb 2026-07-24 02:33:19.155393044 +0000
+++ /tmp/d20260724-485-1dk78n/http-2-1.2.1/lib/http/2/extensions.rb 2026-07-24 02:33:19.162393027 +0000
@@ -28,0 +29,7 @@
+ enc = str.encoding
+
+ if enc != Encoding::BINARY
+ str = str.dup if str.frozen?
+ str.force_encoding(Encoding::BINARY)
+ end
+
@@ -31 +38 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
@@ -40 +47 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
lib/http/2/version.rb
--- /tmp/d20260724-485-1dk78n/http-2-1.2.0/lib/http/2/version.rb 2026-07-24 02:33:19.158393036 +0000
+++ /tmp/d20260724-485-1dk78n/http-2-1.2.1/lib/http/2/version.rb 2026-07-24 02:33:19.164393022 +0000
@@ -4 +4 @@
- VERSION = "1.2.0"
+ VERSION = "1.2.1" |
Contributor
gem compare --diff http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb
--- /tmp/d20260724-488-r6mgv9/http-2-1.2.0/lib/http/2/connection.rb 2026-07-24 02:33:19.351513895 +0000
+++ /tmp/d20260724-488-r6mgv9/http-2-1.2.1/lib/http/2/connection.rb 2026-07-24 02:33:19.357513924 +0000
@@ -402 +401,0 @@
- stream = @streams_recently_closed[stream_id]
lib/http/2/extensions.rb
--- /tmp/d20260724-488-r6mgv9/http-2-1.2.0/lib/http/2/extensions.rb 2026-07-24 02:33:19.352513900 +0000
+++ /tmp/d20260724-488-r6mgv9/http-2-1.2.1/lib/http/2/extensions.rb 2026-07-24 02:33:19.357513924 +0000
@@ -28,0 +29,7 @@
+ enc = str.encoding
+
+ if enc != Encoding::BINARY
+ str = str.dup if str.frozen?
+ str.force_encoding(Encoding::BINARY)
+ end
+
@@ -31 +38 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
@@ -40 +47 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
lib/http/2/version.rb
--- /tmp/d20260724-488-r6mgv9/http-2-1.2.0/lib/http/2/version.rb 2026-07-24 02:33:19.353513905 +0000
+++ /tmp/d20260724-488-r6mgv9/http-2-1.2.1/lib/http/2/version.rb 2026-07-24 02:33:19.359513934 +0000
@@ -4 +4 @@
- VERSION = "1.2.0"
+ VERSION = "1.2.1" |
Contributor
gem compare --diff http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb
--- /tmp/d20260724-453-gve84v/http-2-1.2.0/lib/http/2/connection.rb 2026-07-24 02:33:20.090496024 +0000
+++ /tmp/d20260724-453-gve84v/http-2-1.2.1/lib/http/2/connection.rb 2026-07-24 02:33:20.102496276 +0000
@@ -402 +401,0 @@
- stream = @streams_recently_closed[stream_id]
lib/http/2/extensions.rb
--- /tmp/d20260724-453-gve84v/http-2-1.2.0/lib/http/2/extensions.rb 2026-07-24 02:33:20.090496024 +0000
+++ /tmp/d20260724-453-gve84v/http-2-1.2.1/lib/http/2/extensions.rb 2026-07-24 02:33:20.103496297 +0000
@@ -28,0 +29,7 @@
+ enc = str.encoding
+
+ if enc != Encoding::BINARY
+ str = str.dup if str.frozen?
+ str.force_encoding(Encoding::BINARY)
+ end
+
@@ -31 +38 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
@@ -40 +47 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
lib/http/2/version.rb
--- /tmp/d20260724-453-gve84v/http-2-1.2.0/lib/http/2/version.rb 2026-07-24 02:33:20.092496066 +0000
+++ /tmp/d20260724-453-gve84v/http-2-1.2.1/lib/http/2/version.rb 2026-07-24 02:33:20.104496318 +0000
@@ -4 +4 @@
- VERSION = "1.2.0"
+ VERSION = "1.2.1" |
Contributor
gem compare --diff http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb
--- /tmp/d20260724-485-n96ps3/http-2-1.2.0/lib/http/2/connection.rb 2026-07-24 02:33:19.278351185 +0000
+++ /tmp/d20260724-485-n96ps3/http-2-1.2.1/lib/http/2/connection.rb 2026-07-24 02:33:19.283351156 +0000
@@ -402 +401,0 @@
- stream = @streams_recently_closed[stream_id]
lib/http/2/extensions.rb
--- /tmp/d20260724-485-n96ps3/http-2-1.2.0/lib/http/2/extensions.rb 2026-07-24 02:33:19.278351185 +0000
+++ /tmp/d20260724-485-n96ps3/http-2-1.2.1/lib/http/2/extensions.rb 2026-07-24 02:33:19.283351156 +0000
@@ -28,0 +29,7 @@
+ enc = str.encoding
+
+ if enc != Encoding::BINARY
+ str = str.dup if str.frozen?
+ str.force_encoding(Encoding::BINARY)
+ end
+
@@ -31 +38 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
@@ -40 +47 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
lib/http/2/version.rb
--- /tmp/d20260724-485-n96ps3/http-2-1.2.0/lib/http/2/version.rb 2026-07-24 02:33:19.279351179 +0000
+++ /tmp/d20260724-485-n96ps3/http-2-1.2.1/lib/http/2/version.rb 2026-07-24 02:33:19.284351150 +0000
@@ -4 +4 @@
- VERSION = "1.2.0"
+ VERSION = "1.2.1" |
Contributor
gem compare --diff http-2 1.2.0 1.2.1Compared versions: ["1.2.0", "1.2.1"]
DIFFERENT files:
1.2.0->1.2.1:
* Changed:
lib/http/2/connection.rb
--- /tmp/d20260724-459-k2vhxf/http-2-1.2.0/lib/http/2/connection.rb 2026-07-24 02:33:25.936389731 +0000
+++ /tmp/d20260724-459-k2vhxf/http-2-1.2.1/lib/http/2/connection.rb 2026-07-24 02:33:25.949389724 +0000
@@ -402 +401,0 @@
- stream = @streams_recently_closed[stream_id]
lib/http/2/extensions.rb
--- /tmp/d20260724-459-k2vhxf/http-2-1.2.0/lib/http/2/extensions.rb 2026-07-24 02:33:25.936389731 +0000
+++ /tmp/d20260724-459-k2vhxf/http-2-1.2.1/lib/http/2/extensions.rb 2026-07-24 02:33:25.949389724 +0000
@@ -28,0 +29,7 @@
+ enc = str.encoding
+
+ if enc != Encoding::BINARY
+ str = str.dup if str.frozen?
+ str.force_encoding(Encoding::BINARY)
+ end
+
@@ -31 +38 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
@@ -40 +47 @@
- chunk
+ chunk.force_encoding(Encoding::BINARY)
lib/http/2/version.rb
--- /tmp/d20260724-459-k2vhxf/http-2-1.2.0/lib/http/2/version.rb 2026-07-24 02:33:25.938389730 +0000
+++ /tmp/d20260724-459-k2vhxf/http-2-1.2.1/lib/http/2/version.rb 2026-07-24 02:33:25.955389720 +0000
@@ -4 +4 @@
- VERSION = "1.2.0"
+ VERSION = "1.2.1" |
Contributor
gem compare httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT version:
1.8.0: 1.8.0
1.8.1: 1.8.1
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2
lib/httpx/adapters/datadog.rb +9/-0
lib/httpx/adapters/faraday.rb +2/-2
lib/httpx/adapters/webmock.rb +6/-0
lib/httpx/connection.rb +44/-15
lib/httpx/connection/http1.rb +7/-13
lib/httpx/connection/http2.rb +33/-6
lib/httpx/headers.rb +2/-2
lib/httpx/io/ssl.rb +8/-9
lib/httpx/io/tcp.rb +11/-4
lib/httpx/io/unix.rb +2/-2
lib/httpx/loggable.rb +11/-4
lib/httpx/plugins/auth.rb +11/-2
lib/httpx/plugins/auth/digest.rb +1/-1
lib/httpx/plugins/callbacks.rb +12/-0
lib/httpx/plugins/digest_auth.rb +4/-0
lib/httpx/plugins/fiber_concurrency.rb +25/-1
lib/httpx/plugins/persistent.rb +18/-2
lib/httpx/plugins/push_promise.rb +2/-2
lib/httpx/plugins/ssrf_filter.rb +1/-1
lib/httpx/plugins/stream.rb +2/-2
lib/httpx/plugins/stream_bidi.rb +2/-0
lib/httpx/pool.rb +2/-2
lib/httpx/request.rb +24/-9
lib/httpx/request/body.rb +2/-2
lib/httpx/resolver/cache/base.rb +1/-8
lib/httpx/resolver/https.rb +19/-19
lib/httpx/resolver/native.rb +7/-0
lib/httpx/resolver/resolver.rb +4/-0
lib/httpx/resolver/system.rb +5/-2
lib/httpx/response.rb +3/-4
lib/httpx/response/body.rb +2/-2
lib/httpx/selector.rb +5/-0
lib/httpx/session.rb +6/-1
lib/httpx/session_extensions.rb +2/-2
lib/httpx/timers.rb +3/-0
lib/httpx/version.rb +1/-1
sig/connection.rbs +5/-1
sig/connection/http2.rbs +3/-0
sig/loggable.rbs +4/-0
sig/plugins/auth.rbs +4/-0
sig/plugins/persistent.rbs +3/-0
sig/request.rbs +2/-3
sig/resolver/system.rbs +3/-0
sig/selector.rbs +2/-0
sig/timers.rbs +2/-0
DIFFERENT extra_rdoc_files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2 |
4 similar comments
Contributor
gem compare httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT version:
1.8.0: 1.8.0
1.8.1: 1.8.1
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2
lib/httpx/adapters/datadog.rb +9/-0
lib/httpx/adapters/faraday.rb +2/-2
lib/httpx/adapters/webmock.rb +6/-0
lib/httpx/connection.rb +44/-15
lib/httpx/connection/http1.rb +7/-13
lib/httpx/connection/http2.rb +33/-6
lib/httpx/headers.rb +2/-2
lib/httpx/io/ssl.rb +8/-9
lib/httpx/io/tcp.rb +11/-4
lib/httpx/io/unix.rb +2/-2
lib/httpx/loggable.rb +11/-4
lib/httpx/plugins/auth.rb +11/-2
lib/httpx/plugins/auth/digest.rb +1/-1
lib/httpx/plugins/callbacks.rb +12/-0
lib/httpx/plugins/digest_auth.rb +4/-0
lib/httpx/plugins/fiber_concurrency.rb +25/-1
lib/httpx/plugins/persistent.rb +18/-2
lib/httpx/plugins/push_promise.rb +2/-2
lib/httpx/plugins/ssrf_filter.rb +1/-1
lib/httpx/plugins/stream.rb +2/-2
lib/httpx/plugins/stream_bidi.rb +2/-0
lib/httpx/pool.rb +2/-2
lib/httpx/request.rb +24/-9
lib/httpx/request/body.rb +2/-2
lib/httpx/resolver/cache/base.rb +1/-8
lib/httpx/resolver/https.rb +19/-19
lib/httpx/resolver/native.rb +7/-0
lib/httpx/resolver/resolver.rb +4/-0
lib/httpx/resolver/system.rb +5/-2
lib/httpx/response.rb +3/-4
lib/httpx/response/body.rb +2/-2
lib/httpx/selector.rb +5/-0
lib/httpx/session.rb +6/-1
lib/httpx/session_extensions.rb +2/-2
lib/httpx/timers.rb +3/-0
lib/httpx/version.rb +1/-1
sig/connection.rbs +5/-1
sig/connection/http2.rbs +3/-0
sig/loggable.rbs +4/-0
sig/plugins/auth.rbs +4/-0
sig/plugins/persistent.rbs +3/-0
sig/request.rbs +2/-3
sig/resolver/system.rbs +3/-0
sig/selector.rbs +2/-0
sig/timers.rbs +2/-0
DIFFERENT extra_rdoc_files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2 |
Contributor
gem compare httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT version:
1.8.0: 1.8.0
1.8.1: 1.8.1
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2
lib/httpx/adapters/datadog.rb +9/-0
lib/httpx/adapters/faraday.rb +2/-2
lib/httpx/adapters/webmock.rb +6/-0
lib/httpx/connection.rb +44/-15
lib/httpx/connection/http1.rb +7/-13
lib/httpx/connection/http2.rb +33/-6
lib/httpx/headers.rb +2/-2
lib/httpx/io/ssl.rb +8/-9
lib/httpx/io/tcp.rb +11/-4
lib/httpx/io/unix.rb +2/-2
lib/httpx/loggable.rb +11/-4
lib/httpx/plugins/auth.rb +11/-2
lib/httpx/plugins/auth/digest.rb +1/-1
lib/httpx/plugins/callbacks.rb +12/-0
lib/httpx/plugins/digest_auth.rb +4/-0
lib/httpx/plugins/fiber_concurrency.rb +25/-1
lib/httpx/plugins/persistent.rb +18/-2
lib/httpx/plugins/push_promise.rb +2/-2
lib/httpx/plugins/ssrf_filter.rb +1/-1
lib/httpx/plugins/stream.rb +2/-2
lib/httpx/plugins/stream_bidi.rb +2/-0
lib/httpx/pool.rb +2/-2
lib/httpx/request.rb +24/-9
lib/httpx/request/body.rb +2/-2
lib/httpx/resolver/cache/base.rb +1/-8
lib/httpx/resolver/https.rb +19/-19
lib/httpx/resolver/native.rb +7/-0
lib/httpx/resolver/resolver.rb +4/-0
lib/httpx/resolver/system.rb +5/-2
lib/httpx/response.rb +3/-4
lib/httpx/response/body.rb +2/-2
lib/httpx/selector.rb +5/-0
lib/httpx/session.rb +6/-1
lib/httpx/session_extensions.rb +2/-2
lib/httpx/timers.rb +3/-0
lib/httpx/version.rb +1/-1
sig/connection.rbs +5/-1
sig/connection/http2.rbs +3/-0
sig/loggable.rbs +4/-0
sig/plugins/auth.rbs +4/-0
sig/plugins/persistent.rbs +3/-0
sig/request.rbs +2/-3
sig/resolver/system.rbs +3/-0
sig/selector.rbs +2/-0
sig/timers.rbs +2/-0
DIFFERENT extra_rdoc_files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2 |
Contributor
gem compare httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT version:
1.8.0: 1.8.0
1.8.1: 1.8.1
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2
lib/httpx/adapters/datadog.rb +9/-0
lib/httpx/adapters/faraday.rb +2/-2
lib/httpx/adapters/webmock.rb +6/-0
lib/httpx/connection.rb +44/-15
lib/httpx/connection/http1.rb +7/-13
lib/httpx/connection/http2.rb +33/-6
lib/httpx/headers.rb +2/-2
lib/httpx/io/ssl.rb +8/-9
lib/httpx/io/tcp.rb +11/-4
lib/httpx/io/unix.rb +2/-2
lib/httpx/loggable.rb +11/-4
lib/httpx/plugins/auth.rb +11/-2
lib/httpx/plugins/auth/digest.rb +1/-1
lib/httpx/plugins/callbacks.rb +12/-0
lib/httpx/plugins/digest_auth.rb +4/-0
lib/httpx/plugins/fiber_concurrency.rb +25/-1
lib/httpx/plugins/persistent.rb +18/-2
lib/httpx/plugins/push_promise.rb +2/-2
lib/httpx/plugins/ssrf_filter.rb +1/-1
lib/httpx/plugins/stream.rb +2/-2
lib/httpx/plugins/stream_bidi.rb +2/-0
lib/httpx/pool.rb +2/-2
lib/httpx/request.rb +24/-9
lib/httpx/request/body.rb +2/-2
lib/httpx/resolver/cache/base.rb +1/-8
lib/httpx/resolver/https.rb +19/-19
lib/httpx/resolver/native.rb +7/-0
lib/httpx/resolver/resolver.rb +4/-0
lib/httpx/resolver/system.rb +5/-2
lib/httpx/response.rb +3/-4
lib/httpx/response/body.rb +2/-2
lib/httpx/selector.rb +5/-0
lib/httpx/session.rb +6/-1
lib/httpx/session_extensions.rb +2/-2
lib/httpx/timers.rb +3/-0
lib/httpx/version.rb +1/-1
sig/connection.rbs +5/-1
sig/connection/http2.rbs +3/-0
sig/loggable.rbs +4/-0
sig/plugins/auth.rbs +4/-0
sig/plugins/persistent.rbs +3/-0
sig/request.rbs +2/-3
sig/resolver/system.rbs +3/-0
sig/selector.rbs +2/-0
sig/timers.rbs +2/-0
DIFFERENT extra_rdoc_files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2 |
Contributor
gem compare httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT version:
1.8.0: 1.8.0
1.8.1: 1.8.1
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2
lib/httpx/adapters/datadog.rb +9/-0
lib/httpx/adapters/faraday.rb +2/-2
lib/httpx/adapters/webmock.rb +6/-0
lib/httpx/connection.rb +44/-15
lib/httpx/connection/http1.rb +7/-13
lib/httpx/connection/http2.rb +33/-6
lib/httpx/headers.rb +2/-2
lib/httpx/io/ssl.rb +8/-9
lib/httpx/io/tcp.rb +11/-4
lib/httpx/io/unix.rb +2/-2
lib/httpx/loggable.rb +11/-4
lib/httpx/plugins/auth.rb +11/-2
lib/httpx/plugins/auth/digest.rb +1/-1
lib/httpx/plugins/callbacks.rb +12/-0
lib/httpx/plugins/digest_auth.rb +4/-0
lib/httpx/plugins/fiber_concurrency.rb +25/-1
lib/httpx/plugins/persistent.rb +18/-2
lib/httpx/plugins/push_promise.rb +2/-2
lib/httpx/plugins/ssrf_filter.rb +1/-1
lib/httpx/plugins/stream.rb +2/-2
lib/httpx/plugins/stream_bidi.rb +2/-0
lib/httpx/pool.rb +2/-2
lib/httpx/request.rb +24/-9
lib/httpx/request/body.rb +2/-2
lib/httpx/resolver/cache/base.rb +1/-8
lib/httpx/resolver/https.rb +19/-19
lib/httpx/resolver/native.rb +7/-0
lib/httpx/resolver/resolver.rb +4/-0
lib/httpx/resolver/system.rb +5/-2
lib/httpx/response.rb +3/-4
lib/httpx/response/body.rb +2/-2
lib/httpx/selector.rb +5/-0
lib/httpx/session.rb +6/-1
lib/httpx/session_extensions.rb +2/-2
lib/httpx/timers.rb +3/-0
lib/httpx/version.rb +1/-1
sig/connection.rbs +5/-1
sig/connection/http2.rbs +3/-0
sig/loggable.rbs +4/-0
sig/plugins/auth.rbs +4/-0
sig/plugins/persistent.rbs +3/-0
sig/request.rbs +2/-3
sig/resolver/system.rbs +3/-0
sig/selector.rbs +2/-0
sig/timers.rbs +2/-0
DIFFERENT extra_rdoc_files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md +27/-0
* Changed:
doc/release_notes/1_7_1.md +1/-2 |
Contributor
gem compare --diff httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md
--- /tmp/20260724-2663-8guc1g 2026-07-24 02:33:47.075071626 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/doc/release_notes/1_8_1.md 2026-07-24 02:33:47.048071056 +0000
@@ -0,0 +1,27 @@
+# 1.8.1
+
+## Improvements
+
+* the session will now eagerly write initial data to connections instead of waiting for I/O the first time (saves a syscall).
+* removed all rescue blocks rescuing `StandardError` internally; this could interfere with usages of `httpx` inside `Timeout.timeout` blocks, which may emit an exception at any point, including in blocks where that exception could be rescued, leaving the session in a potentially irrecoverable state and looping.
+* debug logs change the display of ids from 'tid:123, fid:123' to 'tid=123 fid:123'.
+ * and when using the `datadog` adapter, all related correlation ids (trace id, span id, etc) will also be added to the identifiers in the same format
+* plugins built on top of the `:retries` plugin will skip the `retry_after` interval when certain conditions are met.
+ * `:persistent` plugin: request will be retried immediately, when the error happens after the keep alive interval expired.
+ * `:auth` plugin: request will be retried immediately if it failed due to a "401 Unauthorized Error".
+* `:ssrf_filter` plugin: removed public/private references of exception message.
+
+## Bugfixes
+
+* `:auth` plugin: handle edge case where `:auth_header_expires_at` returns no value.
+* `:digest_auth` plugin: do not retry if there was an issue building building the authorization header after the probe.
+* `webmock` adapter: prevent mocked requests from opening a connection to the peer server that will not be used.
+* clear and cancel request timers on completion or reset, ensuring that they won't be retained way past the point where the request is gone.
+* connection: cancel and discard ping timer before closing (removes timer reference)
+* connection: fix logic where purging-while-resending requests to a coalesced connection was leaving references in the old connection.
+* moved an `on_body_chunk` callback to the `:callbacks` plugin, where it's used and expected to be defined.
+* `http2`: avoid closing the connection on internal errors which are supposed to be specific to a request, such as the max headers or max response body size checks.
+* system resolver will use an internal exception when using `Timeout.timeout` on resolutions to avoid conflicts with the default timeout exception class.
+* prevent edge case where `#alpn_protocol` was being called on a `TCPSocket`.
+* fixed v1.8.0 regression causing connection to loop when an error happens while connecting.
+* resolver cache: fixed cache eviction logic, where alias answers weren't being evicted, causing resolutions to stall after a certain number of resolutions.
* Changed:
doc/release_notes/1_7_1.md
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/doc/release_notes/1_7_1.md 2026-07-24 02:33:47.009070233 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/doc/release_notes/1_7_1.md 2026-07-24 02:33:47.048071056 +0000
@@ -20,2 +20 @@
-* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
-*
\ No newline at end of file
+* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
\ No newline at end of file
lib/httpx/adapters/datadog.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:47.011070275 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:47.049071077 +0000
@@ -187,0 +188,7 @@
+ # patches httpx debug logs to include datadog correlation ids
+ module LoggablePatch
+ def log_identifiers
+ "#{super} #{Datadog::Tracing.log_correlation}"
+ end
+ end
+
@@ -299,0 +307,2 @@
+
+ ::HTTPX::Loggable.singleton_class.prepend(LoggablePatch)
lib/httpx/adapters/faraday.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:47.011070275 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:47.049071077 +0000
@@ -118 +118 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/adapters/webmock.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:47.011070275 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:47.049071077 +0000
@@ -157,0 +158,6 @@
+
+ private
+
+ def connect
+ super unless @mocked
+ end
lib/httpx/connection.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/connection.rb 2026-07-24 02:33:47.012070296 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/connection.rb 2026-07-24 02:33:47.050071098 +0000
@@ -164 +163,0 @@
- pendings = []
@@ -168 +167,4 @@
- pendings << pending
+ pending.reject! do |req|
+ block.call(req)
+ true
+ end
@@ -170,3 +172,3 @@
- pendings << @pending
- pendings.each do |pending|
- pending.reject!(&block)
+ @pending.reject! do |req|
+ block.call(req)
+ true
@@ -206 +208 @@
- rescue StandardError => e
+ rescue Error => e
@@ -217,0 +220,2 @@
+ return if no_more_requests?
+
@@ -225 +229 @@
- return if @pending.empty?
+ return if no_more_requests?
@@ -250 +254,5 @@
- rescue IOError => e
+ rescue Errno::ECONNRESET,
+ Errno::EINVAL,
+ SocketError,
+ IOError,
+ TLSError => e
@@ -253 +261 @@
- rescue StandardError => e
+ rescue Error => e
@@ -260,0 +269,4 @@
+ def initial_call
+ call
+ end
+
@@ -316,0 +329,5 @@
+ if @ping_timer
+ @ping_timer.cancel
+ @ping_timer = nil
+ end
+
@@ -435,0 +453,5 @@
+
+ # do not force close if parser resets the connection.
+ # can happen i.e. when HTTP/1.1 pipelining is disabled.
+ return if @state == :idle && @pending.any?
+
@@ -459 +481 @@
- # :nocov:
+ # simplecov:disable
@@ -467 +489 @@
- # :nocov:
+ # simplecov:enable
@@ -493 +515 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty?
+ if no_more_requests? && @write_buffer.empty?
@@ -543 +565 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty? # rubocop:disable Style/Next
+ if no_more_requests? && @write_buffer.empty? # rubocop:disable Style/Next
@@ -962,0 +985 @@
+ log(level: 3) { "ping timeout expired..." }
@@ -988,0 +1012,5 @@
+ # true when there are no more pending nor inflight (in parser) requests
+ def no_more_requests?
+ @pending.empty? && @inflight.zero?
+ end
+
@@ -1102 +1130,2 @@
- request.active_timeouts << label
+ timer.label = label
+ request.active_timeouts << timer
@@ -1108 +1137 @@
- request.active_timeouts.delete(label)
+ request.active_timeouts.delete(timer)
lib/httpx/connection/http1.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/connection/http1.rb 2026-07-24 02:33:47.012070296 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/connection/http1.rb 2026-07-24 02:33:47.050071098 +0000
@@ -165,12 +165,6 @@
- begin
- request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
- request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
-
- response = request.response
-
- response << chunk
- rescue StandardError => e
- error_response = ErrorResponse.new(request, e)
- request.response = error_response
- dispatch(request)
- end
+ request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
+ request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
+
+ response = request.response
+
+ response << chunk
@@ -419 +413 @@
- UPCASED[field] || field.split("-").map(&:capitalize).join("-")
+ UPCASED.fetch(field) { field.split("-").map(&:capitalize).join("-") }
lib/httpx/connection/http2.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/connection/http2.rb 2026-07-24 02:33:47.012070296 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/connection/http2.rb 2026-07-24 02:33:47.050071098 +0000
@@ -39,0 +40 @@
+ @streams_to_close_after_receive = []
@@ -112,0 +114,6 @@
+
+ while (stream, request, error = @streams_to_close_after_receive.shift)
+ # these streams were marked for cancellation due to errors found while processing the
+ # data received by the peer.
+ emit_stream_error(stream, request, error)
+ end
@@ -131 +138 @@
- rescue StandardError => e
+ rescue ::HTTP2::Error::Error, ArgumentError => e
@@ -335,0 +343,2 @@
+ rescue HTTPX::Error => e
+ @streams_to_close_after_receive << [stream, request, e]
@@ -347,0 +357,3 @@
+
+ return unless request.response
+
@@ -348,0 +361,8 @@
+ rescue HTTPX::Error => e
+ if stream.state == :closing
+ # there won't be any more chunks to process after this one.
+ emit_stream_error(stream, request, e)
+ else
+ # defer until the last chunk from the payload is processed.
+ @streams_to_close_after_receive << [stream, request, e]
+ end
@@ -384,5 +404,6 @@
- response = request.response
- if response && response.is_a?(Response) && response.status == 421
- emit(:error, request, :http_1_1_required)
- else
- emit(:response, request, response)
+ if (response = request.response)
+ if response.is_a?(Response) && response.status == 421
+ emit(:error, request, :http_1_1_required)
+ else
+ emit(:response, request, response)
+ end
@@ -509,0 +531,6 @@
+ end
+
+ def emit_stream_error(stream, request, error)
+ teardown(request)
+ stream.close
+ emit(:error, request, error)
lib/httpx/headers.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/headers.rb 2026-07-24 02:33:47.012070296 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/headers.rb 2026-07-24 02:33:47.051071119 +0000
@@ -143 +143 @@
- # :nocov:
+ # simplecov:disable
@@ -148 +148 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/ssl.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/io/ssl.rb 2026-07-24 02:33:47.013070318 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/io/ssl.rb 2026-07-24 02:33:47.051071119 +0000
@@ -23,2 +23,3 @@
- ctx_options = TLS_OPTIONS.merge(options.ssl)
- @sni_hostname = ctx_options.delete(:hostname) || @hostname
+ ctx_options = TLS_OPTIONS
+ ctx_options = ctx_options.merge(options.ssl) if options.ssl && !options.ssl.empty?
+ @sni_hostname = (ctx_options.delete(:hostname) if ctx_options.key?(:hostname)) || @hostname
@@ -32 +33 @@
- @ctx.set_params(ctx_options) unless ctx_options.empty?
+ @ctx.set_params(ctx_options)
@@ -54 +55,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -56,2 +57,0 @@
- rescue StandardError
- super
@@ -64 +64,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -70,2 +70,0 @@
- rescue StandardError
- super
lib/httpx/io/tcp.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/io/tcp.rb 2026-07-24 02:33:47.013070318 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/io/tcp.rb 2026-07-24 02:33:47.051071119 +0000
@@ -185 +185,8 @@
- return if @keep_open || closed?
+ return if @keep_open
+
+ # mark tcp as closed, so that it can be disconnected.
+ # this bypasses the state machine API as not not allow the transition
+ # from idle to closed in normal circumstances.
+ @state = :closed if @state == :idle
+
+ return if closed?
@@ -189 +196 @@
- rescue StandardError => e
+ rescue IOError => e
@@ -215 +222 @@
- # :nocov:
+ # simplecov:disable
@@ -224 +231 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/unix.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/io/unix.rb 2026-07-24 02:33:47.013070318 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/io/unix.rb 2026-07-24 02:33:47.051071119 +0000
@@ -63 +63 @@
- # :nocov:
+ # simplecov:disable
@@ -67 +67 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/loggable.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/loggable.rb 2026-07-24 02:33:47.013070318 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/loggable.rb 2026-07-24 02:33:47.052071141 +0000
@@ -19,0 +20,6 @@
+ def self.log_identifiers
+ "pid=#{Process.pid} " \
+ "tid=#{Thread.current.object_id} " \
+ "fid=#{Fiber.current.object_id}"
+ end
+
@@ -39,4 +45,3 @@
- message = +"(time:#{Time.now.utc}, pid:#{Process.pid}, " \
- "tid:#{Thread.current.object_id}, " \
- "fid:#{Fiber.current.object_id}, " \
- "self:#{class_name}##{object_id}) "
+ message = +"(time=#{Time.now.utc} " \
+ "#{Loggable.log_identifiers} " \
+ "self=#{class_name}##{object_id}) "
@@ -50,0 +56,2 @@
+
+ private
lib/httpx/plugins/auth.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/auth.rb 2026-07-24 02:33:47.014070339 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/auth.rb 2026-07-24 02:33:47.052071141 +0000
@@ -130,2 +130,2 @@
- if expires_at.respond_to?(:call)
- expires_at = expires_at.call(request).to_f
+ if expires_at.respond_to?(:call) && (expires_at = expires_at.call(request))
+ expires_at = expires_at.to_f
@@ -204,0 +205,9 @@
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(Response)
+
+ # retry immediately if authentication no longer valid.
+ return if response.status == 401
+
+ super
lib/httpx/plugins/auth/digest.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:47.014070339 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:47.053071162 +0000
@@ -27 +27 @@
- rescue StandardError => e
+ rescue HTTPX::Error => e
lib/httpx/plugins/callbacks.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:47.015070360 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:47.054071183 +0000
@@ -124,0 +125,12 @@
+ module RequestMethods
+ def drain_body
+ super.tap do |chunk|
+ emit(:body_chunk, chunk) if chunk
+ rescue StandardError => e
+ # in case an error occurs in callback code
+ @drain_error = e
+ nil
+ end
+ end
+ end
+
lib/httpx/plugins/digest_auth.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:47.016070381 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:47.055071204 +0000
@@ -53,0 +54 @@
+
@@ -56,0 +58,3 @@
+
+ next(request.response) if request.response
+
lib/httpx/plugins/fiber_concurrency.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:47.016070381 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:47.055071204 +0000
@@ -72,0 +73,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -195,0 +202,6 @@
+ def initial_call
+ return unless @queries.values.any?(&:current_context?) || @connections.any?(&:current_context?)
+
+ super
+ end
+
@@ -220,0 +233,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -222 +240 @@
- return unless @queries.any? { |_, conn| conn.current_context? }
+ return unless current_context?
@@ -224,0 +243,6 @@
+ end
+
+ private
+
+ def current_context?
+ @queries.any? { |_, conn| conn.current_context? }
lib/httpx/plugins/persistent.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:47.018070423 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:47.056071225 +0000
@@ -57,0 +58,16 @@
+ def reconnectable_error?(error)
+ Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(ErrorResponse)
+
+ error = response.error
+ # allow request to be retried immediately if the request failed right after the keep alive timeout.
+ # the chances are, the request failed because the connect has been dropped by the peer server, so it's
+ # fine to reopen.
+ return if request.ping? && reconnectable_error?(error)
+
+ super
+ end
+
@@ -60 +76 @@
- return false unless response && response.is_a?(ErrorResponse)
+ return false unless response.is_a?(ErrorResponse)
@@ -64 +80 @@
- Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ reconnectable_error?(error)
lib/httpx/plugins/push_promise.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:47.018070423 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:47.057071246 +0000
@@ -47 +47 @@
- # :nocov:
+ # simplecov:disable
@@ -49 +49 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/ssrf_filter.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:47.019070444 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:47.058071267 +0000
@@ -152 +152 @@
- raise ServerSideRequestForgeryError, "#{@origin.host} has no public IP addresses" if addrs.empty?
+ raise ServerSideRequestForgeryError, "#{@origin.host} has no allowed IP addresses" if addrs.empty?
lib/httpx/plugins/stream.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/stream.rb 2026-07-24 02:33:47.019070444 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/stream.rb 2026-07-24 02:33:47.058071267 +0000
@@ -78 +78 @@
- # :nocov:
+ # simplecov:disable
@@ -82 +82 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/stream_bidi.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:47.019070444 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:47.058071267 +0000
@@ -179,0 +180,2 @@
+ def initial_call; end
+
lib/httpx/pool.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/pool.rb 2026-07-24 02:33:47.020070465 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/pool.rb 2026-07-24 02:33:47.059071288 +0000
@@ -176 +176 @@
- # :nocov:
+ # simplecov:disable
@@ -184 +184 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/request.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/request.rb 2026-07-24 02:33:47.020070465 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/request.rb 2026-07-24 02:33:47.059071288 +0000
@@ -124,0 +125 @@
+ reset_timers(true)
@@ -271 +272 @@
- return nil if @body.nil?
+ return if @body.nil?
@@ -274,4 +275 @@
- chunk = @drainer.next.dup
-
- emit(:body_chunk, chunk)
- chunk
+ @drainer.next.dup
@@ -280,0 +279 @@
+ # in case an error occurs while emitting body chunks
@@ -285 +284 @@
- # :nocov:
+ # simplecov:disable
@@ -293 +292 @@
- # :nocov:
+ # simplecov:enable
@@ -302 +301,4 @@
- @active_timeouts.clear
+
+ # request may be sent to a different connection and will be
+ # reassigned a new set of timers.
+ reset_timers(false)
@@ -329 +331 @@
- log(level: 3) { "#{@state}] -> #{nextstate}" }
+ log(level: 3) { "#{@state} -> #{nextstate}" }
@@ -364,0 +367,13 @@
+ end
+
+ private
+
+ def reset_timers(reset_total_request_timers)
+ timers = @active_timeouts
+
+ until (timer = timers.shift).nil?
+ next if !reset_total_request_timers && timer.label == :total_request_timeout
+
+ # cancel active timers.
+ timer.cancel
+ end
lib/httpx/request/body.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/request/body.rb 2026-07-24 02:33:47.021070486 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/request/body.rb 2026-07-24 02:33:47.059071288 +0000
@@ -117 +117 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/resolver/cache/base.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:47.021070486 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:47.060071309 +0000
@@ -109,8 +109 @@
- lookups[name] ||= []
-
- case family
- when Socket::AF_INET6
- lookups[name] << entry
- when Socket::AF_INET
- lookups[name].unshift(entry)
- end
+ _set(name, family, [entry], lookups, hostnames)
lib/httpx/resolver/https.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/resolver/https.rb 2026-07-24 02:33:47.022070508 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/resolver/https.rb 2026-07-24 02:33:47.060071309 +0000
@@ -129,13 +129,12 @@
- response.raise_for_status
- rescue StandardError => e
- hostname = @requests.delete(request)
- connection = reset_hostname(hostname)
- emit_resolve_error(connection, connection.peer.host, e)
- close_or_resolve
- else
- # @type var response: HTTPX::Response
- if response.status.between?(300, 399) && response.headers.key?("location")
- hostname = @requests[request]
- connection = @queries[hostname]
- location_uri = URI(response.headers["location"])
- location_uri = response.uri.merge(location_uri) if location_uri.relative?
+ if (e = response.error)
+ hostname = @requests.delete(request)
+ connection = reset_hostname(hostname)
+ emit_resolve_error(connection, connection.peer.host, e)
+ close_or_resolve
+ else
+ # @type var response: HTTPX::Response
+ if response.status.between?(300, 399) && response.headers.key?("location")
+ hostname = @requests[request]
+ connection = @queries[hostname]
+ location_uri = URI(response.headers["location"])
+ location_uri = response.uri.merge(location_uri) if location_uri.relative?
@@ -143,5 +142,5 @@
- # we assume that the DNS server URI changed permanently and move on
- @uri = location_uri
- send_request(hostname, connection)
- return
- end
+ # we assume that the DNS server URI changed permanently and move on
+ @uri = location_uri
+ send_request(hostname, connection)
+ return
+ end
@@ -149 +148,2 @@
- parse(request, response)
+ parse(request, response)
+ end
lib/httpx/resolver/native.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/resolver/native.rb 2026-07-24 02:33:47.022070508 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/resolver/native.rb 2026-07-24 02:33:47.060071309 +0000
@@ -77,0 +78,7 @@
+ when :idle, :closed
+ return if @connections.empty?
+
+ transition(:idle) if @state == :closed
+ transition(:open)
+
+ consume if @state == :open
lib/httpx/resolver/resolver.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:47.022070508 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:47.061071331 +0000
@@ -54,0 +55,4 @@
+ def initial_call
+ call
+ end
+
lib/httpx/resolver/system.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/resolver/system.rb 2026-07-24 02:33:47.022070508 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/resolver/system.rb 2026-07-24 02:33:47.061071331 +0000
@@ -25,0 +26,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
@@ -230 +233 @@
- Timeout.timeout(resolve_timeout) do
+ Timeout.timeout(resolve_timeout, AddrinfoTimeoutError) do
@@ -249 +252 @@
- if e.is_a?(Timeout::Error)
+ if e.is_a?(AddrinfoTimeoutError)
lib/httpx/response.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/response.rb 2026-07-24 02:33:47.023070529 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/response.rb 2026-07-24 02:33:47.061071331 +0000
@@ -144 +144 @@
- # :nocov:
+ # simplecov:disable
@@ -152 +152 @@
- # :nocov:
+ # simplecov:enable
@@ -270 +269,0 @@
- include Loggable
@@ -293 +292 @@
- log_exception(@error)
+ @request.log_exception(@error)
lib/httpx/response/body.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/response/body.rb 2026-07-24 02:33:47.023070529 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/response/body.rb 2026-07-24 02:33:47.061071331 +0000
@@ -164 +164 @@
- # :nocov:
+ # simplecov:disable
@@ -170 +170 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/selector.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/selector.rb 2026-07-24 02:33:47.023070529 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/selector.rb 2026-07-24 02:33:47.061071331 +0000
@@ -43,0 +44,5 @@
+ # first time the registered selectables are added, there's probably work to do.
+ def initial_call
+ @selectables.each(&:initial_call)
+ end
+
lib/httpx/session.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/session.rb 2026-07-24 02:33:47.023070529 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/session.rb 2026-07-24 02:33:47.061071331 +0000
@@ -322 +322 @@
- responses = requests.each_with_index.map do |request, idx|
+ requests.each do |request|
@@ -323,0 +324,4 @@
+ end
+
+ # do work first
+ selector.initial_call
@@ -324,0 +329 @@
+ responses = requests.each_with_index.map do |request, idx|
lib/httpx/session_extensions.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/session_extensions.rb 2026-07-24 02:33:47.023070529 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/session_extensions.rb 2026-07-24 02:33:47.062071352 +0000
@@ -23 +23 @@
- # :nocov:
+ # simplecov:disable
@@ -29 +29 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/timers.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/timers.rb 2026-07-24 02:33:47.023070529 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/timers.rb 2026-07-24 02:33:47.062071352 +0000
@@ -64,0 +65,3 @@
+ # simpler helper which allows classification
+ attr_accessor :label
+
lib/httpx/version.rb
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/lib/httpx/version.rb 2026-07-24 02:33:47.025070571 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/lib/httpx/version.rb 2026-07-24 02:33:47.063071373 +0000
@@ -4 +4 @@
- VERSION = "1.8.0"
+ VERSION = "1.8.1"
sig/connection.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/connection.rbs 2026-07-24 02:33:47.026070592 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/connection.rbs 2026-07-24 02:33:47.064071394 +0000
@@ -94,0 +95,2 @@
+ def initial_call: () -> void
+
@@ -125 +127 @@
- def on_io_error: (IOError error) -> void
+ def on_io_error: (SocketError | IOError | TLSError error) -> void
@@ -165,0 +168,2 @@
+
+ def no_more_requests?: () -> bool
sig/connection/http2.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/connection/http2.rbs 2026-07-24 02:33:47.026070592 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/connection/http2.rbs 2026-07-24 02:33:47.064071394 +0000
@@ -18,0 +19 @@
+ @streams_to_close_after_receive: Array[[HTTP2::Stream, Request, HTTPX::Error]]
@@ -107,0 +109,2 @@
+
+ def emit_stream_error: (HTTP2::Stream stream, Request request, StandardError error) -> void
sig/loggable.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/loggable.rbs 2026-07-24 02:33:47.027070613 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/loggable.rbs 2026-07-24 02:33:47.065071415 +0000
@@ -14,0 +15,2 @@
+ def self.log_identifiers: () -> String
+
@@ -17,0 +20,2 @@
+
+ private
sig/plugins/auth.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/plugins/auth.rbs 2026-07-24 02:33:47.027070613 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/plugins/auth.rbs 2026-07-24 02:33:47.065071415 +0000
@@ -9,0 +10,4 @@
+
+ def auth_header_expires_at: () -> (^(Request request) -> _ToF?)?
+
+ def auth_header_expires_in: () -> Float?
sig/plugins/persistent.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/plugins/persistent.rbs 2026-07-24 02:33:47.030070676 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/plugins/persistent.rbs 2026-07-24 02:33:47.069071499 +0000
@@ -8,0 +9,3 @@
+ private
+
+ def reconnectable_error?: (StandardError error) -> bool
sig/request.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/request.rbs 2026-07-24 02:33:47.032070719 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/request.rbs 2026-07-24 02:33:47.071071542 +0000
@@ -20 +20 @@
- attr_reader active_timeouts: Array[Symbol]
+ attr_reader active_timeouts: Array[Timers::Timer]
@@ -96,2 +96 @@
- def initialize_body: (Options options) -> Transcoder::_Encoder?
-
+ def reset_timers: (bool reset_total_request_timers) -> void
sig/resolver/system.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/resolver/system.rbs 2026-07-24 02:33:47.034070761 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/resolver/system.rbs 2026-07-24 02:33:47.072071563 +0000
@@ -7,0 +8,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
sig/selector.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/selector.rbs 2026-07-24 02:33:47.034070761 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/selector.rbs 2026-07-24 02:33:47.073071584 +0000
@@ -8,0 +9,2 @@
+ def initial_call: () -> void
+
sig/timers.rbs
--- /tmp/d20260724-2663-injf86/httpx-1.8.0/sig/timers.rbs 2026-07-24 02:33:47.034070761 +0000
+++ /tmp/d20260724-2663-injf86/httpx-1.8.1/sig/timers.rbs 2026-07-24 02:33:47.073071584 +0000
@@ -50,0 +51,2 @@
+ attr_accessor label: Symbol?
+ |
Contributor
gem compare --diff httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md
--- /tmp/20260724-2693-hmr1qj 2026-07-24 02:33:47.559767191 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/doc/release_notes/1_8_1.md 2026-07-24 02:33:47.521766942 +0000
@@ -0,0 +1,27 @@
+# 1.8.1
+
+## Improvements
+
+* the session will now eagerly write initial data to connections instead of waiting for I/O the first time (saves a syscall).
+* removed all rescue blocks rescuing `StandardError` internally; this could interfere with usages of `httpx` inside `Timeout.timeout` blocks, which may emit an exception at any point, including in blocks where that exception could be rescued, leaving the session in a potentially irrecoverable state and looping.
+* debug logs change the display of ids from 'tid:123, fid:123' to 'tid=123 fid:123'.
+ * and when using the `datadog` adapter, all related correlation ids (trace id, span id, etc) will also be added to the identifiers in the same format
+* plugins built on top of the `:retries` plugin will skip the `retry_after` interval when certain conditions are met.
+ * `:persistent` plugin: request will be retried immediately, when the error happens after the keep alive interval expired.
+ * `:auth` plugin: request will be retried immediately if it failed due to a "401 Unauthorized Error".
+* `:ssrf_filter` plugin: removed public/private references of exception message.
+
+## Bugfixes
+
+* `:auth` plugin: handle edge case where `:auth_header_expires_at` returns no value.
+* `:digest_auth` plugin: do not retry if there was an issue building building the authorization header after the probe.
+* `webmock` adapter: prevent mocked requests from opening a connection to the peer server that will not be used.
+* clear and cancel request timers on completion or reset, ensuring that they won't be retained way past the point where the request is gone.
+* connection: cancel and discard ping timer before closing (removes timer reference)
+* connection: fix logic where purging-while-resending requests to a coalesced connection was leaving references in the old connection.
+* moved an `on_body_chunk` callback to the `:callbacks` plugin, where it's used and expected to be defined.
+* `http2`: avoid closing the connection on internal errors which are supposed to be specific to a request, such as the max headers or max response body size checks.
+* system resolver will use an internal exception when using `Timeout.timeout` on resolutions to avoid conflicts with the default timeout exception class.
+* prevent edge case where `#alpn_protocol` was being called on a `TCPSocket`.
+* fixed v1.8.0 regression causing connection to loop when an error happens while connecting.
+* resolver cache: fixed cache eviction logic, where alias answers weren't being evicted, causing resolutions to stall after a certain number of resolutions.
* Changed:
doc/release_notes/1_7_1.md
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/doc/release_notes/1_7_1.md 2026-07-24 02:33:47.462766555 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/doc/release_notes/1_7_1.md 2026-07-24 02:33:47.520766935 +0000
@@ -20,2 +20 @@
-* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
-*
\ No newline at end of file
+* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
\ No newline at end of file
lib/httpx/adapters/datadog.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:47.470766607 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:47.521766942 +0000
@@ -187,0 +188,7 @@
+ # patches httpx debug logs to include datadog correlation ids
+ module LoggablePatch
+ def log_identifiers
+ "#{super} #{Datadog::Tracing.log_correlation}"
+ end
+ end
+
@@ -299,0 +307,2 @@
+
+ ::HTTPX::Loggable.singleton_class.prepend(LoggablePatch)
lib/httpx/adapters/faraday.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:47.470766607 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:47.522766948 +0000
@@ -118 +118 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/adapters/webmock.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:47.470766607 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:47.522766948 +0000
@@ -157,0 +158,6 @@
+
+ private
+
+ def connect
+ super unless @mocked
+ end
lib/httpx/connection.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/connection.rb 2026-07-24 02:33:47.471766614 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/connection.rb 2026-07-24 02:33:47.525766968 +0000
@@ -164 +163,0 @@
- pendings = []
@@ -168 +167,4 @@
- pendings << pending
+ pending.reject! do |req|
+ block.call(req)
+ true
+ end
@@ -170,3 +172,3 @@
- pendings << @pending
- pendings.each do |pending|
- pending.reject!(&block)
+ @pending.reject! do |req|
+ block.call(req)
+ true
@@ -206 +208 @@
- rescue StandardError => e
+ rescue Error => e
@@ -217,0 +220,2 @@
+ return if no_more_requests?
+
@@ -225 +229 @@
- return if @pending.empty?
+ return if no_more_requests?
@@ -250 +254,5 @@
- rescue IOError => e
+ rescue Errno::ECONNRESET,
+ Errno::EINVAL,
+ SocketError,
+ IOError,
+ TLSError => e
@@ -253 +261 @@
- rescue StandardError => e
+ rescue Error => e
@@ -260,0 +269,4 @@
+ def initial_call
+ call
+ end
+
@@ -316,0 +329,5 @@
+ if @ping_timer
+ @ping_timer.cancel
+ @ping_timer = nil
+ end
+
@@ -435,0 +453,5 @@
+
+ # do not force close if parser resets the connection.
+ # can happen i.e. when HTTP/1.1 pipelining is disabled.
+ return if @state == :idle && @pending.any?
+
@@ -459 +481 @@
- # :nocov:
+ # simplecov:disable
@@ -467 +489 @@
- # :nocov:
+ # simplecov:enable
@@ -493 +515 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty?
+ if no_more_requests? && @write_buffer.empty?
@@ -543 +565 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty? # rubocop:disable Style/Next
+ if no_more_requests? && @write_buffer.empty? # rubocop:disable Style/Next
@@ -962,0 +985 @@
+ log(level: 3) { "ping timeout expired..." }
@@ -988,0 +1012,5 @@
+ # true when there are no more pending nor inflight (in parser) requests
+ def no_more_requests?
+ @pending.empty? && @inflight.zero?
+ end
+
@@ -1102 +1130,2 @@
- request.active_timeouts << label
+ timer.label = label
+ request.active_timeouts << timer
@@ -1108 +1137 @@
- request.active_timeouts.delete(label)
+ request.active_timeouts.delete(timer)
lib/httpx/connection/http1.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/connection/http1.rb 2026-07-24 02:33:47.471766614 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/connection/http1.rb 2026-07-24 02:33:47.525766968 +0000
@@ -165,12 +165,6 @@
- begin
- request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
- request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
-
- response = request.response
-
- response << chunk
- rescue StandardError => e
- error_response = ErrorResponse.new(request, e)
- request.response = error_response
- dispatch(request)
- end
+ request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
+ request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
+
+ response = request.response
+
+ response << chunk
@@ -419 +413 @@
- UPCASED[field] || field.split("-").map(&:capitalize).join("-")
+ UPCASED.fetch(field) { field.split("-").map(&:capitalize).join("-") }
lib/httpx/connection/http2.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/connection/http2.rb 2026-07-24 02:33:47.471766614 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/connection/http2.rb 2026-07-24 02:33:47.525766968 +0000
@@ -39,0 +40 @@
+ @streams_to_close_after_receive = []
@@ -112,0 +114,6 @@
+
+ while (stream, request, error = @streams_to_close_after_receive.shift)
+ # these streams were marked for cancellation due to errors found while processing the
+ # data received by the peer.
+ emit_stream_error(stream, request, error)
+ end
@@ -131 +138 @@
- rescue StandardError => e
+ rescue ::HTTP2::Error::Error, ArgumentError => e
@@ -335,0 +343,2 @@
+ rescue HTTPX::Error => e
+ @streams_to_close_after_receive << [stream, request, e]
@@ -347,0 +357,3 @@
+
+ return unless request.response
+
@@ -348,0 +361,8 @@
+ rescue HTTPX::Error => e
+ if stream.state == :closing
+ # there won't be any more chunks to process after this one.
+ emit_stream_error(stream, request, e)
+ else
+ # defer until the last chunk from the payload is processed.
+ @streams_to_close_after_receive << [stream, request, e]
+ end
@@ -384,5 +404,6 @@
- response = request.response
- if response && response.is_a?(Response) && response.status == 421
- emit(:error, request, :http_1_1_required)
- else
- emit(:response, request, response)
+ if (response = request.response)
+ if response.is_a?(Response) && response.status == 421
+ emit(:error, request, :http_1_1_required)
+ else
+ emit(:response, request, response)
+ end
@@ -509,0 +531,6 @@
+ end
+
+ def emit_stream_error(stream, request, error)
+ teardown(request)
+ stream.close
+ emit(:error, request, error)
lib/httpx/headers.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/headers.rb 2026-07-24 02:33:47.472766620 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/headers.rb 2026-07-24 02:33:47.526766975 +0000
@@ -143 +143 @@
- # :nocov:
+ # simplecov:disable
@@ -148 +148 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/ssl.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/io/ssl.rb 2026-07-24 02:33:47.472766620 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/io/ssl.rb 2026-07-24 02:33:47.526766975 +0000
@@ -23,2 +23,3 @@
- ctx_options = TLS_OPTIONS.merge(options.ssl)
- @sni_hostname = ctx_options.delete(:hostname) || @hostname
+ ctx_options = TLS_OPTIONS
+ ctx_options = ctx_options.merge(options.ssl) if options.ssl && !options.ssl.empty?
+ @sni_hostname = (ctx_options.delete(:hostname) if ctx_options.key?(:hostname)) || @hostname
@@ -32 +33 @@
- @ctx.set_params(ctx_options) unless ctx_options.empty?
+ @ctx.set_params(ctx_options)
@@ -54 +55,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -56,2 +57,0 @@
- rescue StandardError
- super
@@ -64 +64,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -70,2 +70,0 @@
- rescue StandardError
- super
lib/httpx/io/tcp.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/io/tcp.rb 2026-07-24 02:33:47.472766620 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/io/tcp.rb 2026-07-24 02:33:47.526766975 +0000
@@ -185 +185,8 @@
- return if @keep_open || closed?
+ return if @keep_open
+
+ # mark tcp as closed, so that it can be disconnected.
+ # this bypasses the state machine API as not not allow the transition
+ # from idle to closed in normal circumstances.
+ @state = :closed if @state == :idle
+
+ return if closed?
@@ -189 +196 @@
- rescue StandardError => e
+ rescue IOError => e
@@ -215 +222 @@
- # :nocov:
+ # simplecov:disable
@@ -224 +231 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/unix.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/io/unix.rb 2026-07-24 02:33:47.472766620 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/io/unix.rb 2026-07-24 02:33:47.526766975 +0000
@@ -63 +63 @@
- # :nocov:
+ # simplecov:disable
@@ -67 +67 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/loggable.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/loggable.rb 2026-07-24 02:33:47.473766627 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/loggable.rb 2026-07-24 02:33:47.526766975 +0000
@@ -19,0 +20,6 @@
+ def self.log_identifiers
+ "pid=#{Process.pid} " \
+ "tid=#{Thread.current.object_id} " \
+ "fid=#{Fiber.current.object_id}"
+ end
+
@@ -39,4 +45,3 @@
- message = +"(time:#{Time.now.utc}, pid:#{Process.pid}, " \
- "tid:#{Thread.current.object_id}, " \
- "fid:#{Fiber.current.object_id}, " \
- "self:#{class_name}##{object_id}) "
+ message = +"(time=#{Time.now.utc} " \
+ "#{Loggable.log_identifiers} " \
+ "self=#{class_name}##{object_id}) "
@@ -50,0 +56,2 @@
+
+ private
lib/httpx/plugins/auth.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/auth.rb 2026-07-24 02:33:47.473766627 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/auth.rb 2026-07-24 02:33:47.527766981 +0000
@@ -130,2 +130,2 @@
- if expires_at.respond_to?(:call)
- expires_at = expires_at.call(request).to_f
+ if expires_at.respond_to?(:call) && (expires_at = expires_at.call(request))
+ expires_at = expires_at.to_f
@@ -204,0 +205,9 @@
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(Response)
+
+ # retry immediately if authentication no longer valid.
+ return if response.status == 401
+
+ super
lib/httpx/plugins/auth/digest.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:47.474766634 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:47.527766981 +0000
@@ -27 +27 @@
- rescue StandardError => e
+ rescue HTTPX::Error => e
lib/httpx/plugins/callbacks.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:47.475766640 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:47.529766994 +0000
@@ -124,0 +125,12 @@
+ module RequestMethods
+ def drain_body
+ super.tap do |chunk|
+ emit(:body_chunk, chunk) if chunk
+ rescue StandardError => e
+ # in case an error occurs in callback code
+ @drain_error = e
+ nil
+ end
+ end
+ end
+
lib/httpx/plugins/digest_auth.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:47.477766653 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:47.530767001 +0000
@@ -53,0 +54 @@
+
@@ -56,0 +58,3 @@
+
+ next(request.response) if request.response
+
lib/httpx/plugins/fiber_concurrency.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:47.477766653 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:47.531767008 +0000
@@ -72,0 +73,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -195,0 +202,6 @@
+ def initial_call
+ return unless @queries.values.any?(&:current_context?) || @connections.any?(&:current_context?)
+
+ super
+ end
+
@@ -220,0 +233,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -222 +240 @@
- return unless @queries.any? { |_, conn| conn.current_context? }
+ return unless current_context?
@@ -224,0 +243,6 @@
+ end
+
+ private
+
+ def current_context?
+ @queries.any? { |_, conn| conn.current_context? }
lib/httpx/plugins/persistent.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:47.478766660 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:47.532767014 +0000
@@ -57,0 +58,16 @@
+ def reconnectable_error?(error)
+ Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(ErrorResponse)
+
+ error = response.error
+ # allow request to be retried immediately if the request failed right after the keep alive timeout.
+ # the chances are, the request failed because the connect has been dropped by the peer server, so it's
+ # fine to reopen.
+ return if request.ping? && reconnectable_error?(error)
+
+ super
+ end
+
@@ -60 +76 @@
- return false unless response && response.is_a?(ErrorResponse)
+ return false unless response.is_a?(ErrorResponse)
@@ -64 +80 @@
- Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ reconnectable_error?(error)
lib/httpx/plugins/push_promise.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:47.480766673 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:47.533767021 +0000
@@ -47 +47 @@
- # :nocov:
+ # simplecov:disable
@@ -49 +49 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/ssrf_filter.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:47.481766679 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:47.534767027 +0000
@@ -152 +152 @@
- raise ServerSideRequestForgeryError, "#{@origin.host} has no public IP addresses" if addrs.empty?
+ raise ServerSideRequestForgeryError, "#{@origin.host} has no allowed IP addresses" if addrs.empty?
lib/httpx/plugins/stream.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/stream.rb 2026-07-24 02:33:47.481766679 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/stream.rb 2026-07-24 02:33:47.534767027 +0000
@@ -78 +78 @@
- # :nocov:
+ # simplecov:disable
@@ -82 +82 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/stream_bidi.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:47.481766679 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:47.534767027 +0000
@@ -179,0 +180,2 @@
+ def initial_call; end
+
lib/httpx/pool.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/pool.rb 2026-07-24 02:33:47.482766686 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/pool.rb 2026-07-24 02:33:47.535767034 +0000
@@ -176 +176 @@
- # :nocov:
+ # simplecov:disable
@@ -184 +184 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/request.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/request.rb 2026-07-24 02:33:47.482766686 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/request.rb 2026-07-24 02:33:47.536767040 +0000
@@ -124,0 +125 @@
+ reset_timers(true)
@@ -271 +272 @@
- return nil if @body.nil?
+ return if @body.nil?
@@ -274,4 +275 @@
- chunk = @drainer.next.dup
-
- emit(:body_chunk, chunk)
- chunk
+ @drainer.next.dup
@@ -280,0 +279 @@
+ # in case an error occurs while emitting body chunks
@@ -285 +284 @@
- # :nocov:
+ # simplecov:disable
@@ -293 +292 @@
- # :nocov:
+ # simplecov:enable
@@ -302 +301,4 @@
- @active_timeouts.clear
+
+ # request may be sent to a different connection and will be
+ # reassigned a new set of timers.
+ reset_timers(false)
@@ -329 +331 @@
- log(level: 3) { "#{@state}] -> #{nextstate}" }
+ log(level: 3) { "#{@state} -> #{nextstate}" }
@@ -364,0 +367,13 @@
+ end
+
+ private
+
+ def reset_timers(reset_total_request_timers)
+ timers = @active_timeouts
+
+ until (timer = timers.shift).nil?
+ next if !reset_total_request_timers && timer.label == :total_request_timeout
+
+ # cancel active timers.
+ timer.cancel
+ end
lib/httpx/request/body.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/request/body.rb 2026-07-24 02:33:47.482766686 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/request/body.rb 2026-07-24 02:33:47.536767040 +0000
@@ -117 +117 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/resolver/cache/base.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:47.483766692 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:47.536767040 +0000
@@ -109,8 +109 @@
- lookups[name] ||= []
-
- case family
- when Socket::AF_INET6
- lookups[name] << entry
- when Socket::AF_INET
- lookups[name].unshift(entry)
- end
+ _set(name, family, [entry], lookups, hostnames)
lib/httpx/resolver/https.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/resolver/https.rb 2026-07-24 02:33:47.484766699 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/resolver/https.rb 2026-07-24 02:33:47.537767047 +0000
@@ -129,13 +129,12 @@
- response.raise_for_status
- rescue StandardError => e
- hostname = @requests.delete(request)
- connection = reset_hostname(hostname)
- emit_resolve_error(connection, connection.peer.host, e)
- close_or_resolve
- else
- # @type var response: HTTPX::Response
- if response.status.between?(300, 399) && response.headers.key?("location")
- hostname = @requests[request]
- connection = @queries[hostname]
- location_uri = URI(response.headers["location"])
- location_uri = response.uri.merge(location_uri) if location_uri.relative?
+ if (e = response.error)
+ hostname = @requests.delete(request)
+ connection = reset_hostname(hostname)
+ emit_resolve_error(connection, connection.peer.host, e)
+ close_or_resolve
+ else
+ # @type var response: HTTPX::Response
+ if response.status.between?(300, 399) && response.headers.key?("location")
+ hostname = @requests[request]
+ connection = @queries[hostname]
+ location_uri = URI(response.headers["location"])
+ location_uri = response.uri.merge(location_uri) if location_uri.relative?
@@ -143,5 +142,5 @@
- # we assume that the DNS server URI changed permanently and move on
- @uri = location_uri
- send_request(hostname, connection)
- return
- end
+ # we assume that the DNS server URI changed permanently and move on
+ @uri = location_uri
+ send_request(hostname, connection)
+ return
+ end
@@ -149 +148,2 @@
- parse(request, response)
+ parse(request, response)
+ end
lib/httpx/resolver/native.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/resolver/native.rb 2026-07-24 02:33:47.484766699 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/resolver/native.rb 2026-07-24 02:33:47.537767047 +0000
@@ -77,0 +78,7 @@
+ when :idle, :closed
+ return if @connections.empty?
+
+ transition(:idle) if @state == :closed
+ transition(:open)
+
+ consume if @state == :open
lib/httpx/resolver/resolver.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:47.484766699 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:47.537767047 +0000
@@ -54,0 +55,4 @@
+ def initial_call
+ call
+ end
+
lib/httpx/resolver/system.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/resolver/system.rb 2026-07-24 02:33:47.484766699 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/resolver/system.rb 2026-07-24 02:33:47.537767047 +0000
@@ -25,0 +26,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
@@ -230 +233 @@
- Timeout.timeout(resolve_timeout) do
+ Timeout.timeout(resolve_timeout, AddrinfoTimeoutError) do
@@ -249 +252 @@
- if e.is_a?(Timeout::Error)
+ if e.is_a?(AddrinfoTimeoutError)
lib/httpx/response.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/response.rb 2026-07-24 02:33:47.484766699 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/response.rb 2026-07-24 02:33:47.538767053 +0000
@@ -144 +144 @@
- # :nocov:
+ # simplecov:disable
@@ -152 +152 @@
- # :nocov:
+ # simplecov:enable
@@ -270 +269,0 @@
- include Loggable
@@ -293 +292 @@
- log_exception(@error)
+ @request.log_exception(@error)
lib/httpx/response/body.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/response/body.rb 2026-07-24 02:33:47.485766706 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/response/body.rb 2026-07-24 02:33:47.538767053 +0000
@@ -164 +164 @@
- # :nocov:
+ # simplecov:disable
@@ -170 +170 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/selector.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/selector.rb 2026-07-24 02:33:47.485766706 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/selector.rb 2026-07-24 02:33:47.538767053 +0000
@@ -43,0 +44,5 @@
+ # first time the registered selectables are added, there's probably work to do.
+ def initial_call
+ @selectables.each(&:initial_call)
+ end
+
lib/httpx/session.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/session.rb 2026-07-24 02:33:47.485766706 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/session.rb 2026-07-24 02:33:47.538767053 +0000
@@ -322 +322 @@
- responses = requests.each_with_index.map do |request, idx|
+ requests.each do |request|
@@ -323,0 +324,4 @@
+ end
+
+ # do work first
+ selector.initial_call
@@ -324,0 +329 @@
+ responses = requests.each_with_index.map do |request, idx|
lib/httpx/session_extensions.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/session_extensions.rb 2026-07-24 02:33:47.485766706 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/session_extensions.rb 2026-07-24 02:33:47.538767053 +0000
@@ -23 +23 @@
- # :nocov:
+ # simplecov:disable
@@ -29 +29 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/timers.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/timers.rb 2026-07-24 02:33:47.486766712 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/timers.rb 2026-07-24 02:33:47.539767060 +0000
@@ -64,0 +65,3 @@
+ # simpler helper which allows classification
+ attr_accessor :label
+
lib/httpx/version.rb
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/lib/httpx/version.rb 2026-07-24 02:33:47.488766725 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/lib/httpx/version.rb 2026-07-24 02:33:47.542767080 +0000
@@ -4 +4 @@
- VERSION = "1.8.0"
+ VERSION = "1.8.1"
sig/connection.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/connection.rbs 2026-07-24 02:33:47.488766725 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/connection.rbs 2026-07-24 02:33:47.542767080 +0000
@@ -94,0 +95,2 @@
+ def initial_call: () -> void
+
@@ -125 +127 @@
- def on_io_error: (IOError error) -> void
+ def on_io_error: (SocketError | IOError | TLSError error) -> void
@@ -165,0 +168,2 @@
+
+ def no_more_requests?: () -> bool
sig/connection/http2.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/connection/http2.rbs 2026-07-24 02:33:47.489766732 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/connection/http2.rbs 2026-07-24 02:33:47.543767086 +0000
@@ -18,0 +19 @@
+ @streams_to_close_after_receive: Array[[HTTP2::Stream, Request, HTTPX::Error]]
@@ -107,0 +109,2 @@
+
+ def emit_stream_error: (HTTP2::Stream stream, Request request, StandardError error) -> void
sig/loggable.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/loggable.rbs 2026-07-24 02:33:47.490766739 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/loggable.rbs 2026-07-24 02:33:47.545767099 +0000
@@ -14,0 +15,2 @@
+ def self.log_identifiers: () -> String
+
@@ -17,0 +20,2 @@
+
+ private
sig/plugins/auth.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/plugins/auth.rbs 2026-07-24 02:33:47.491766745 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/plugins/auth.rbs 2026-07-24 02:33:47.546767106 +0000
@@ -9,0 +10,4 @@
+
+ def auth_header_expires_at: () -> (^(Request request) -> _ToF?)?
+
+ def auth_header_expires_in: () -> Float?
sig/plugins/persistent.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/plugins/persistent.rbs 2026-07-24 02:33:47.495766771 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/plugins/persistent.rbs 2026-07-24 02:33:47.551767139 +0000
@@ -8,0 +9,3 @@
+ private
+
+ def reconnectable_error?: (StandardError error) -> bool
sig/request.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/request.rbs 2026-07-24 02:33:47.498766791 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/request.rbs 2026-07-24 02:33:47.553767152 +0000
@@ -20 +20 @@
- attr_reader active_timeouts: Array[Symbol]
+ attr_reader active_timeouts: Array[Timers::Timer]
@@ -96,2 +96 @@
- def initialize_body: (Options options) -> Transcoder::_Encoder?
-
+ def reset_timers: (bool reset_total_request_timers) -> void
sig/resolver/system.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/resolver/system.rbs 2026-07-24 02:33:47.499766797 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/resolver/system.rbs 2026-07-24 02:33:47.555767165 +0000
@@ -7,0 +8,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
sig/selector.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/selector.rbs 2026-07-24 02:33:47.500766804 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/selector.rbs 2026-07-24 02:33:47.555767165 +0000
@@ -8,0 +9,2 @@
+ def initial_call: () -> void
+
sig/timers.rbs
--- /tmp/d20260724-2693-nxgjyi/httpx-1.8.0/sig/timers.rbs 2026-07-24 02:33:47.500766804 +0000
+++ /tmp/d20260724-2693-nxgjyi/httpx-1.8.1/sig/timers.rbs 2026-07-24 02:33:47.556767172 +0000
@@ -50,0 +51,2 @@
+ attr_accessor label: Symbol?
+ |
Contributor
gem compare --diff httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md
--- /tmp/20260724-2694-76eky5 2026-07-24 02:33:48.365293060 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/doc/release_notes/1_8_1.md 2026-07-24 02:33:48.320293187 +0000
@@ -0,0 +1,27 @@
+# 1.8.1
+
+## Improvements
+
+* the session will now eagerly write initial data to connections instead of waiting for I/O the first time (saves a syscall).
+* removed all rescue blocks rescuing `StandardError` internally; this could interfere with usages of `httpx` inside `Timeout.timeout` blocks, which may emit an exception at any point, including in blocks where that exception could be rescued, leaving the session in a potentially irrecoverable state and looping.
+* debug logs change the display of ids from 'tid:123, fid:123' to 'tid=123 fid:123'.
+ * and when using the `datadog` adapter, all related correlation ids (trace id, span id, etc) will also be added to the identifiers in the same format
+* plugins built on top of the `:retries` plugin will skip the `retry_after` interval when certain conditions are met.
+ * `:persistent` plugin: request will be retried immediately, when the error happens after the keep alive interval expired.
+ * `:auth` plugin: request will be retried immediately if it failed due to a "401 Unauthorized Error".
+* `:ssrf_filter` plugin: removed public/private references of exception message.
+
+## Bugfixes
+
+* `:auth` plugin: handle edge case where `:auth_header_expires_at` returns no value.
+* `:digest_auth` plugin: do not retry if there was an issue building building the authorization header after the probe.
+* `webmock` adapter: prevent mocked requests from opening a connection to the peer server that will not be used.
+* clear and cancel request timers on completion or reset, ensuring that they won't be retained way past the point where the request is gone.
+* connection: cancel and discard ping timer before closing (removes timer reference)
+* connection: fix logic where purging-while-resending requests to a coalesced connection was leaving references in the old connection.
+* moved an `on_body_chunk` callback to the `:callbacks` plugin, where it's used and expected to be defined.
+* `http2`: avoid closing the connection on internal errors which are supposed to be specific to a request, such as the max headers or max response body size checks.
+* system resolver will use an internal exception when using `Timeout.timeout` on resolutions to avoid conflicts with the default timeout exception class.
+* prevent edge case where `#alpn_protocol` was being called on a `TCPSocket`.
+* fixed v1.8.0 regression causing connection to loop when an error happens while connecting.
+* resolver cache: fixed cache eviction logic, where alias answers weren't being evicted, causing resolutions to stall after a certain number of resolutions.
* Changed:
doc/release_notes/1_7_1.md
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/doc/release_notes/1_7_1.md 2026-07-24 02:33:48.252293379 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/doc/release_notes/1_7_1.md 2026-07-24 02:33:48.319293190 +0000
@@ -20,2 +20 @@
-* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
-*
\ No newline at end of file
+* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
\ No newline at end of file
lib/httpx/adapters/datadog.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:48.254293374 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:48.321293184 +0000
@@ -187,0 +188,7 @@
+ # patches httpx debug logs to include datadog correlation ids
+ module LoggablePatch
+ def log_identifiers
+ "#{super} #{Datadog::Tracing.log_correlation}"
+ end
+ end
+
@@ -299,0 +307,2 @@
+
+ ::HTTPX::Loggable.singleton_class.prepend(LoggablePatch)
lib/httpx/adapters/faraday.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:48.254293374 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:48.321293184 +0000
@@ -118 +118 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/adapters/webmock.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:48.255293371 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:48.321293184 +0000
@@ -157,0 +158,6 @@
+
+ private
+
+ def connect
+ super unless @mocked
+ end
lib/httpx/connection.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/connection.rb 2026-07-24 02:33:48.255293371 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/connection.rb 2026-07-24 02:33:48.323293179 +0000
@@ -164 +163,0 @@
- pendings = []
@@ -168 +167,4 @@
- pendings << pending
+ pending.reject! do |req|
+ block.call(req)
+ true
+ end
@@ -170,3 +172,3 @@
- pendings << @pending
- pendings.each do |pending|
- pending.reject!(&block)
+ @pending.reject! do |req|
+ block.call(req)
+ true
@@ -206 +208 @@
- rescue StandardError => e
+ rescue Error => e
@@ -217,0 +220,2 @@
+ return if no_more_requests?
+
@@ -225 +229 @@
- return if @pending.empty?
+ return if no_more_requests?
@@ -250 +254,5 @@
- rescue IOError => e
+ rescue Errno::ECONNRESET,
+ Errno::EINVAL,
+ SocketError,
+ IOError,
+ TLSError => e
@@ -253 +261 @@
- rescue StandardError => e
+ rescue Error => e
@@ -260,0 +269,4 @@
+ def initial_call
+ call
+ end
+
@@ -316,0 +329,5 @@
+ if @ping_timer
+ @ping_timer.cancel
+ @ping_timer = nil
+ end
+
@@ -435,0 +453,5 @@
+
+ # do not force close if parser resets the connection.
+ # can happen i.e. when HTTP/1.1 pipelining is disabled.
+ return if @state == :idle && @pending.any?
+
@@ -459 +481 @@
- # :nocov:
+ # simplecov:disable
@@ -467 +489 @@
- # :nocov:
+ # simplecov:enable
@@ -493 +515 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty?
+ if no_more_requests? && @write_buffer.empty?
@@ -543 +565 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty? # rubocop:disable Style/Next
+ if no_more_requests? && @write_buffer.empty? # rubocop:disable Style/Next
@@ -962,0 +985 @@
+ log(level: 3) { "ping timeout expired..." }
@@ -988,0 +1012,5 @@
+ # true when there are no more pending nor inflight (in parser) requests
+ def no_more_requests?
+ @pending.empty? && @inflight.zero?
+ end
+
@@ -1102 +1130,2 @@
- request.active_timeouts << label
+ timer.label = label
+ request.active_timeouts << timer
@@ -1108 +1137 @@
- request.active_timeouts.delete(label)
+ request.active_timeouts.delete(timer)
lib/httpx/connection/http1.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/connection/http1.rb 2026-07-24 02:33:48.256293368 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/connection/http1.rb 2026-07-24 02:33:48.323293179 +0000
@@ -165,12 +165,6 @@
- begin
- request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
- request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
-
- response = request.response
-
- response << chunk
- rescue StandardError => e
- error_response = ErrorResponse.new(request, e)
- request.response = error_response
- dispatch(request)
- end
+ request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
+ request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
+
+ response = request.response
+
+ response << chunk
@@ -419 +413 @@
- UPCASED[field] || field.split("-").map(&:capitalize).join("-")
+ UPCASED.fetch(field) { field.split("-").map(&:capitalize).join("-") }
lib/httpx/connection/http2.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/connection/http2.rb 2026-07-24 02:33:48.256293368 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/connection/http2.rb 2026-07-24 02:33:48.323293179 +0000
@@ -39,0 +40 @@
+ @streams_to_close_after_receive = []
@@ -112,0 +114,6 @@
+
+ while (stream, request, error = @streams_to_close_after_receive.shift)
+ # these streams were marked for cancellation due to errors found while processing the
+ # data received by the peer.
+ emit_stream_error(stream, request, error)
+ end
@@ -131 +138 @@
- rescue StandardError => e
+ rescue ::HTTP2::Error::Error, ArgumentError => e
@@ -335,0 +343,2 @@
+ rescue HTTPX::Error => e
+ @streams_to_close_after_receive << [stream, request, e]
@@ -347,0 +357,3 @@
+
+ return unless request.response
+
@@ -348,0 +361,8 @@
+ rescue HTTPX::Error => e
+ if stream.state == :closing
+ # there won't be any more chunks to process after this one.
+ emit_stream_error(stream, request, e)
+ else
+ # defer until the last chunk from the payload is processed.
+ @streams_to_close_after_receive << [stream, request, e]
+ end
@@ -384,5 +404,6 @@
- response = request.response
- if response && response.is_a?(Response) && response.status == 421
- emit(:error, request, :http_1_1_required)
- else
- emit(:response, request, response)
+ if (response = request.response)
+ if response.is_a?(Response) && response.status == 421
+ emit(:error, request, :http_1_1_required)
+ else
+ emit(:response, request, response)
+ end
@@ -509,0 +531,6 @@
+ end
+
+ def emit_stream_error(stream, request, error)
+ teardown(request)
+ stream.close
+ emit(:error, request, error)
lib/httpx/headers.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/headers.rb 2026-07-24 02:33:48.256293368 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/headers.rb 2026-07-24 02:33:48.324293176 +0000
@@ -143 +143 @@
- # :nocov:
+ # simplecov:disable
@@ -148 +148 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/ssl.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/io/ssl.rb 2026-07-24 02:33:48.257293365 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/io/ssl.rb 2026-07-24 02:33:48.324293176 +0000
@@ -23,2 +23,3 @@
- ctx_options = TLS_OPTIONS.merge(options.ssl)
- @sni_hostname = ctx_options.delete(:hostname) || @hostname
+ ctx_options = TLS_OPTIONS
+ ctx_options = ctx_options.merge(options.ssl) if options.ssl && !options.ssl.empty?
+ @sni_hostname = (ctx_options.delete(:hostname) if ctx_options.key?(:hostname)) || @hostname
@@ -32 +33 @@
- @ctx.set_params(ctx_options) unless ctx_options.empty?
+ @ctx.set_params(ctx_options)
@@ -54 +55,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -56,2 +57,0 @@
- rescue StandardError
- super
@@ -64 +64,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -70,2 +70,0 @@
- rescue StandardError
- super
lib/httpx/io/tcp.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/io/tcp.rb 2026-07-24 02:33:48.257293365 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/io/tcp.rb 2026-07-24 02:33:48.333293150 +0000
@@ -185 +185,8 @@
- return if @keep_open || closed?
+ return if @keep_open
+
+ # mark tcp as closed, so that it can be disconnected.
+ # this bypasses the state machine API as not not allow the transition
+ # from idle to closed in normal circumstances.
+ @state = :closed if @state == :idle
+
+ return if closed?
@@ -189 +196 @@
- rescue StandardError => e
+ rescue IOError => e
@@ -215 +222 @@
- # :nocov:
+ # simplecov:disable
@@ -224 +231 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/unix.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/io/unix.rb 2026-07-24 02:33:48.257293365 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/io/unix.rb 2026-07-24 02:33:48.333293150 +0000
@@ -63 +63 @@
- # :nocov:
+ # simplecov:disable
@@ -67 +67 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/loggable.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/loggable.rb 2026-07-24 02:33:48.257293365 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/loggable.rb 2026-07-24 02:33:48.333293150 +0000
@@ -19,0 +20,6 @@
+ def self.log_identifiers
+ "pid=#{Process.pid} " \
+ "tid=#{Thread.current.object_id} " \
+ "fid=#{Fiber.current.object_id}"
+ end
+
@@ -39,4 +45,3 @@
- message = +"(time:#{Time.now.utc}, pid:#{Process.pid}, " \
- "tid:#{Thread.current.object_id}, " \
- "fid:#{Fiber.current.object_id}, " \
- "self:#{class_name}##{object_id}) "
+ message = +"(time=#{Time.now.utc} " \
+ "#{Loggable.log_identifiers} " \
+ "self=#{class_name}##{object_id}) "
@@ -50,0 +56,2 @@
+
+ private
lib/httpx/plugins/auth.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/auth.rb 2026-07-24 02:33:48.258293362 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/auth.rb 2026-07-24 02:33:48.334293147 +0000
@@ -130,2 +130,2 @@
- if expires_at.respond_to?(:call)
- expires_at = expires_at.call(request).to_f
+ if expires_at.respond_to?(:call) && (expires_at = expires_at.call(request))
+ expires_at = expires_at.to_f
@@ -204,0 +205,9 @@
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(Response)
+
+ # retry immediately if authentication no longer valid.
+ return if response.status == 401
+
+ super
lib/httpx/plugins/auth/digest.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:48.259293359 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:48.334293147 +0000
@@ -27 +27 @@
- rescue StandardError => e
+ rescue HTTPX::Error => e
lib/httpx/plugins/callbacks.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:48.260293357 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:48.336293142 +0000
@@ -124,0 +125,12 @@
+ module RequestMethods
+ def drain_body
+ super.tap do |chunk|
+ emit(:body_chunk, chunk) if chunk
+ rescue StandardError => e
+ # in case an error occurs in callback code
+ @drain_error = e
+ nil
+ end
+ end
+ end
+
lib/httpx/plugins/digest_auth.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:48.262293351 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:48.337293139 +0000
@@ -53,0 +54 @@
+
@@ -56,0 +58,3 @@
+
+ next(request.response) if request.response
+
lib/httpx/plugins/fiber_concurrency.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:48.262293351 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:48.337293139 +0000
@@ -72,0 +73,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -195,0 +202,6 @@
+ def initial_call
+ return unless @queries.values.any?(&:current_context?) || @connections.any?(&:current_context?)
+
+ super
+ end
+
@@ -220,0 +233,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -222 +240 @@
- return unless @queries.any? { |_, conn| conn.current_context? }
+ return unless current_context?
@@ -224,0 +243,6 @@
+ end
+
+ private
+
+ def current_context?
+ @queries.any? { |_, conn| conn.current_context? }
lib/httpx/plugins/persistent.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:48.265293343 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:48.339293133 +0000
@@ -57,0 +58,16 @@
+ def reconnectable_error?(error)
+ Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(ErrorResponse)
+
+ error = response.error
+ # allow request to be retried immediately if the request failed right after the keep alive timeout.
+ # the chances are, the request failed because the connect has been dropped by the peer server, so it's
+ # fine to reopen.
+ return if request.ping? && reconnectable_error?(error)
+
+ super
+ end
+
@@ -60 +76 @@
- return false unless response && response.is_a?(ErrorResponse)
+ return false unless response.is_a?(ErrorResponse)
@@ -64 +80 @@
- Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ reconnectable_error?(error)
lib/httpx/plugins/push_promise.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:48.266293340 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:48.340293131 +0000
@@ -47 +47 @@
- # :nocov:
+ # simplecov:disable
@@ -49 +49 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/ssrf_filter.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:48.267293337 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:48.341293128 +0000
@@ -152 +152 @@
- raise ServerSideRequestForgeryError, "#{@origin.host} has no public IP addresses" if addrs.empty?
+ raise ServerSideRequestForgeryError, "#{@origin.host} has no allowed IP addresses" if addrs.empty?
lib/httpx/plugins/stream.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/stream.rb 2026-07-24 02:33:48.267293337 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/stream.rb 2026-07-24 02:33:48.341293128 +0000
@@ -78 +78 @@
- # :nocov:
+ # simplecov:disable
@@ -82 +82 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/stream_bidi.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:48.267293337 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:48.341293128 +0000
@@ -179,0 +180,2 @@
+ def initial_call; end
+
lib/httpx/pool.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/pool.rb 2026-07-24 02:33:48.268293334 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/pool.rb 2026-07-24 02:33:48.342293125 +0000
@@ -176 +176 @@
- # :nocov:
+ # simplecov:disable
@@ -184 +184 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/request.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/request.rb 2026-07-24 02:33:48.268293334 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/request.rb 2026-07-24 02:33:48.343293122 +0000
@@ -124,0 +125 @@
+ reset_timers(true)
@@ -271 +272 @@
- return nil if @body.nil?
+ return if @body.nil?
@@ -274,4 +275 @@
- chunk = @drainer.next.dup
-
- emit(:body_chunk, chunk)
- chunk
+ @drainer.next.dup
@@ -280,0 +279 @@
+ # in case an error occurs while emitting body chunks
@@ -285 +284 @@
- # :nocov:
+ # simplecov:disable
@@ -293 +292 @@
- # :nocov:
+ # simplecov:enable
@@ -302 +301,4 @@
- @active_timeouts.clear
+
+ # request may be sent to a different connection and will be
+ # reassigned a new set of timers.
+ reset_timers(false)
@@ -329 +331 @@
- log(level: 3) { "#{@state}] -> #{nextstate}" }
+ log(level: 3) { "#{@state} -> #{nextstate}" }
@@ -364,0 +367,13 @@
+ end
+
+ private
+
+ def reset_timers(reset_total_request_timers)
+ timers = @active_timeouts
+
+ until (timer = timers.shift).nil?
+ next if !reset_total_request_timers && timer.label == :total_request_timeout
+
+ # cancel active timers.
+ timer.cancel
+ end
lib/httpx/request/body.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/request/body.rb 2026-07-24 02:33:48.268293334 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/request/body.rb 2026-07-24 02:33:48.343293122 +0000
@@ -117 +117 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/resolver/cache/base.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:48.278293306 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:48.344293119 +0000
@@ -109,8 +109 @@
- lookups[name] ||= []
-
- case family
- when Socket::AF_INET6
- lookups[name] << entry
- when Socket::AF_INET
- lookups[name].unshift(entry)
- end
+ _set(name, family, [entry], lookups, hostnames)
lib/httpx/resolver/https.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/resolver/https.rb 2026-07-24 02:33:48.278293306 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/resolver/https.rb 2026-07-24 02:33:48.344293119 +0000
@@ -129,13 +129,12 @@
- response.raise_for_status
- rescue StandardError => e
- hostname = @requests.delete(request)
- connection = reset_hostname(hostname)
- emit_resolve_error(connection, connection.peer.host, e)
- close_or_resolve
- else
- # @type var response: HTTPX::Response
- if response.status.between?(300, 399) && response.headers.key?("location")
- hostname = @requests[request]
- connection = @queries[hostname]
- location_uri = URI(response.headers["location"])
- location_uri = response.uri.merge(location_uri) if location_uri.relative?
+ if (e = response.error)
+ hostname = @requests.delete(request)
+ connection = reset_hostname(hostname)
+ emit_resolve_error(connection, connection.peer.host, e)
+ close_or_resolve
+ else
+ # @type var response: HTTPX::Response
+ if response.status.between?(300, 399) && response.headers.key?("location")
+ hostname = @requests[request]
+ connection = @queries[hostname]
+ location_uri = URI(response.headers["location"])
+ location_uri = response.uri.merge(location_uri) if location_uri.relative?
@@ -143,5 +142,5 @@
- # we assume that the DNS server URI changed permanently and move on
- @uri = location_uri
- send_request(hostname, connection)
- return
- end
+ # we assume that the DNS server URI changed permanently and move on
+ @uri = location_uri
+ send_request(hostname, connection)
+ return
+ end
@@ -149 +148,2 @@
- parse(request, response)
+ parse(request, response)
+ end
lib/httpx/resolver/native.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/resolver/native.rb 2026-07-24 02:33:48.279293303 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/resolver/native.rb 2026-07-24 02:33:48.344293119 +0000
@@ -77,0 +78,7 @@
+ when :idle, :closed
+ return if @connections.empty?
+
+ transition(:idle) if @state == :closed
+ transition(:open)
+
+ consume if @state == :open
lib/httpx/resolver/resolver.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:48.281293297 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:48.344293119 +0000
@@ -54,0 +55,4 @@
+ def initial_call
+ call
+ end
+
lib/httpx/resolver/system.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/resolver/system.rb 2026-07-24 02:33:48.281293297 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/resolver/system.rb 2026-07-24 02:33:48.345293116 +0000
@@ -25,0 +26,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
@@ -230 +233 @@
- Timeout.timeout(resolve_timeout) do
+ Timeout.timeout(resolve_timeout, AddrinfoTimeoutError) do
@@ -249 +252 @@
- if e.is_a?(Timeout::Error)
+ if e.is_a?(AddrinfoTimeoutError)
lib/httpx/response.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/response.rb 2026-07-24 02:33:48.281293297 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/response.rb 2026-07-24 02:33:48.345293116 +0000
@@ -144 +144 @@
- # :nocov:
+ # simplecov:disable
@@ -152 +152 @@
- # :nocov:
+ # simplecov:enable
@@ -270 +269,0 @@
- include Loggable
@@ -293 +292 @@
- log_exception(@error)
+ @request.log_exception(@error)
lib/httpx/response/body.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/response/body.rb 2026-07-24 02:33:48.281293297 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/response/body.rb 2026-07-24 02:33:48.345293116 +0000
@@ -164 +164 @@
- # :nocov:
+ # simplecov:disable
@@ -170 +170 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/selector.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/selector.rb 2026-07-24 02:33:48.282293295 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/selector.rb 2026-07-24 02:33:48.345293116 +0000
@@ -43,0 +44,5 @@
+ # first time the registered selectables are added, there's probably work to do.
+ def initial_call
+ @selectables.each(&:initial_call)
+ end
+
lib/httpx/session.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/session.rb 2026-07-24 02:33:48.282293295 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/session.rb 2026-07-24 02:33:48.345293116 +0000
@@ -322 +322 @@
- responses = requests.each_with_index.map do |request, idx|
+ requests.each do |request|
@@ -323,0 +324,4 @@
+ end
+
+ # do work first
+ selector.initial_call
@@ -324,0 +329 @@
+ responses = requests.each_with_index.map do |request, idx|
lib/httpx/session_extensions.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/session_extensions.rb 2026-07-24 02:33:48.282293295 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/session_extensions.rb 2026-07-24 02:33:48.346293114 +0000
@@ -23 +23 @@
- # :nocov:
+ # simplecov:disable
@@ -29 +29 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/timers.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/timers.rb 2026-07-24 02:33:48.282293295 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/timers.rb 2026-07-24 02:33:48.346293114 +0000
@@ -64,0 +65,3 @@
+ # simpler helper which allows classification
+ attr_accessor :label
+
lib/httpx/version.rb
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/lib/httpx/version.rb 2026-07-24 02:33:48.285293286 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/lib/httpx/version.rb 2026-07-24 02:33:48.348293108 +0000
@@ -4 +4 @@
- VERSION = "1.8.0"
+ VERSION = "1.8.1"
sig/connection.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/connection.rbs 2026-07-24 02:33:48.287293281 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/connection.rbs 2026-07-24 02:33:48.349293105 +0000
@@ -94,0 +95,2 @@
+ def initial_call: () -> void
+
@@ -125 +127 @@
- def on_io_error: (IOError error) -> void
+ def on_io_error: (SocketError | IOError | TLSError error) -> void
@@ -165,0 +168,2 @@
+
+ def no_more_requests?: () -> bool
sig/connection/http2.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/connection/http2.rbs 2026-07-24 02:33:48.287293281 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/connection/http2.rbs 2026-07-24 02:33:48.349293105 +0000
@@ -18,0 +19 @@
+ @streams_to_close_after_receive: Array[[HTTP2::Stream, Request, HTTPX::Error]]
@@ -107,0 +109,2 @@
+
+ def emit_stream_error: (HTTP2::Stream stream, Request request, StandardError error) -> void
sig/loggable.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/loggable.rbs 2026-07-24 02:33:48.288293278 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/loggable.rbs 2026-07-24 02:33:48.350293102 +0000
@@ -14,0 +15,2 @@
+ def self.log_identifiers: () -> String
+
@@ -17,0 +20,2 @@
+
+ private
sig/plugins/auth.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/plugins/auth.rbs 2026-07-24 02:33:48.288293278 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/plugins/auth.rbs 2026-07-24 02:33:48.351293099 +0000
@@ -9,0 +10,4 @@
+
+ def auth_header_expires_at: () -> (^(Request request) -> _ToF?)?
+
+ def auth_header_expires_in: () -> Float?
sig/plugins/persistent.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/plugins/persistent.rbs 2026-07-24 02:33:48.293293264 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/plugins/persistent.rbs 2026-07-24 02:33:48.356293085 +0000
@@ -8,0 +9,3 @@
+ private
+
+ def reconnectable_error?: (StandardError error) -> bool
sig/request.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/request.rbs 2026-07-24 02:33:48.295293258 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/request.rbs 2026-07-24 02:33:48.359293077 +0000
@@ -20 +20 @@
- attr_reader active_timeouts: Array[Symbol]
+ attr_reader active_timeouts: Array[Timers::Timer]
@@ -96,2 +96 @@
- def initialize_body: (Options options) -> Transcoder::_Encoder?
-
+ def reset_timers: (bool reset_total_request_timers) -> void
sig/resolver/system.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/resolver/system.rbs 2026-07-24 02:33:48.297293252 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/resolver/system.rbs 2026-07-24 02:33:48.361293071 +0000
@@ -7,0 +8,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
sig/selector.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/selector.rbs 2026-07-24 02:33:48.298293249 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/selector.rbs 2026-07-24 02:33:48.361293071 +0000
@@ -8,0 +9,2 @@
+ def initial_call: () -> void
+
sig/timers.rbs
--- /tmp/d20260724-2694-jfk7lt/httpx-1.8.0/sig/timers.rbs 2026-07-24 02:33:48.298293249 +0000
+++ /tmp/d20260724-2694-jfk7lt/httpx-1.8.1/sig/timers.rbs 2026-07-24 02:33:48.361293071 +0000
@@ -50,0 +51,2 @@
+ attr_accessor label: Symbol?
+ |
Contributor
gem compare --diff httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md
--- /tmp/20260724-2696-sg8c00 2026-07-24 02:33:48.796149141 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/doc/release_notes/1_8_1.md 2026-07-24 02:33:48.770149308 +0000
@@ -0,0 +1,27 @@
+# 1.8.1
+
+## Improvements
+
+* the session will now eagerly write initial data to connections instead of waiting for I/O the first time (saves a syscall).
+* removed all rescue blocks rescuing `StandardError` internally; this could interfere with usages of `httpx` inside `Timeout.timeout` blocks, which may emit an exception at any point, including in blocks where that exception could be rescued, leaving the session in a potentially irrecoverable state and looping.
+* debug logs change the display of ids from 'tid:123, fid:123' to 'tid=123 fid:123'.
+ * and when using the `datadog` adapter, all related correlation ids (trace id, span id, etc) will also be added to the identifiers in the same format
+* plugins built on top of the `:retries` plugin will skip the `retry_after` interval when certain conditions are met.
+ * `:persistent` plugin: request will be retried immediately, when the error happens after the keep alive interval expired.
+ * `:auth` plugin: request will be retried immediately if it failed due to a "401 Unauthorized Error".
+* `:ssrf_filter` plugin: removed public/private references of exception message.
+
+## Bugfixes
+
+* `:auth` plugin: handle edge case where `:auth_header_expires_at` returns no value.
+* `:digest_auth` plugin: do not retry if there was an issue building building the authorization header after the probe.
+* `webmock` adapter: prevent mocked requests from opening a connection to the peer server that will not be used.
+* clear and cancel request timers on completion or reset, ensuring that they won't be retained way past the point where the request is gone.
+* connection: cancel and discard ping timer before closing (removes timer reference)
+* connection: fix logic where purging-while-resending requests to a coalesced connection was leaving references in the old connection.
+* moved an `on_body_chunk` callback to the `:callbacks` plugin, where it's used and expected to be defined.
+* `http2`: avoid closing the connection on internal errors which are supposed to be specific to a request, such as the max headers or max response body size checks.
+* system resolver will use an internal exception when using `Timeout.timeout` on resolutions to avoid conflicts with the default timeout exception class.
+* prevent edge case where `#alpn_protocol` was being called on a `TCPSocket`.
+* fixed v1.8.0 regression causing connection to loop when an error happens while connecting.
+* resolver cache: fixed cache eviction logic, where alias answers weren't being evicted, causing resolutions to stall after a certain number of resolutions.
* Changed:
doc/release_notes/1_7_1.md
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/doc/release_notes/1_7_1.md 2026-07-24 02:33:48.730149566 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/doc/release_notes/1_7_1.md 2026-07-24 02:33:48.769149315 +0000
@@ -20,2 +20 @@
-* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
-*
\ No newline at end of file
+* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
\ No newline at end of file
lib/httpx/adapters/datadog.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:48.732149553 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:48.771149302 +0000
@@ -187,0 +188,7 @@
+ # patches httpx debug logs to include datadog correlation ids
+ module LoggablePatch
+ def log_identifiers
+ "#{super} #{Datadog::Tracing.log_correlation}"
+ end
+ end
+
@@ -299,0 +307,2 @@
+
+ ::HTTPX::Loggable.singleton_class.prepend(LoggablePatch)
lib/httpx/adapters/faraday.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:48.732149553 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:48.771149302 +0000
@@ -118 +118 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/adapters/webmock.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:48.732149553 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:48.771149302 +0000
@@ -157,0 +158,6 @@
+
+ private
+
+ def connect
+ super unless @mocked
+ end
lib/httpx/connection.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/connection.rb 2026-07-24 02:33:48.733149546 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/connection.rb 2026-07-24 02:33:48.772149296 +0000
@@ -164 +163,0 @@
- pendings = []
@@ -168 +167,4 @@
- pendings << pending
+ pending.reject! do |req|
+ block.call(req)
+ true
+ end
@@ -170,3 +172,3 @@
- pendings << @pending
- pendings.each do |pending|
- pending.reject!(&block)
+ @pending.reject! do |req|
+ block.call(req)
+ true
@@ -206 +208 @@
- rescue StandardError => e
+ rescue Error => e
@@ -217,0 +220,2 @@
+ return if no_more_requests?
+
@@ -225 +229 @@
- return if @pending.empty?
+ return if no_more_requests?
@@ -250 +254,5 @@
- rescue IOError => e
+ rescue Errno::ECONNRESET,
+ Errno::EINVAL,
+ SocketError,
+ IOError,
+ TLSError => e
@@ -253 +261 @@
- rescue StandardError => e
+ rescue Error => e
@@ -260,0 +269,4 @@
+ def initial_call
+ call
+ end
+
@@ -316,0 +329,5 @@
+ if @ping_timer
+ @ping_timer.cancel
+ @ping_timer = nil
+ end
+
@@ -435,0 +453,5 @@
+
+ # do not force close if parser resets the connection.
+ # can happen i.e. when HTTP/1.1 pipelining is disabled.
+ return if @state == :idle && @pending.any?
+
@@ -459 +481 @@
- # :nocov:
+ # simplecov:disable
@@ -467 +489 @@
- # :nocov:
+ # simplecov:enable
@@ -493 +515 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty?
+ if no_more_requests? && @write_buffer.empty?
@@ -543 +565 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty? # rubocop:disable Style/Next
+ if no_more_requests? && @write_buffer.empty? # rubocop:disable Style/Next
@@ -962,0 +985 @@
+ log(level: 3) { "ping timeout expired..." }
@@ -988,0 +1012,5 @@
+ # true when there are no more pending nor inflight (in parser) requests
+ def no_more_requests?
+ @pending.empty? && @inflight.zero?
+ end
+
@@ -1102 +1130,2 @@
- request.active_timeouts << label
+ timer.label = label
+ request.active_timeouts << timer
@@ -1108 +1137 @@
- request.active_timeouts.delete(label)
+ request.active_timeouts.delete(timer)
lib/httpx/connection/http1.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/connection/http1.rb 2026-07-24 02:33:48.733149546 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/connection/http1.rb 2026-07-24 02:33:48.772149296 +0000
@@ -165,12 +165,6 @@
- begin
- request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
- request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
-
- response = request.response
-
- response << chunk
- rescue StandardError => e
- error_response = ErrorResponse.new(request, e)
- request.response = error_response
- dispatch(request)
- end
+ request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
+ request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
+
+ response = request.response
+
+ response << chunk
@@ -419 +413 @@
- UPCASED[field] || field.split("-").map(&:capitalize).join("-")
+ UPCASED.fetch(field) { field.split("-").map(&:capitalize).join("-") }
lib/httpx/connection/http2.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/connection/http2.rb 2026-07-24 02:33:48.733149546 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/connection/http2.rb 2026-07-24 02:33:48.772149296 +0000
@@ -39,0 +40 @@
+ @streams_to_close_after_receive = []
@@ -112,0 +114,6 @@
+
+ while (stream, request, error = @streams_to_close_after_receive.shift)
+ # these streams were marked for cancellation due to errors found while processing the
+ # data received by the peer.
+ emit_stream_error(stream, request, error)
+ end
@@ -131 +138 @@
- rescue StandardError => e
+ rescue ::HTTP2::Error::Error, ArgumentError => e
@@ -335,0 +343,2 @@
+ rescue HTTPX::Error => e
+ @streams_to_close_after_receive << [stream, request, e]
@@ -347,0 +357,3 @@
+
+ return unless request.response
+
@@ -348,0 +361,8 @@
+ rescue HTTPX::Error => e
+ if stream.state == :closing
+ # there won't be any more chunks to process after this one.
+ emit_stream_error(stream, request, e)
+ else
+ # defer until the last chunk from the payload is processed.
+ @streams_to_close_after_receive << [stream, request, e]
+ end
@@ -384,5 +404,6 @@
- response = request.response
- if response && response.is_a?(Response) && response.status == 421
- emit(:error, request, :http_1_1_required)
- else
- emit(:response, request, response)
+ if (response = request.response)
+ if response.is_a?(Response) && response.status == 421
+ emit(:error, request, :http_1_1_required)
+ else
+ emit(:response, request, response)
+ end
@@ -509,0 +531,6 @@
+ end
+
+ def emit_stream_error(stream, request, error)
+ teardown(request)
+ stream.close
+ emit(:error, request, error)
lib/httpx/headers.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/headers.rb 2026-07-24 02:33:48.733149546 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/headers.rb 2026-07-24 02:33:48.773149289 +0000
@@ -143 +143 @@
- # :nocov:
+ # simplecov:disable
@@ -148 +148 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/ssl.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/io/ssl.rb 2026-07-24 02:33:48.734149540 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/io/ssl.rb 2026-07-24 02:33:48.773149289 +0000
@@ -23,2 +23,3 @@
- ctx_options = TLS_OPTIONS.merge(options.ssl)
- @sni_hostname = ctx_options.delete(:hostname) || @hostname
+ ctx_options = TLS_OPTIONS
+ ctx_options = ctx_options.merge(options.ssl) if options.ssl && !options.ssl.empty?
+ @sni_hostname = (ctx_options.delete(:hostname) if ctx_options.key?(:hostname)) || @hostname
@@ -32 +33 @@
- @ctx.set_params(ctx_options) unless ctx_options.empty?
+ @ctx.set_params(ctx_options)
@@ -54 +55,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -56,2 +57,0 @@
- rescue StandardError
- super
@@ -64 +64,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -70,2 +70,0 @@
- rescue StandardError
- super
lib/httpx/io/tcp.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/io/tcp.rb 2026-07-24 02:33:48.734149540 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/io/tcp.rb 2026-07-24 02:33:48.773149289 +0000
@@ -185 +185,8 @@
- return if @keep_open || closed?
+ return if @keep_open
+
+ # mark tcp as closed, so that it can be disconnected.
+ # this bypasses the state machine API as not not allow the transition
+ # from idle to closed in normal circumstances.
+ @state = :closed if @state == :idle
+
+ return if closed?
@@ -189 +196 @@
- rescue StandardError => e
+ rescue IOError => e
@@ -215 +222 @@
- # :nocov:
+ # simplecov:disable
@@ -224 +231 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/unix.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/io/unix.rb 2026-07-24 02:33:48.734149540 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/io/unix.rb 2026-07-24 02:33:48.773149289 +0000
@@ -63 +63 @@
- # :nocov:
+ # simplecov:disable
@@ -67 +67 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/loggable.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/loggable.rb 2026-07-24 02:33:48.734149540 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/loggable.rb 2026-07-24 02:33:48.773149289 +0000
@@ -19,0 +20,6 @@
+ def self.log_identifiers
+ "pid=#{Process.pid} " \
+ "tid=#{Thread.current.object_id} " \
+ "fid=#{Fiber.current.object_id}"
+ end
+
@@ -39,4 +45,3 @@
- message = +"(time:#{Time.now.utc}, pid:#{Process.pid}, " \
- "tid:#{Thread.current.object_id}, " \
- "fid:#{Fiber.current.object_id}, " \
- "self:#{class_name}##{object_id}) "
+ message = +"(time=#{Time.now.utc} " \
+ "#{Loggable.log_identifiers} " \
+ "self=#{class_name}##{object_id}) "
@@ -50,0 +56,2 @@
+
+ private
lib/httpx/plugins/auth.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/auth.rb 2026-07-24 02:33:48.735149533 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/auth.rb 2026-07-24 02:33:48.774149283 +0000
@@ -130,2 +130,2 @@
- if expires_at.respond_to?(:call)
- expires_at = expires_at.call(request).to_f
+ if expires_at.respond_to?(:call) && (expires_at = expires_at.call(request))
+ expires_at = expires_at.to_f
@@ -204,0 +205,9 @@
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(Response)
+
+ # retry immediately if authentication no longer valid.
+ return if response.status == 401
+
+ super
lib/httpx/plugins/auth/digest.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:48.735149533 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:48.774149283 +0000
@@ -27 +27 @@
- rescue StandardError => e
+ rescue HTTPX::Error => e
lib/httpx/plugins/callbacks.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:48.736149527 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:48.775149276 +0000
@@ -124,0 +125,12 @@
+ module RequestMethods
+ def drain_body
+ super.tap do |chunk|
+ emit(:body_chunk, chunk) if chunk
+ rescue StandardError => e
+ # in case an error occurs in callback code
+ @drain_error = e
+ nil
+ end
+ end
+ end
+
lib/httpx/plugins/digest_auth.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:48.737149521 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:48.776149270 +0000
@@ -53,0 +54 @@
+
@@ -56,0 +58,3 @@
+
+ next(request.response) if request.response
+
lib/httpx/plugins/fiber_concurrency.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:48.738149514 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:48.777149263 +0000
@@ -72,0 +73,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -195,0 +202,6 @@
+ def initial_call
+ return unless @queries.values.any?(&:current_context?) || @connections.any?(&:current_context?)
+
+ super
+ end
+
@@ -220,0 +233,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -222 +240 @@
- return unless @queries.any? { |_, conn| conn.current_context? }
+ return unless current_context?
@@ -224,0 +243,6 @@
+ end
+
+ private
+
+ def current_context?
+ @queries.any? { |_, conn| conn.current_context? }
lib/httpx/plugins/persistent.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:48.739149508 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:48.778149257 +0000
@@ -57,0 +58,16 @@
+ def reconnectable_error?(error)
+ Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(ErrorResponse)
+
+ error = response.error
+ # allow request to be retried immediately if the request failed right after the keep alive timeout.
+ # the chances are, the request failed because the connect has been dropped by the peer server, so it's
+ # fine to reopen.
+ return if request.ping? && reconnectable_error?(error)
+
+ super
+ end
+
@@ -60 +76 @@
- return false unless response && response.is_a?(ErrorResponse)
+ return false unless response.is_a?(ErrorResponse)
@@ -64 +80 @@
- Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ reconnectable_error?(error)
lib/httpx/plugins/push_promise.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:48.740149501 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:48.779149251 +0000
@@ -47 +47 @@
- # :nocov:
+ # simplecov:disable
@@ -49 +49 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/ssrf_filter.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:48.741149495 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:48.780149244 +0000
@@ -152 +152 @@
- raise ServerSideRequestForgeryError, "#{@origin.host} has no public IP addresses" if addrs.empty?
+ raise ServerSideRequestForgeryError, "#{@origin.host} has no allowed IP addresses" if addrs.empty?
lib/httpx/plugins/stream.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/stream.rb 2026-07-24 02:33:48.741149495 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/stream.rb 2026-07-24 02:33:48.780149244 +0000
@@ -78 +78 @@
- # :nocov:
+ # simplecov:disable
@@ -82 +82 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/stream_bidi.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:48.741149495 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:48.780149244 +0000
@@ -179,0 +180,2 @@
+ def initial_call; end
+
lib/httpx/pool.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/pool.rb 2026-07-24 02:33:48.742149488 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/pool.rb 2026-07-24 02:33:48.781149238 +0000
@@ -176 +176 @@
- # :nocov:
+ # simplecov:disable
@@ -184 +184 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/request.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/request.rb 2026-07-24 02:33:48.742149488 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/request.rb 2026-07-24 02:33:48.781149238 +0000
@@ -124,0 +125 @@
+ reset_timers(true)
@@ -271 +272 @@
- return nil if @body.nil?
+ return if @body.nil?
@@ -274,4 +275 @@
- chunk = @drainer.next.dup
-
- emit(:body_chunk, chunk)
- chunk
+ @drainer.next.dup
@@ -280,0 +279 @@
+ # in case an error occurs while emitting body chunks
@@ -285 +284 @@
- # :nocov:
+ # simplecov:disable
@@ -293 +292 @@
- # :nocov:
+ # simplecov:enable
@@ -302 +301,4 @@
- @active_timeouts.clear
+
+ # request may be sent to a different connection and will be
+ # reassigned a new set of timers.
+ reset_timers(false)
@@ -329 +331 @@
- log(level: 3) { "#{@state}] -> #{nextstate}" }
+ log(level: 3) { "#{@state} -> #{nextstate}" }
@@ -364,0 +367,13 @@
+ end
+
+ private
+
+ def reset_timers(reset_total_request_timers)
+ timers = @active_timeouts
+
+ until (timer = timers.shift).nil?
+ next if !reset_total_request_timers && timer.label == :total_request_timeout
+
+ # cancel active timers.
+ timer.cancel
+ end
lib/httpx/request/body.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/request/body.rb 2026-07-24 02:33:48.742149488 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/request/body.rb 2026-07-24 02:33:48.781149238 +0000
@@ -117 +117 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/resolver/cache/base.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:48.742149488 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:48.782149231 +0000
@@ -109,8 +109 @@
- lookups[name] ||= []
-
- case family
- when Socket::AF_INET6
- lookups[name] << entry
- when Socket::AF_INET
- lookups[name].unshift(entry)
- end
+ _set(name, family, [entry], lookups, hostnames)
lib/httpx/resolver/https.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/resolver/https.rb 2026-07-24 02:33:48.743149482 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/resolver/https.rb 2026-07-24 02:33:48.782149231 +0000
@@ -129,13 +129,12 @@
- response.raise_for_status
- rescue StandardError => e
- hostname = @requests.delete(request)
- connection = reset_hostname(hostname)
- emit_resolve_error(connection, connection.peer.host, e)
- close_or_resolve
- else
- # @type var response: HTTPX::Response
- if response.status.between?(300, 399) && response.headers.key?("location")
- hostname = @requests[request]
- connection = @queries[hostname]
- location_uri = URI(response.headers["location"])
- location_uri = response.uri.merge(location_uri) if location_uri.relative?
+ if (e = response.error)
+ hostname = @requests.delete(request)
+ connection = reset_hostname(hostname)
+ emit_resolve_error(connection, connection.peer.host, e)
+ close_or_resolve
+ else
+ # @type var response: HTTPX::Response
+ if response.status.between?(300, 399) && response.headers.key?("location")
+ hostname = @requests[request]
+ connection = @queries[hostname]
+ location_uri = URI(response.headers["location"])
+ location_uri = response.uri.merge(location_uri) if location_uri.relative?
@@ -143,5 +142,5 @@
- # we assume that the DNS server URI changed permanently and move on
- @uri = location_uri
- send_request(hostname, connection)
- return
- end
+ # we assume that the DNS server URI changed permanently and move on
+ @uri = location_uri
+ send_request(hostname, connection)
+ return
+ end
@@ -149 +148,2 @@
- parse(request, response)
+ parse(request, response)
+ end
lib/httpx/resolver/native.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/resolver/native.rb 2026-07-24 02:33:48.743149482 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/resolver/native.rb 2026-07-24 02:33:48.783149225 +0000
@@ -77,0 +78,7 @@
+ when :idle, :closed
+ return if @connections.empty?
+
+ transition(:idle) if @state == :closed
+ transition(:open)
+
+ consume if @state == :open
lib/httpx/resolver/resolver.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:48.743149482 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:48.783149225 +0000
@@ -54,0 +55,4 @@
+ def initial_call
+ call
+ end
+
lib/httpx/resolver/system.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/resolver/system.rb 2026-07-24 02:33:48.743149482 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/resolver/system.rb 2026-07-24 02:33:48.783149225 +0000
@@ -25,0 +26,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
@@ -230 +233 @@
- Timeout.timeout(resolve_timeout) do
+ Timeout.timeout(resolve_timeout, AddrinfoTimeoutError) do
@@ -249 +252 @@
- if e.is_a?(Timeout::Error)
+ if e.is_a?(AddrinfoTimeoutError)
lib/httpx/response.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/response.rb 2026-07-24 02:33:48.744149476 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/response.rb 2026-07-24 02:33:48.783149225 +0000
@@ -144 +144 @@
- # :nocov:
+ # simplecov:disable
@@ -152 +152 @@
- # :nocov:
+ # simplecov:enable
@@ -270 +269,0 @@
- include Loggable
@@ -293 +292 @@
- log_exception(@error)
+ @request.log_exception(@error)
lib/httpx/response/body.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/response/body.rb 2026-07-24 02:33:48.744149476 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/response/body.rb 2026-07-24 02:33:48.783149225 +0000
@@ -164 +164 @@
- # :nocov:
+ # simplecov:disable
@@ -170 +170 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/selector.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/selector.rb 2026-07-24 02:33:48.744149476 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/selector.rb 2026-07-24 02:33:48.783149225 +0000
@@ -43,0 +44,5 @@
+ # first time the registered selectables are added, there's probably work to do.
+ def initial_call
+ @selectables.each(&:initial_call)
+ end
+
lib/httpx/session.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/session.rb 2026-07-24 02:33:48.744149476 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/session.rb 2026-07-24 02:33:48.784149218 +0000
@@ -322 +322 @@
- responses = requests.each_with_index.map do |request, idx|
+ requests.each do |request|
@@ -323,0 +324,4 @@
+ end
+
+ # do work first
+ selector.initial_call
@@ -324,0 +329 @@
+ responses = requests.each_with_index.map do |request, idx|
lib/httpx/session_extensions.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/session_extensions.rb 2026-07-24 02:33:48.744149476 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/session_extensions.rb 2026-07-24 02:33:48.784149218 +0000
@@ -23 +23 @@
- # :nocov:
+ # simplecov:disable
@@ -29 +29 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/timers.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/timers.rb 2026-07-24 02:33:48.744149476 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/timers.rb 2026-07-24 02:33:48.784149218 +0000
@@ -64,0 +65,3 @@
+ # simpler helper which allows classification
+ attr_accessor :label
+
lib/httpx/version.rb
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/lib/httpx/version.rb 2026-07-24 02:33:48.746149463 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/lib/httpx/version.rb 2026-07-24 02:33:48.785149212 +0000
@@ -4 +4 @@
- VERSION = "1.8.0"
+ VERSION = "1.8.1"
sig/connection.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/connection.rbs 2026-07-24 02:33:48.747149456 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/connection.rbs 2026-07-24 02:33:48.786149206 +0000
@@ -94,0 +95,2 @@
+ def initial_call: () -> void
+
@@ -125 +127 @@
- def on_io_error: (IOError error) -> void
+ def on_io_error: (SocketError | IOError | TLSError error) -> void
@@ -165,0 +168,2 @@
+
+ def no_more_requests?: () -> bool
sig/connection/http2.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/connection/http2.rbs 2026-07-24 02:33:48.747149456 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/connection/http2.rbs 2026-07-24 02:33:48.786149206 +0000
@@ -18,0 +19 @@
+ @streams_to_close_after_receive: Array[[HTTP2::Stream, Request, HTTPX::Error]]
@@ -107,0 +109,2 @@
+
+ def emit_stream_error: (HTTP2::Stream stream, Request request, StandardError error) -> void
sig/loggable.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/loggable.rbs 2026-07-24 02:33:48.748149450 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/loggable.rbs 2026-07-24 02:33:48.787149199 +0000
@@ -14,0 +15,2 @@
+ def self.log_identifiers: () -> String
+
@@ -17,0 +20,2 @@
+
+ private
sig/plugins/auth.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/plugins/auth.rbs 2026-07-24 02:33:48.748149450 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/plugins/auth.rbs 2026-07-24 02:33:48.788149193 +0000
@@ -9,0 +10,4 @@
+
+ def auth_header_expires_at: () -> (^(Request request) -> _ToF?)?
+
+ def auth_header_expires_in: () -> Float?
sig/plugins/persistent.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/plugins/persistent.rbs 2026-07-24 02:33:48.751149431 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/plugins/persistent.rbs 2026-07-24 02:33:48.791149173 +0000
@@ -8,0 +9,3 @@
+ private
+
+ def reconnectable_error?: (StandardError error) -> bool
sig/request.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/request.rbs 2026-07-24 02:33:48.753149418 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/request.rbs 2026-07-24 02:33:48.793149161 +0000
@@ -20 +20 @@
- attr_reader active_timeouts: Array[Symbol]
+ attr_reader active_timeouts: Array[Timers::Timer]
@@ -96,2 +96 @@
- def initialize_body: (Options options) -> Transcoder::_Encoder?
-
+ def reset_timers: (bool reset_total_request_timers) -> void
sig/resolver/system.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/resolver/system.rbs 2026-07-24 02:33:48.755149405 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/resolver/system.rbs 2026-07-24 02:33:48.794149154 +0000
@@ -7,0 +8,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
sig/selector.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/selector.rbs 2026-07-24 02:33:48.755149405 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/selector.rbs 2026-07-24 02:33:48.795149148 +0000
@@ -8,0 +9,2 @@
+ def initial_call: () -> void
+
sig/timers.rbs
--- /tmp/d20260724-2696-4yxvx0/httpx-1.8.0/sig/timers.rbs 2026-07-24 02:33:48.755149405 +0000
+++ /tmp/d20260724-2696-4yxvx0/httpx-1.8.1/sig/timers.rbs 2026-07-24 02:33:48.795149148 +0000
@@ -50,0 +51,2 @@
+ attr_accessor label: Symbol?
+ |
Contributor
gem compare --diff httpx 1.8.0 1.8.1Compared versions: ["1.8.0", "1.8.1"]
DIFFERENT files:
1.8.0->1.8.1:
* Added:
doc/release_notes/1_8_1.md
--- /tmp/20260724-2669-gzy9ry 2026-07-24 02:33:58.605369791 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/doc/release_notes/1_8_1.md 2026-07-24 02:33:58.564369816 +0000
@@ -0,0 +1,27 @@
+# 1.8.1
+
+## Improvements
+
+* the session will now eagerly write initial data to connections instead of waiting for I/O the first time (saves a syscall).
+* removed all rescue blocks rescuing `StandardError` internally; this could interfere with usages of `httpx` inside `Timeout.timeout` blocks, which may emit an exception at any point, including in blocks where that exception could be rescued, leaving the session in a potentially irrecoverable state and looping.
+* debug logs change the display of ids from 'tid:123, fid:123' to 'tid=123 fid:123'.
+ * and when using the `datadog` adapter, all related correlation ids (trace id, span id, etc) will also be added to the identifiers in the same format
+* plugins built on top of the `:retries` plugin will skip the `retry_after` interval when certain conditions are met.
+ * `:persistent` plugin: request will be retried immediately, when the error happens after the keep alive interval expired.
+ * `:auth` plugin: request will be retried immediately if it failed due to a "401 Unauthorized Error".
+* `:ssrf_filter` plugin: removed public/private references of exception message.
+
+## Bugfixes
+
+* `:auth` plugin: handle edge case where `:auth_header_expires_at` returns no value.
+* `:digest_auth` plugin: do not retry if there was an issue building building the authorization header after the probe.
+* `webmock` adapter: prevent mocked requests from opening a connection to the peer server that will not be used.
+* clear and cancel request timers on completion or reset, ensuring that they won't be retained way past the point where the request is gone.
+* connection: cancel and discard ping timer before closing (removes timer reference)
+* connection: fix logic where purging-while-resending requests to a coalesced connection was leaving references in the old connection.
+* moved an `on_body_chunk` callback to the `:callbacks` plugin, where it's used and expected to be defined.
+* `http2`: avoid closing the connection on internal errors which are supposed to be specific to a request, such as the max headers or max response body size checks.
+* system resolver will use an internal exception when using `Timeout.timeout` on resolutions to avoid conflicts with the default timeout exception class.
+* prevent edge case where `#alpn_protocol` was being called on a `TCPSocket`.
+* fixed v1.8.0 regression causing connection to loop when an error happens while connecting.
+* resolver cache: fixed cache eviction logic, where alias answers weren't being evicted, causing resolutions to stall after a certain number of resolutions.
* Changed:
doc/release_notes/1_7_1.md
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/doc/release_notes/1_7_1.md 2026-07-24 02:33:58.485369864 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/doc/release_notes/1_7_1.md 2026-07-24 02:33:58.563369816 +0000
@@ -20,2 +20 @@
-* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
-*
\ No newline at end of file
+* selector loop fix: when there are no selectables and an interval is passed, sleep instead of returning (thereby avoiding potential busy loop).
\ No newline at end of file
lib/httpx/adapters/datadog.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:58.487369862 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/adapters/datadog.rb 2026-07-24 02:33:58.565369815 +0000
@@ -187,0 +188,7 @@
+ # patches httpx debug logs to include datadog correlation ids
+ module LoggablePatch
+ def log_identifiers
+ "#{super} #{Datadog::Tracing.log_correlation}"
+ end
+ end
+
@@ -299,0 +307,2 @@
+
+ ::HTTPX::Loggable.singleton_class.prepend(LoggablePatch)
lib/httpx/adapters/faraday.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:58.487369862 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/adapters/faraday.rb 2026-07-24 02:33:58.565369815 +0000
@@ -118 +118 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/adapters/webmock.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:58.487369862 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/adapters/webmock.rb 2026-07-24 02:33:58.565369815 +0000
@@ -157,0 +158,6 @@
+
+ private
+
+ def connect
+ super unless @mocked
+ end
lib/httpx/connection.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/connection.rb 2026-07-24 02:33:58.488369862 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/connection.rb 2026-07-24 02:33:58.566369814 +0000
@@ -164 +163,0 @@
- pendings = []
@@ -168 +167,4 @@
- pendings << pending
+ pending.reject! do |req|
+ block.call(req)
+ true
+ end
@@ -170,3 +172,3 @@
- pendings << @pending
- pendings.each do |pending|
- pending.reject!(&block)
+ @pending.reject! do |req|
+ block.call(req)
+ true
@@ -206 +208 @@
- rescue StandardError => e
+ rescue Error => e
@@ -217,0 +220,2 @@
+ return if no_more_requests?
+
@@ -225 +229 @@
- return if @pending.empty?
+ return if no_more_requests?
@@ -250 +254,5 @@
- rescue IOError => e
+ rescue Errno::ECONNRESET,
+ Errno::EINVAL,
+ SocketError,
+ IOError,
+ TLSError => e
@@ -253 +261 @@
- rescue StandardError => e
+ rescue Error => e
@@ -260,0 +269,4 @@
+ def initial_call
+ call
+ end
+
@@ -316,0 +329,5 @@
+ if @ping_timer
+ @ping_timer.cancel
+ @ping_timer = nil
+ end
+
@@ -435,0 +453,5 @@
+
+ # do not force close if parser resets the connection.
+ # can happen i.e. when HTTP/1.1 pipelining is disabled.
+ return if @state == :idle && @pending.any?
+
@@ -459 +481 @@
- # :nocov:
+ # simplecov:disable
@@ -467 +489 @@
- # :nocov:
+ # simplecov:enable
@@ -493 +515 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty?
+ if no_more_requests? && @write_buffer.empty?
@@ -543 +565 @@
- if @pending.empty? && @inflight.zero? && @write_buffer.empty? # rubocop:disable Style/Next
+ if no_more_requests? && @write_buffer.empty? # rubocop:disable Style/Next
@@ -962,0 +985 @@
+ log(level: 3) { "ping timeout expired..." }
@@ -988,0 +1012,5 @@
+ # true when there are no more pending nor inflight (in parser) requests
+ def no_more_requests?
+ @pending.empty? && @inflight.zero?
+ end
+
@@ -1102 +1130,2 @@
- request.active_timeouts << label
+ timer.label = label
+ request.active_timeouts << timer
@@ -1108 +1137 @@
- request.active_timeouts.delete(label)
+ request.active_timeouts.delete(timer)
lib/httpx/connection/http1.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/connection/http1.rb 2026-07-24 02:33:58.488369862 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/connection/http1.rb 2026-07-24 02:33:58.566369814 +0000
@@ -165,12 +165,6 @@
- begin
- request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
- request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
-
- response = request.response
-
- response << chunk
- rescue StandardError => e
- error_response = ErrorResponse.new(request, e)
- request.response = error_response
- dispatch(request)
- end
+ request.log(color: :green) { "-> DATA: #{chunk.bytesize} bytes..." }
+ request.log(level: 2, color: :green) { "-> #{log_redact_body(chunk.inspect)}" }
+
+ response = request.response
+
+ response << chunk
@@ -419 +413 @@
- UPCASED[field] || field.split("-").map(&:capitalize).join("-")
+ UPCASED.fetch(field) { field.split("-").map(&:capitalize).join("-") }
lib/httpx/connection/http2.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/connection/http2.rb 2026-07-24 02:33:58.489369861 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/connection/http2.rb 2026-07-24 02:33:58.566369814 +0000
@@ -39,0 +40 @@
+ @streams_to_close_after_receive = []
@@ -112,0 +114,6 @@
+
+ while (stream, request, error = @streams_to_close_after_receive.shift)
+ # these streams were marked for cancellation due to errors found while processing the
+ # data received by the peer.
+ emit_stream_error(stream, request, error)
+ end
@@ -131 +138 @@
- rescue StandardError => e
+ rescue ::HTTP2::Error::Error, ArgumentError => e
@@ -335,0 +343,2 @@
+ rescue HTTPX::Error => e
+ @streams_to_close_after_receive << [stream, request, e]
@@ -347,0 +357,3 @@
+
+ return unless request.response
+
@@ -348,0 +361,8 @@
+ rescue HTTPX::Error => e
+ if stream.state == :closing
+ # there won't be any more chunks to process after this one.
+ emit_stream_error(stream, request, e)
+ else
+ # defer until the last chunk from the payload is processed.
+ @streams_to_close_after_receive << [stream, request, e]
+ end
@@ -384,5 +404,6 @@
- response = request.response
- if response && response.is_a?(Response) && response.status == 421
- emit(:error, request, :http_1_1_required)
- else
- emit(:response, request, response)
+ if (response = request.response)
+ if response.is_a?(Response) && response.status == 421
+ emit(:error, request, :http_1_1_required)
+ else
+ emit(:response, request, response)
+ end
@@ -509,0 +531,6 @@
+ end
+
+ def emit_stream_error(stream, request, error)
+ teardown(request)
+ stream.close
+ emit(:error, request, error)
lib/httpx/headers.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/headers.rb 2026-07-24 02:33:58.490369861 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/headers.rb 2026-07-24 02:33:58.567369814 +0000
@@ -143 +143 @@
- # :nocov:
+ # simplecov:disable
@@ -148 +148 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/ssl.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/io/ssl.rb 2026-07-24 02:33:58.490369861 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/io/ssl.rb 2026-07-24 02:33:58.568369813 +0000
@@ -23,2 +23,3 @@
- ctx_options = TLS_OPTIONS.merge(options.ssl)
- @sni_hostname = ctx_options.delete(:hostname) || @hostname
+ ctx_options = TLS_OPTIONS
+ ctx_options = ctx_options.merge(options.ssl) if options.ssl && !options.ssl.empty?
+ @sni_hostname = (ctx_options.delete(:hostname) if ctx_options.key?(:hostname)) || @hostname
@@ -32 +33 @@
- @ctx.set_params(ctx_options) unless ctx_options.empty?
+ @ctx.set_params(ctx_options)
@@ -54 +55,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -56,2 +57,0 @@
- rescue StandardError
- super
@@ -64 +64,2 @@
- # @type ivar @io: OpenSSL::SSL::SSLSocket
+ return super unless @io.is_a?(OpenSSL::SSL::SSLSocket)
+
@@ -70,2 +70,0 @@
- rescue StandardError
- super
lib/httpx/io/tcp.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/io/tcp.rb 2026-07-24 02:33:58.490369861 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/io/tcp.rb 2026-07-24 02:33:58.568369813 +0000
@@ -185 +185,8 @@
- return if @keep_open || closed?
+ return if @keep_open
+
+ # mark tcp as closed, so that it can be disconnected.
+ # this bypasses the state machine API as not not allow the transition
+ # from idle to closed in normal circumstances.
+ @state = :closed if @state == :idle
+
+ return if closed?
@@ -189 +196 @@
- rescue StandardError => e
+ rescue IOError => e
@@ -215 +222 @@
- # :nocov:
+ # simplecov:disable
@@ -224 +231 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/io/unix.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/io/unix.rb 2026-07-24 02:33:58.491369860 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/io/unix.rb 2026-07-24 02:33:58.568369813 +0000
@@ -63 +63 @@
- # :nocov:
+ # simplecov:disable
@@ -67 +67 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/loggable.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/loggable.rb 2026-07-24 02:33:58.495369858 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/loggable.rb 2026-07-24 02:33:58.568369813 +0000
@@ -19,0 +20,6 @@
+ def self.log_identifiers
+ "pid=#{Process.pid} " \
+ "tid=#{Thread.current.object_id} " \
+ "fid=#{Fiber.current.object_id}"
+ end
+
@@ -39,4 +45,3 @@
- message = +"(time:#{Time.now.utc}, pid:#{Process.pid}, " \
- "tid:#{Thread.current.object_id}, " \
- "fid:#{Fiber.current.object_id}, " \
- "self:#{class_name}##{object_id}) "
+ message = +"(time=#{Time.now.utc} " \
+ "#{Loggable.log_identifiers} " \
+ "self=#{class_name}##{object_id}) "
@@ -50,0 +56,2 @@
+
+ private
lib/httpx/plugins/auth.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/auth.rb 2026-07-24 02:33:58.496369857 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/auth.rb 2026-07-24 02:33:58.569369813 +0000
@@ -130,2 +130,2 @@
- if expires_at.respond_to?(:call)
- expires_at = expires_at.call(request).to_f
+ if expires_at.respond_to?(:call) && (expires_at = expires_at.call(request))
+ expires_at = expires_at.to_f
@@ -204,0 +205,9 @@
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(Response)
+
+ # retry immediately if authentication no longer valid.
+ return if response.status == 401
+
+ super
lib/httpx/plugins/auth/digest.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:58.497369856 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/auth/digest.rb 2026-07-24 02:33:58.569369813 +0000
@@ -27 +27 @@
- rescue StandardError => e
+ rescue HTTPX::Error => e
lib/httpx/plugins/callbacks.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:58.499369855 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/callbacks.rb 2026-07-24 02:33:58.571369811 +0000
@@ -124,0 +125,12 @@
+ module RequestMethods
+ def drain_body
+ super.tap do |chunk|
+ emit(:body_chunk, chunk) if chunk
+ rescue StandardError => e
+ # in case an error occurs in callback code
+ @drain_error = e
+ nil
+ end
+ end
+ end
+
lib/httpx/plugins/digest_auth.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:58.502369853 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/digest_auth.rb 2026-07-24 02:33:58.572369811 +0000
@@ -53,0 +54 @@
+
@@ -56,0 +58,3 @@
+
+ next(request.response) if request.response
+
lib/httpx/plugins/fiber_concurrency.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:58.502369853 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/fiber_concurrency.rb 2026-07-24 02:33:58.572369811 +0000
@@ -72,0 +73,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -195,0 +202,6 @@
+ def initial_call
+ return unless @queries.values.any?(&:current_context?) || @connections.any?(&:current_context?)
+
+ super
+ end
+
@@ -220,0 +233,6 @@
+ def initial_call
+ return unless current_context?
+
+ super
+ end
+
@@ -222 +240 @@
- return unless @queries.any? { |_, conn| conn.current_context? }
+ return unless current_context?
@@ -224,0 +243,6 @@
+ end
+
+ private
+
+ def current_context?
+ @queries.any? { |_, conn| conn.current_context? }
lib/httpx/plugins/persistent.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:58.505369852 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/persistent.rb 2026-07-24 02:33:58.574369810 +0000
@@ -57,0 +58,16 @@
+ def reconnectable_error?(error)
+ Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ end
+
+ def when_to_retry(request, response, *)
+ return super unless response.is_a?(ErrorResponse)
+
+ error = response.error
+ # allow request to be retried immediately if the request failed right after the keep alive timeout.
+ # the chances are, the request failed because the connect has been dropped by the peer server, so it's
+ # fine to reopen.
+ return if request.ping? && reconnectable_error?(error)
+
+ super
+ end
+
@@ -60 +76 @@
- return false unless response && response.is_a?(ErrorResponse)
+ return false unless response.is_a?(ErrorResponse)
@@ -64 +80 @@
- Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
+ reconnectable_error?(error)
lib/httpx/plugins/push_promise.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:58.507369850 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/push_promise.rb 2026-07-24 02:33:58.575369809 +0000
@@ -47 +47 @@
- # :nocov:
+ # simplecov:disable
@@ -49 +49 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/ssrf_filter.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:58.508369850 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/ssrf_filter.rb 2026-07-24 02:33:58.575369809 +0000
@@ -152 +152 @@
- raise ServerSideRequestForgeryError, "#{@origin.host} has no public IP addresses" if addrs.empty?
+ raise ServerSideRequestForgeryError, "#{@origin.host} has no allowed IP addresses" if addrs.empty?
lib/httpx/plugins/stream.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/stream.rb 2026-07-24 02:33:58.508369850 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/stream.rb 2026-07-24 02:33:58.575369809 +0000
@@ -78 +78 @@
- # :nocov:
+ # simplecov:disable
@@ -82 +82 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/plugins/stream_bidi.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:58.508369850 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/plugins/stream_bidi.rb 2026-07-24 02:33:58.576369808 +0000
@@ -179,0 +180,2 @@
+ def initial_call; end
+
lib/httpx/pool.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/pool.rb 2026-07-24 02:33:58.510369848 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/pool.rb 2026-07-24 02:33:58.577369808 +0000
@@ -176 +176 @@
- # :nocov:
+ # simplecov:disable
@@ -184 +184 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/request.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/request.rb 2026-07-24 02:33:58.510369848 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/request.rb 2026-07-24 02:33:58.577369808 +0000
@@ -124,0 +125 @@
+ reset_timers(true)
@@ -271 +272 @@
- return nil if @body.nil?
+ return if @body.nil?
@@ -274,4 +275 @@
- chunk = @drainer.next.dup
-
- emit(:body_chunk, chunk)
- chunk
+ @drainer.next.dup
@@ -280,0 +279 @@
+ # in case an error occurs while emitting body chunks
@@ -285 +284 @@
- # :nocov:
+ # simplecov:disable
@@ -293 +292 @@
- # :nocov:
+ # simplecov:enable
@@ -302 +301,4 @@
- @active_timeouts.clear
+
+ # request may be sent to a different connection and will be
+ # reassigned a new set of timers.
+ reset_timers(false)
@@ -329 +331 @@
- log(level: 3) { "#{@state}] -> #{nextstate}" }
+ log(level: 3) { "#{@state} -> #{nextstate}" }
@@ -364,0 +367,13 @@
+ end
+
+ private
+
+ def reset_timers(reset_total_request_timers)
+ timers = @active_timeouts
+
+ until (timer = timers.shift).nil?
+ next if !reset_total_request_timers && timer.label == :total_request_timeout
+
+ # cancel active timers.
+ timer.cancel
+ end
lib/httpx/request/body.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/request/body.rb 2026-07-24 02:33:58.511369848 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/request/body.rb 2026-07-24 02:33:58.577369808 +0000
@@ -117 +117 @@
- # :nocov:
+ # simplecov:disable
@@ -122 +122 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/resolver/cache/base.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:58.512369847 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/resolver/cache/base.rb 2026-07-24 02:33:58.578369807 +0000
@@ -109,8 +109 @@
- lookups[name] ||= []
-
- case family
- when Socket::AF_INET6
- lookups[name] << entry
- when Socket::AF_INET
- lookups[name].unshift(entry)
- end
+ _set(name, family, [entry], lookups, hostnames)
lib/httpx/resolver/https.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/resolver/https.rb 2026-07-24 02:33:58.512369847 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/resolver/https.rb 2026-07-24 02:33:58.579369807 +0000
@@ -129,13 +129,12 @@
- response.raise_for_status
- rescue StandardError => e
- hostname = @requests.delete(request)
- connection = reset_hostname(hostname)
- emit_resolve_error(connection, connection.peer.host, e)
- close_or_resolve
- else
- # @type var response: HTTPX::Response
- if response.status.between?(300, 399) && response.headers.key?("location")
- hostname = @requests[request]
- connection = @queries[hostname]
- location_uri = URI(response.headers["location"])
- location_uri = response.uri.merge(location_uri) if location_uri.relative?
+ if (e = response.error)
+ hostname = @requests.delete(request)
+ connection = reset_hostname(hostname)
+ emit_resolve_error(connection, connection.peer.host, e)
+ close_or_resolve
+ else
+ # @type var response: HTTPX::Response
+ if response.status.between?(300, 399) && response.headers.key?("location")
+ hostname = @requests[request]
+ connection = @queries[hostname]
+ location_uri = URI(response.headers["location"])
+ location_uri = response.uri.merge(location_uri) if location_uri.relative?
@@ -143,5 +142,5 @@
- # we assume that the DNS server URI changed permanently and move on
- @uri = location_uri
- send_request(hostname, connection)
- return
- end
+ # we assume that the DNS server URI changed permanently and move on
+ @uri = location_uri
+ send_request(hostname, connection)
+ return
+ end
@@ -149 +148,2 @@
- parse(request, response)
+ parse(request, response)
+ end
lib/httpx/resolver/native.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/resolver/native.rb 2026-07-24 02:33:58.513369847 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/resolver/native.rb 2026-07-24 02:33:58.579369807 +0000
@@ -77,0 +78,7 @@
+ when :idle, :closed
+ return if @connections.empty?
+
+ transition(:idle) if @state == :closed
+ transition(:open)
+
+ consume if @state == :open
lib/httpx/resolver/resolver.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:58.513369847 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/resolver/resolver.rb 2026-07-24 02:33:58.580369806 +0000
@@ -54,0 +55,4 @@
+ def initial_call
+ call
+ end
+
lib/httpx/resolver/system.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/resolver/system.rb 2026-07-24 02:33:58.513369847 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/resolver/system.rb 2026-07-24 02:33:58.580369806 +0000
@@ -25,0 +26,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
@@ -230 +233 @@
- Timeout.timeout(resolve_timeout) do
+ Timeout.timeout(resolve_timeout, AddrinfoTimeoutError) do
@@ -249 +252 @@
- if e.is_a?(Timeout::Error)
+ if e.is_a?(AddrinfoTimeoutError)
lib/httpx/response.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/response.rb 2026-07-24 02:33:58.513369847 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/response.rb 2026-07-24 02:33:58.580369806 +0000
@@ -144 +144 @@
- # :nocov:
+ # simplecov:disable
@@ -152 +152 @@
- # :nocov:
+ # simplecov:enable
@@ -270 +269,0 @@
- include Loggable
@@ -293 +292 @@
- log_exception(@error)
+ @request.log_exception(@error)
lib/httpx/response/body.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/response/body.rb 2026-07-24 02:33:58.513369847 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/response/body.rb 2026-07-24 02:33:58.580369806 +0000
@@ -164 +164 @@
- # :nocov:
+ # simplecov:disable
@@ -170 +170 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/selector.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/selector.rb 2026-07-24 02:33:58.514369846 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/selector.rb 2026-07-24 02:33:58.580369806 +0000
@@ -43,0 +44,5 @@
+ # first time the registered selectables are added, there's probably work to do.
+ def initial_call
+ @selectables.each(&:initial_call)
+ end
+
lib/httpx/session.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/session.rb 2026-07-24 02:33:58.514369846 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/session.rb 2026-07-24 02:33:58.581369805 +0000
@@ -322 +322 @@
- responses = requests.each_with_index.map do |request, idx|
+ requests.each do |request|
@@ -323,0 +324,4 @@
+ end
+
+ # do work first
+ selector.initial_call
@@ -324,0 +329 @@
+ responses = requests.each_with_index.map do |request, idx|
lib/httpx/session_extensions.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/session_extensions.rb 2026-07-24 02:33:58.514369846 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/session_extensions.rb 2026-07-24 02:33:58.581369805 +0000
@@ -23 +23 @@
- # :nocov:
+ # simplecov:disable
@@ -29 +29 @@
- # :nocov:
+ # simplecov:enable
lib/httpx/timers.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/timers.rb 2026-07-24 02:33:58.514369846 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/timers.rb 2026-07-24 02:33:58.581369805 +0000
@@ -64,0 +65,3 @@
+ # simpler helper which allows classification
+ attr_accessor :label
+
lib/httpx/version.rb
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/lib/httpx/version.rb 2026-07-24 02:33:58.520369842 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/lib/httpx/version.rb 2026-07-24 02:33:58.583369804 +0000
@@ -4 +4 @@
- VERSION = "1.8.0"
+ VERSION = "1.8.1"
sig/connection.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/connection.rbs 2026-07-24 02:33:58.522369841 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/connection.rbs 2026-07-24 02:33:58.584369803 +0000
@@ -94,0 +95,2 @@
+ def initial_call: () -> void
+
@@ -125 +127 @@
- def on_io_error: (IOError error) -> void
+ def on_io_error: (SocketError | IOError | TLSError error) -> void
@@ -165,0 +168,2 @@
+
+ def no_more_requests?: () -> bool
sig/connection/http2.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/connection/http2.rbs 2026-07-24 02:33:58.522369841 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/connection/http2.rbs 2026-07-24 02:33:58.584369803 +0000
@@ -18,0 +19 @@
+ @streams_to_close_after_receive: Array[[HTTP2::Stream, Request, HTTPX::Error]]
@@ -107,0 +109,2 @@
+
+ def emit_stream_error: (HTTP2::Stream stream, Request request, StandardError error) -> void
sig/loggable.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/loggable.rbs 2026-07-24 02:33:58.523369841 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/loggable.rbs 2026-07-24 02:33:58.585369803 +0000
@@ -14,0 +15,2 @@
+ def self.log_identifiers: () -> String
+
@@ -17,0 +20,2 @@
+
+ private
sig/plugins/auth.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/plugins/auth.rbs 2026-07-24 02:33:58.524369840 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/plugins/auth.rbs 2026-07-24 02:33:58.586369802 +0000
@@ -9,0 +10,4 @@
+
+ def auth_header_expires_at: () -> (^(Request request) -> _ToF?)?
+
+ def auth_header_expires_in: () -> Float?
sig/plugins/persistent.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/plugins/persistent.rbs 2026-07-24 02:33:58.530369836 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/plugins/persistent.rbs 2026-07-24 02:33:58.597369796 +0000
@@ -8,0 +9,3 @@
+ private
+
+ def reconnectable_error?: (StandardError error) -> bool
sig/request.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/request.rbs 2026-07-24 02:33:58.534369834 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/request.rbs 2026-07-24 02:33:58.600369794 +0000
@@ -20 +20 @@
- attr_reader active_timeouts: Array[Symbol]
+ attr_reader active_timeouts: Array[Timers::Timer]
@@ -96,2 +96 @@
- def initialize_body: (Options options) -> Transcoder::_Encoder?
-
+ def reset_timers: (bool reset_total_request_timers) -> void
sig/resolver/system.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/resolver/system.rbs 2026-07-24 02:33:58.536369833 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/resolver/system.rbs 2026-07-24 02:33:58.602369793 +0000
@@ -7,0 +8,3 @@
+ class AddrinfoTimeoutError < StandardError
+ end
+
sig/selector.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/selector.rbs 2026-07-24 02:33:58.537369832 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/selector.rbs 2026-07-24 02:33:58.603369792 +0000
@@ -8,0 +9,2 @@
+ def initial_call: () -> void
+
sig/timers.rbs
--- /tmp/d20260724-2669-c3a09v/httpx-1.8.0/sig/timers.rbs 2026-07-24 02:33:58.538369831 +0000
+++ /tmp/d20260724-2669-c3a09v/httpx-1.8.1/sig/timers.rbs 2026-07-24 02:33:58.603369792 +0000
@@ -50,0 +51,2 @@
+ attr_accessor label: Symbol?
+ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps httpx from 1.8.0 to 1.8.1.
Commits
988e6c2bump version to 1.8.160b9b0bRevert "revert max retries conf"66ce00bchanged test of ssrf filter exception to remove mention of public/private (al...58aa9cdrevert max retries conf8b0fc4afixed the test fiber scheduler to accomodate the cases being tested31ab58aMerge branch 'fix-timers' into 'master'7e367b6temporarily patch fiber scheduler testsb6d72cddo not allow connection idle/closed transitions if there ain't no more requests549368efix simplecov conf v1 deprecationsac3c698correctly clearing timers across the request lifecycleDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)