http 5.3.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +241 -41
- data/LICENSE.txt +1 -1
- data/README.md +110 -13
- data/UPGRADING.md +491 -0
- data/http.gemspec +32 -29
- data/lib/http/base64.rb +11 -1
- data/lib/http/chainable/helpers.rb +62 -0
- data/lib/http/chainable/verbs.rb +136 -0
- data/lib/http/chainable.rb +232 -136
- data/lib/http/client.rb +158 -127
- data/lib/http/connection/internals.rb +141 -0
- data/lib/http/connection.rb +126 -97
- data/lib/http/content_type.rb +61 -6
- data/lib/http/errors.rb +25 -1
- data/lib/http/feature.rb +65 -5
- data/lib/http/features/auto_deflate.rb +124 -17
- data/lib/http/features/auto_inflate.rb +38 -15
- data/lib/http/features/caching/entry.rb +178 -0
- data/lib/http/features/caching/in_memory_store.rb +63 -0
- data/lib/http/features/caching.rb +216 -0
- data/lib/http/features/digest_auth.rb +234 -0
- data/lib/http/features/instrumentation.rb +97 -17
- data/lib/http/features/logging.rb +183 -5
- data/lib/http/features/normalize_uri.rb +17 -0
- data/lib/http/features/raise_error.rb +18 -3
- data/lib/http/form_data/composite_io.rb +106 -0
- data/lib/http/form_data/file.rb +95 -0
- data/lib/http/form_data/multipart/param.rb +62 -0
- data/lib/http/form_data/multipart.rb +106 -0
- data/lib/http/form_data/part.rb +52 -0
- data/lib/http/form_data/readable.rb +58 -0
- data/lib/http/form_data/urlencoded.rb +175 -0
- data/lib/http/form_data/version.rb +8 -0
- data/lib/http/form_data.rb +102 -0
- data/lib/http/headers/known.rb +3 -0
- data/lib/http/headers/normalizer.rb +17 -36
- data/lib/http/headers.rb +172 -65
- data/lib/http/mime_type/adapter.rb +24 -9
- data/lib/http/mime_type/json.rb +19 -4
- data/lib/http/mime_type.rb +21 -3
- data/lib/http/options/definitions.rb +189 -0
- data/lib/http/options.rb +172 -125
- data/lib/http/redirector.rb +80 -75
- data/lib/http/request/body.rb +87 -6
- data/lib/http/request/builder.rb +184 -0
- data/lib/http/request/proxy.rb +83 -0
- data/lib/http/request/writer.rb +76 -16
- data/lib/http/request.rb +214 -98
- data/lib/http/response/body.rb +103 -18
- data/lib/http/response/inflater.rb +35 -7
- data/lib/http/response/parser.rb +98 -4
- data/lib/http/response/status/reasons.rb +2 -4
- data/lib/http/response/status.rb +141 -31
- data/lib/http/response.rb +219 -61
- data/lib/http/retriable/delay_calculator.rb +38 -11
- data/lib/http/retriable/errors.rb +21 -0
- data/lib/http/retriable/performer.rb +82 -38
- data/lib/http/session.rb +280 -0
- data/lib/http/timeout/global.rb +147 -34
- data/lib/http/timeout/null.rb +155 -9
- data/lib/http/timeout/per_operation.rb +139 -18
- data/lib/http/uri/normalizer.rb +82 -0
- data/lib/http/uri/parsing.rb +182 -0
- data/lib/http/uri.rb +289 -124
- data/lib/http/version.rb +2 -1
- data/lib/http.rb +11 -2
- data/sig/deps.rbs +122 -0
- data/sig/http.rbs +1619 -0
- data/test/http/base64_test.rb +28 -0
- data/test/http/client_test.rb +739 -0
- data/test/http/connection_test.rb +1533 -0
- data/test/http/content_type_test.rb +190 -0
- data/test/http/errors_test.rb +28 -0
- data/test/http/feature_test.rb +49 -0
- data/test/http/features/auto_deflate_test.rb +317 -0
- data/test/http/features/auto_inflate_test.rb +213 -0
- data/test/http/features/caching_test.rb +942 -0
- data/test/http/features/digest_auth_test.rb +996 -0
- data/test/http/features/instrumentation_test.rb +246 -0
- data/test/http/features/logging_test.rb +654 -0
- data/test/http/features/normalize_uri_test.rb +41 -0
- data/test/http/features/raise_error_test.rb +77 -0
- data/test/http/form_data/composite_io_test.rb +215 -0
- data/test/http/form_data/file_test.rb +255 -0
- data/test/http/form_data/fixtures/the-http-gem.info +1 -0
- data/test/http/form_data/multipart_test.rb +303 -0
- data/test/http/form_data/part_test.rb +90 -0
- data/test/http/form_data/urlencoded_test.rb +164 -0
- data/test/http/form_data_test.rb +232 -0
- data/test/http/headers/normalizer_test.rb +93 -0
- data/test/http/headers_test.rb +888 -0
- data/test/http/mime_type/json_test.rb +39 -0
- data/test/http/mime_type_test.rb +150 -0
- data/test/http/options/base_uri_test.rb +148 -0
- data/test/http/options/body_test.rb +21 -0
- data/test/http/options/features_test.rb +38 -0
- data/test/http/options/form_test.rb +21 -0
- data/test/http/options/headers_test.rb +32 -0
- data/test/http/options/json_test.rb +21 -0
- data/test/http/options/merge_test.rb +78 -0
- data/test/http/options/new_test.rb +37 -0
- data/test/http/options/proxy_test.rb +32 -0
- data/test/http/options_test.rb +575 -0
- data/test/http/redirector_test.rb +639 -0
- data/test/http/request/body_test.rb +318 -0
- data/test/http/request/builder_test.rb +623 -0
- data/test/http/request/writer_test.rb +391 -0
- data/test/http/request_test.rb +1733 -0
- data/test/http/response/body_test.rb +292 -0
- data/test/http/response/parser_test.rb +105 -0
- data/test/http/response/status_test.rb +322 -0
- data/test/http/response_test.rb +502 -0
- data/test/http/retriable/delay_calculator_test.rb +194 -0
- data/test/http/retriable/errors_test.rb +71 -0
- data/test/http/retriable/performer_test.rb +551 -0
- data/test/http/session_test.rb +424 -0
- data/test/http/timeout/global_test.rb +239 -0
- data/test/http/timeout/null_test.rb +218 -0
- data/test/http/timeout/per_operation_test.rb +220 -0
- data/test/http/uri/normalizer_test.rb +89 -0
- data/test/http/uri_test.rb +1140 -0
- data/test/http/version_test.rb +15 -0
- data/test/http_test.rb +818 -0
- data/test/regression_tests.rb +27 -0
- data/test/support/dummy_server/encoding_routes.rb +47 -0
- data/test/support/dummy_server/routes.rb +201 -0
- data/test/support/dummy_server/servlet.rb +81 -0
- data/test/support/dummy_server.rb +200 -0
- data/{spec → test}/support/fakeio.rb +2 -2
- data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
- data/test/support/http_handling_shared/timeout_tests.rb +134 -0
- data/test/support/http_handling_shared.rb +11 -0
- data/test/support/proxy_server.rb +207 -0
- data/test/support/servers/runner.rb +67 -0
- data/{spec → test}/support/simplecov.rb +11 -2
- data/test/support/ssl_helper.rb +108 -0
- data/test/test_helper.rb +38 -0
- metadata +108 -168
- data/.github/workflows/ci.yml +0 -67
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.rubocop/layout.yml +0 -8
- data/.rubocop/metrics.yml +0 -4
- data/.rubocop/rspec.yml +0 -9
- data/.rubocop/style.yml +0 -32
- data/.rubocop.yml +0 -11
- data/.rubocop_todo.yml +0 -219
- data/.yardopts +0 -2
- data/CHANGES_OLD.md +0 -1002
- data/Gemfile +0 -51
- data/Guardfile +0 -18
- data/Rakefile +0 -64
- data/lib/http/headers/mixin.rb +0 -34
- data/lib/http/retriable/client.rb +0 -37
- data/logo.png +0 -0
- data/spec/lib/http/client_spec.rb +0 -556
- data/spec/lib/http/connection_spec.rb +0 -88
- data/spec/lib/http/content_type_spec.rb +0 -47
- data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
- data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
- data/spec/lib/http/features/instrumentation_spec.rb +0 -81
- data/spec/lib/http/features/logging_spec.rb +0 -65
- data/spec/lib/http/features/raise_error_spec.rb +0 -62
- data/spec/lib/http/headers/mixin_spec.rb +0 -36
- data/spec/lib/http/headers/normalizer_spec.rb +0 -52
- data/spec/lib/http/headers_spec.rb +0 -527
- data/spec/lib/http/options/body_spec.rb +0 -15
- data/spec/lib/http/options/features_spec.rb +0 -33
- data/spec/lib/http/options/form_spec.rb +0 -15
- data/spec/lib/http/options/headers_spec.rb +0 -24
- data/spec/lib/http/options/json_spec.rb +0 -15
- data/spec/lib/http/options/merge_spec.rb +0 -68
- data/spec/lib/http/options/new_spec.rb +0 -30
- data/spec/lib/http/options/proxy_spec.rb +0 -20
- data/spec/lib/http/options_spec.rb +0 -13
- data/spec/lib/http/redirector_spec.rb +0 -530
- data/spec/lib/http/request/body_spec.rb +0 -211
- data/spec/lib/http/request/writer_spec.rb +0 -121
- data/spec/lib/http/request_spec.rb +0 -234
- data/spec/lib/http/response/body_spec.rb +0 -85
- data/spec/lib/http/response/parser_spec.rb +0 -74
- data/spec/lib/http/response/status_spec.rb +0 -253
- data/spec/lib/http/response_spec.rb +0 -262
- data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
- data/spec/lib/http/retriable/performer_spec.rb +0 -302
- data/spec/lib/http/uri/normalizer_spec.rb +0 -95
- data/spec/lib/http/uri_spec.rb +0 -71
- data/spec/lib/http_spec.rb +0 -535
- data/spec/regression_specs.rb +0 -24
- data/spec/spec_helper.rb +0 -89
- data/spec/support/black_hole.rb +0 -13
- data/spec/support/dummy_server/servlet.rb +0 -203
- data/spec/support/dummy_server.rb +0 -44
- data/spec/support/fuubar.rb +0 -21
- data/spec/support/http_handling_shared.rb +0 -190
- data/spec/support/proxy_server.rb +0 -39
- data/spec/support/servers/config.rb +0 -11
- data/spec/support/servers/runner.rb +0 -19
- data/spec/support/ssl_helper.rb +0 -104
- /data/{spec → test}/support/capture_warning.rb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1567381d914309e80e272367711f0e26f48f0123730078e1cde3f6f1eb19447e
|
|
4
|
+
data.tar.gz: f8b6826b7a57470157a9caa3524bd89b77e3274ae69736f3983ad1e512ae8306
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 698b3d83287e492df7aced8106af2cd861b196c0691a484a007f8f3d56fff8bdaa278f3b3c860b851b4ec51e18b8f63d00b29242d8e1c7aa79ef590abc5f7ab3
|
|
7
|
+
data.tar.gz: b853190dabe880ee5232536f716b493e095f888c53a1fef3e7a598a05fce8864444096113de10f2d7e7ded74b08737bd2f50ac19788dd3c8a2b86e29bd6b6e78
|
data/CHANGELOG.md
CHANGED
|
@@ -5,63 +5,263 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## [5.3.1] - 2025-06-09
|
|
8
|
+
## [6.0.0] - 2026-03-16
|
|
12
9
|
|
|
13
10
|
### Changed
|
|
14
11
|
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
- Merged `http-form_data` gem into the main `http` gem. The `HTTP::FormData`
|
|
13
|
+
module (including `Part`, `File`, `Multipart`, `Urlencoded`, and `CompositeIO`)
|
|
14
|
+
is now shipped directly with `http` instead of being a separate dependency.
|
|
15
|
+
The public API is unchanged.
|
|
18
16
|
|
|
17
|
+
### Fixed
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
- `Inflater` no longer raises `Zlib::BufError` when a response declares
|
|
20
|
+
`Content-Encoding: gzip` (or deflate) but the body is not valid compressed
|
|
21
|
+
data. This commonly occurred when following redirects with `auto_inflate`
|
|
22
|
+
enabled, because the redirect response had a `Content-Encoding` header but a
|
|
23
|
+
non-compressed body. ([#621])
|
|
24
|
+
- Persistent connections now auto-flush unread response bodies before sending
|
|
25
|
+
the next request, instead of raising `StateError`. Bodies up to 1 MiB are
|
|
26
|
+
drained transparently; larger bodies cause the connection to close and reopen.
|
|
27
|
+
This prevents the silent body clobbering described in [#371], where an unread
|
|
28
|
+
response body would return `""` after a subsequent request. ([#371])
|
|
29
|
+
- `Response#content_length` now handles duplicate `Content-Length` headers per
|
|
30
|
+
RFC 7230 Section 3.3.2. When all values are identical, they are collapsed into
|
|
31
|
+
a single valid value. When values conflict, `nil` is returned instead of
|
|
32
|
+
raising `TypeError`. ([#566])
|
|
33
|
+
- HTTP 1xx informational responses (e.g. `100 Continue`) are now transparently
|
|
34
|
+
skipped, returning the final response. This was a regression introduced when
|
|
35
|
+
the parser was migrated from http-parser to llhttp. ([#667])
|
|
36
|
+
- Redirect loop detection now considers cookies, so a redirect back to the
|
|
37
|
+
same URL with different cookies is no longer falsely detected as an endless
|
|
38
|
+
loop. Fixes cookie-dependent redirect flows where a server sets a cookie on
|
|
39
|
+
one hop and expects it on the next. ([#544])
|
|
40
|
+
- Per-operation timeouts (`HTTP.timeout(read: n, write: n, connect: n)`) no
|
|
41
|
+
longer default unspecified values to 0.25 seconds. Omitted timeouts now mean
|
|
42
|
+
no timeout for that operation, matching the behavior when no timeout is
|
|
43
|
+
configured at all. ([#579])
|
|
44
|
+
- Per-operation timeout handler now correctly handles `:wait_writable` from
|
|
45
|
+
`read_nonblock` and `:wait_readable` from `write_nonblock` on SSL sockets
|
|
46
|
+
during TLS renegotiation. Previously these symbols were returned as data
|
|
47
|
+
instead of being waited on. ([#358])
|
|
48
|
+
- Persistent sessions now follow cross-origin redirects instead of raising
|
|
49
|
+
`StateError`. `HTTP.persistent` returns an `HTTP::Session` that pools one
|
|
50
|
+
`HTTP::Client` per origin, so redirects to a different domain transparently
|
|
51
|
+
open (and reuse) a separate persistent connection. Cookie management is
|
|
52
|
+
preserved across all hops. ([#557])
|
|
53
|
+
- Chaining configuration methods (`.headers`, `.auth`, `.cookies`, etc.) on a
|
|
54
|
+
persistent session no longer breaks connection reuse. Child sessions created
|
|
55
|
+
by chaining now share the parent's connection pool, so
|
|
56
|
+
`HTTP.persistent(host).headers(...).get(path)` reuses the same underlying
|
|
57
|
+
TCP connection across calls. ([#372])
|
|
21
58
|
|
|
22
|
-
###
|
|
59
|
+
### Changed
|
|
23
60
|
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
61
|
+
- **BREAKING** `HTTP.persistent` now returns an `HTTP::Session` instead of an
|
|
62
|
+
`HTTP::Client`. The session pools persistent clients per origin and exposes
|
|
63
|
+
the same chainable API (`get`, `post`, `headers`, `follow`, etc.) plus a
|
|
64
|
+
`close` method that shuts down all pooled connections. Code that called
|
|
65
|
+
`HTTP::Client`-only methods on the return value will need updating. ([#557])
|
|
66
|
+
- **BREAKING** Convert options hash parameters to explicit keyword arguments
|
|
67
|
+
across the public API. Methods like `HTTP.get(url, body: "data")` continue to
|
|
68
|
+
work, but passing an explicit hash (e.g., `HTTP.get(url, {body: "data"})`) is
|
|
69
|
+
no longer supported, and unrecognized keyword arguments now raise
|
|
70
|
+
`ArgumentError`. Affected methods: all HTTP verb methods (`get`, `post`,
|
|
71
|
+
etc.), `request`, `follow`, `retriable`, `URI.new`, `Request.new`,
|
|
72
|
+
`Response.new`, `Redirector.new`, `Retriable::Performer.new`,
|
|
73
|
+
`Retriable::DelayCalculator.new`, and `Timeout::Null.new` (and subclasses).
|
|
74
|
+
`HTTP::URI.new` also no longer accepts `Addressable::URI` objects.
|
|
75
|
+
- **BREAKING** `addressable` is no longer a runtime dependency. It is now
|
|
76
|
+
lazy-loaded only when parsing non-ASCII (IRI) URIs or normalizing
|
|
77
|
+
internationalized hostnames. Install the `addressable` gem if you need
|
|
78
|
+
non-ASCII URI support. ASCII-only URIs use Ruby's stdlib `URI` parser
|
|
79
|
+
exclusively.
|
|
80
|
+
- **BREAKING** Extract request building into `HTTP::Request::Builder`. The
|
|
81
|
+
`build_request` method has been removed from `Client`, `Session`, and the
|
|
82
|
+
top-level `HTTP` module. Use `HTTP::Request::Builder.new(options).build(verb, uri)`
|
|
83
|
+
to construct requests without executing them.
|
|
27
84
|
|
|
28
|
-
###
|
|
85
|
+
### Added
|
|
29
86
|
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
|
|
87
|
+
- Block form for verb methods and `request` that auto-closes the connection
|
|
88
|
+
after the block returns. `HTTP.get(url) { |response| response.status }` yields
|
|
89
|
+
the response, closes the underlying connection, and returns the block's value.
|
|
90
|
+
Works with all verb methods and chained options. ([#270])
|
|
91
|
+
- HTTP caching feature (`HTTP.use(:caching)`) that stores and reuses responses
|
|
92
|
+
according to RFC 7234. Supports `Cache-Control` (`max-age`, `no-cache`,
|
|
93
|
+
`no-store`), `Expires`, `ETag` / `If-None-Match`, and
|
|
94
|
+
`Last-Modified` / `If-Modified-Since` for freshness checks and conditional
|
|
95
|
+
revalidation. Ships with a default in-memory store; custom stores can be
|
|
96
|
+
passed via `store:` option. Only GET and HEAD responses are cached. ([#223])
|
|
97
|
+
- `HTTP.digest_auth(user:, pass:)` for HTTP Digest Authentication (RFC 2617 /
|
|
98
|
+
RFC 7616). Automatically handles 401 challenges with digest credentials,
|
|
99
|
+
supporting MD5, SHA-256, MD5-sess, and SHA-256-sess algorithms with
|
|
100
|
+
quality-of-protection negotiation. Works as a chainable feature:
|
|
101
|
+
`HTTP.digest_auth(user: "admin", pass: "secret").get(url)` ([#448])
|
|
102
|
+
- Happy Eyeballs (RFC 8305) support via Ruby 3.4's native `TCPSocket`
|
|
103
|
+
implementation. Connection attempts now try multiple addresses (IPv6 and
|
|
104
|
+
IPv4) concurrently, improving reliability on dual-stack networks. Connect
|
|
105
|
+
timeouts are passed natively to `TCPSocket` instead of using
|
|
106
|
+
`Timeout.timeout`, avoiding `Thread.raise` interference with the Happy
|
|
107
|
+
Eyeballs state machine. ([#739])
|
|
108
|
+
- `HTTP.base_uri` for setting a base URI that resolves relative request paths
|
|
109
|
+
per RFC 3986. Supports chaining (`HTTP.base_uri("https://api.example.com/v1")
|
|
110
|
+
.get("users")`), and integrates with `persistent` connections by deriving the
|
|
111
|
+
host when omitted ([#519], [#512], [#493])
|
|
112
|
+
- `Request::Body#loggable?` and `Response::Body#loggable?` predicates, and a
|
|
113
|
+
`binary_formatter` option for the logging feature. Binary bodies
|
|
114
|
+
(IO/Enumerable request sources, binary-encoded request strings, and
|
|
115
|
+
binary-encoded responses) are now formatted instead of dumped raw,
|
|
116
|
+
preventing unreadable log output when transferring files like images or
|
|
117
|
+
audio. Available formatters: `:stats` (default, logs byte count),
|
|
118
|
+
`:base64` (logs base64-encoded content), or a custom `Proc`. Invalid
|
|
119
|
+
formatter values raise `ArgumentError` ([#784])
|
|
120
|
+
- `Feature#on_request` and `Feature#around_request` lifecycle hooks, called
|
|
121
|
+
before/around each request attempt (including retries), for per-attempt side
|
|
122
|
+
effects like instrumentation spans and circuit breakers ([#826])
|
|
123
|
+
- Pattern matching support (`deconstruct_keys`) for Response, Response::Status,
|
|
124
|
+
Headers, ContentType, and URI ([#642])
|
|
125
|
+
- Combined global and per-operation timeouts: global and per-operation timeouts
|
|
126
|
+
are no longer mutually exclusive. Use
|
|
127
|
+
`HTTP.timeout(global: 60, read: 30, write: 30, connect: 5)` to set both a
|
|
128
|
+
global request timeout and individual operation limits ([#773])
|
|
33
129
|
|
|
130
|
+
### Fixed
|
|
34
131
|
|
|
35
|
-
|
|
132
|
+
- `HTTP::URI.form_encode` now encodes newlines as `%0A` instead of
|
|
133
|
+
`%0D%0A` ([#449])
|
|
134
|
+
- Thread-safety: `Headers::Normalizer` cache is now per-thread via
|
|
135
|
+
`Thread.current`, eliminating a potential race condition when multiple
|
|
136
|
+
threads share a normalizer instance
|
|
137
|
+
- Instrumentation feature now correctly starts a new span for each retry
|
|
138
|
+
attempt, fixing `NoMethodError` with `ActiveSupport::Notifications` when
|
|
139
|
+
using `.retriable` with the instrumentation feature ([#826])
|
|
140
|
+
- Raise `HTTP::URI::InvalidError` for malformed or schemeless URIs and
|
|
141
|
+
`ArgumentError` for nil or empty URIs, instead of confusing
|
|
142
|
+
`UnsupportedSchemeError` or `Addressable::URI::InvalidURIError` ([#565])
|
|
143
|
+
- Strip `Authorization` and `Cookie` headers when following redirects to a
|
|
144
|
+
different origin (scheme, host, or port) to prevent credential leakage
|
|
145
|
+
([#516], [#770])
|
|
146
|
+
- AutoInflate now preserves the response charset encoding instead of
|
|
147
|
+
defaulting to `Encoding::BINARY` ([#535])
|
|
148
|
+
- `LocalJumpError` when using instrumentation with instrumenters that
|
|
149
|
+
unconditionally yield in `#instrument` (e.g., `ActiveSupport::Notifications`)
|
|
150
|
+
([#673])
|
|
151
|
+
- Logging feature no longer eagerly consumes the response body at debug level;
|
|
152
|
+
body chunks are now logged as they are streamed, preserving
|
|
153
|
+
`response.body.each` ([#785])
|
|
36
154
|
|
|
37
|
-
###
|
|
155
|
+
### Removed
|
|
38
156
|
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
157
|
+
- `HTTP::URI` setter methods (`scheme=`, `user=`, `password=`, `authority=`,
|
|
158
|
+
`origin=`, `port=`, `request_uri=`, `fragment=`) and normalized accessors
|
|
159
|
+
(`normalized_user`, `normalized_password`, `normalized_port`,
|
|
160
|
+
`normalized_path`, `normalized_query`) that were delegated to
|
|
161
|
+
`Addressable::URI` but never used internally
|
|
162
|
+
- `HTTP::URI#origin` is no longer delegated to `Addressable::URI`. The new
|
|
163
|
+
implementation follows RFC 6454, normalizing scheme and host to lowercase
|
|
164
|
+
and excluding user info from the origin string
|
|
165
|
+
- `HTTP::URI#request_uri` is no longer delegated to `Addressable::URI`
|
|
166
|
+
- `HTTP::URI#omit` is no longer delegated to `Addressable::URI` and now
|
|
167
|
+
returns `HTTP::URI` instead of `Addressable::URI` ([#491])
|
|
168
|
+
- `HTTP::URI#query_values` and `HTTP::URI#query_values=` delegations to
|
|
169
|
+
`Addressable::URI`. Query parameter merging now uses stdlib
|
|
170
|
+
`URI.decode_www_form`/`URI.encode_www_form`
|
|
171
|
+
- `HTTP::URI` delegations for `normalized_scheme`, `normalized_authority`,
|
|
172
|
+
`normalized_fragment`, and `authority` to `Addressable::URI`. The URI
|
|
173
|
+
normalizer now inlines these operations directly
|
|
174
|
+
- `HTTP::URI#join` is no longer delegated to `Addressable::URI` and now
|
|
175
|
+
returns `HTTP::URI` instead of `Addressable::URI`. Uses stdlib `URI.join`
|
|
176
|
+
with automatic percent-encoding of non-ASCII characters ([#491])
|
|
177
|
+
- `HTTP::URI.form_encode` no longer delegates to `Addressable::URI`. Uses
|
|
178
|
+
stdlib `URI.encode_www_form` instead
|
|
48
179
|
|
|
49
180
|
### Changed
|
|
50
181
|
|
|
51
|
-
- **BREAKING**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
182
|
+
- **BREAKING** `HTTP::Response::Status` no longer inherits from `Delegator`.
|
|
183
|
+
It now uses `Comparable` and `Forwardable` instead, providing `to_i`,
|
|
184
|
+
`to_int`, and `<=>` for numeric comparisons and range matching. Code that
|
|
185
|
+
called `__getobj__`/`__setobj__` or relied on implicit delegation of
|
|
186
|
+
arbitrary `Integer` methods (e.g., `status.even?`) will need to be updated
|
|
187
|
+
to use `status.code` instead
|
|
188
|
+
- **BREAKING** Chainable option methods (`.headers`, `.timeout`, `.cookies`,
|
|
189
|
+
`.auth`, `.follow`, `.via`, `.use`, `.encoding`, `.nodelay`, `.basic_auth`,
|
|
190
|
+
`.accept`) now return a thread-safe `HTTP::Session` instead of `HTTP::Client`.
|
|
191
|
+
`Session` creates a new `Client` for each request, making it safe to share a
|
|
192
|
+
configured session across threads. `HTTP.persistent` still returns
|
|
193
|
+
`HTTP::Client` since persistent connections require mutable state. Code that
|
|
194
|
+
calls HTTP verb methods (`.get`, `.post`, etc.) or accesses `.default_options`
|
|
195
|
+
is unaffected. Code that checks `is_a?(HTTP::Client)` on the return value of
|
|
196
|
+
chainable methods will need to be updated to check for `HTTP::Session`
|
|
197
|
+
- **BREAKING** `.retriable` now returns `HTTP::Session` instead of
|
|
198
|
+
`HTTP::Retriable::Client`. Retry is a session-level option: it flows through
|
|
199
|
+
`HTTP::Options` into `HTTP::Client#perform`, eliminating the need for
|
|
200
|
+
separate `Retriable::Client` and `Retriable::Session` classes
|
|
201
|
+
- Improved error message when request body size cannot be determined to suggest
|
|
202
|
+
setting `Content-Length` explicitly or using chunked `Transfer-Encoding` ([#560])
|
|
203
|
+
- **BREAKING** `Connection#readpartial` now raises `EOFError` instead of
|
|
204
|
+
returning `nil` at end-of-stream, and supports an `outbuf` parameter,
|
|
205
|
+
conforming to the `IO#readpartial` API. `Body#readpartial` and
|
|
206
|
+
`Inflater#readpartial` also raise `EOFError` ([#618])
|
|
207
|
+
- **BREAKING** Stricter timeout options parsing: `.timeout()` with a Hash now
|
|
208
|
+
rejects unknown keys, non-numeric values, string keys, and empty hashes ([#754])
|
|
209
|
+
- Bumped min llhttp dependency version
|
|
210
|
+
- **BREAKING** Handle responses in the reverse order from the requests ([#776])
|
|
211
|
+
- **BREAKING** `Response#cookies` now returns `Array<HTTP::Cookie>` instead of
|
|
212
|
+
`HTTP::CookieJar`. The `cookies` option has been removed from `Options`;
|
|
213
|
+
`Chainable#cookies` now sets the `Cookie` header directly with no implicit
|
|
214
|
+
merging — the last `.cookies()` call wins ([#536])
|
|
215
|
+
- Cookie jar management during redirects moved from `Redirector` to `Session`.
|
|
216
|
+
`Redirector` is now a pure redirect-following engine with no cookie
|
|
217
|
+
awareness; `Session#request` manages cookies across redirect hops
|
|
218
|
+
- **BREAKING** `HTTP::Options.new`, `HTTP::Client.new`, and `HTTP::Session.new`
|
|
219
|
+
now accept keyword arguments instead of an options hash. For example,
|
|
220
|
+
`HTTP::Options.new(response: :body)` continues to work, but
|
|
221
|
+
`HTTP::Options.new({response: :body})` must be updated to
|
|
222
|
+
`HTTP::Options.new(**options)`. Invalid option names now raise
|
|
223
|
+
`ArgumentError` automatically ([#447])
|
|
57
224
|
|
|
58
|
-
###
|
|
225
|
+
### Removed
|
|
59
226
|
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
([#
|
|
227
|
+
- **BREAKING** Drop Ruby 2.x support
|
|
228
|
+
- **BREAKING** Remove `Headers::Mixin` and the `[]`/`[]=` delegators on
|
|
229
|
+
`Request` and `Response`. Use `request.headers["..."]` and
|
|
230
|
+
`response.headers["..."]` instead ([#537])
|
|
64
231
|
|
|
65
|
-
[
|
|
66
|
-
[
|
|
67
|
-
[
|
|
232
|
+
[#270]: https://github.com/httprb/http/issues/270
|
|
233
|
+
[#223]: https://github.com/httprb/http/issues/223
|
|
234
|
+
[#358]: https://github.com/httprb/http/issues/358
|
|
235
|
+
[#371]: https://github.com/httprb/http/issues/371
|
|
236
|
+
[#372]: https://github.com/httprb/http/issues/372
|
|
237
|
+
[#447]: https://github.com/httprb/http/issues/447
|
|
238
|
+
[#448]: https://github.com/httprb/http/issues/448
|
|
239
|
+
[#449]: https://github.com/httprb/http/issues/449
|
|
240
|
+
[#491]: https://github.com/httprb/http/issues/491
|
|
241
|
+
[#493]: https://github.com/httprb/http/pull/493
|
|
242
|
+
[#512]: https://github.com/httprb/http/issues/512
|
|
243
|
+
[#516]: https://github.com/httprb/http/issues/516
|
|
244
|
+
[#519]: https://github.com/httprb/http/issues/519
|
|
245
|
+
[#535]: https://github.com/httprb/http/issues/535
|
|
246
|
+
[#536]: https://github.com/httprb/http/issues/536
|
|
247
|
+
[#537]: https://github.com/httprb/http/issues/537
|
|
248
|
+
[#544]: https://github.com/httprb/http/issues/544
|
|
249
|
+
[#557]: https://github.com/httprb/http/issues/557
|
|
250
|
+
[#560]: https://github.com/httprb/http/pull/560
|
|
251
|
+
[#565]: https://github.com/httprb/http/issues/565
|
|
252
|
+
[#566]: https://github.com/httprb/http/issues/566
|
|
253
|
+
[#579]: https://github.com/httprb/http/issues/579
|
|
254
|
+
[#618]: https://github.com/httprb/http/pull/618
|
|
255
|
+
[#621]: https://github.com/httprb/http/issues/621
|
|
256
|
+
[#642]: https://github.com/httprb/http/issues/642
|
|
257
|
+
[#667]: https://github.com/httprb/http/issues/667
|
|
258
|
+
[#673]: https://github.com/httprb/http/issues/673
|
|
259
|
+
[#739]: https://github.com/httprb/http/issues/739
|
|
260
|
+
[#754]: https://github.com/httprb/http/pull/754
|
|
261
|
+
[#770]: https://github.com/httprb/http/issues/770
|
|
262
|
+
[#773]: https://github.com/httprb/http/issues/773
|
|
263
|
+
[#776]: https://github.com/httprb/http/issues/776
|
|
264
|
+
[#784]: https://github.com/httprb/http/issues/784
|
|
265
|
+
[#785]: https://github.com/httprb/http/issues/785
|
|
266
|
+
[#826]: https://github.com/httprb/http/issues/826
|
|
267
|
+
[unreleased]: https://github.com/httprb/http/compare/v5.3.0...main
|
data/LICENSE.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2011-
|
|
1
|
+
Copyright (c) 2011-2026 Tony Arcieri, Erik Berlin, Alexey V. Zapparov, Zachary Anker
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
4
|
a copy of this software and associated documentation files (the
|
data/README.md
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[![Gem Version][gem-image]][gem-link]
|
|
4
4
|
[![MIT licensed][license-image]][license-link]
|
|
5
|
-
[![
|
|
6
|
-
[![
|
|
5
|
+
[![Docs][docs-image]][docs-link]
|
|
6
|
+
[![Lint][lint-image]][lint-link]
|
|
7
|
+
[![Mutant][mutant-image]][mutant-link]
|
|
8
|
+
[![Test][test-image]][test-link]
|
|
9
|
+
[![Typecheck][typecheck-image]][typecheck-link]
|
|
7
10
|
|
|
8
11
|
[Documentation]
|
|
9
12
|
|
|
@@ -105,18 +108,91 @@ and call `#readpartial` on it repeatedly until it returns `nil`:
|
|
|
105
108
|
=> nil
|
|
106
109
|
```
|
|
107
110
|
|
|
111
|
+
### Pattern Matching
|
|
112
|
+
|
|
113
|
+
Response objects support Ruby's pattern matching:
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
case HTTP.get("https://api.example.com/users")
|
|
117
|
+
in { status: 200..299, body: body }
|
|
118
|
+
JSON.parse(body.to_s)
|
|
119
|
+
in { status: 404 }
|
|
120
|
+
nil
|
|
121
|
+
in { status: 400.. }
|
|
122
|
+
raise "request failed"
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Pattern matching is also supported on `HTTP::Response::Status`, `HTTP::Headers`,
|
|
127
|
+
`HTTP::ContentType`, and `HTTP::URI`.
|
|
128
|
+
|
|
129
|
+
### Base URI
|
|
130
|
+
|
|
131
|
+
Set a base URI to avoid repeating the scheme and host in every request:
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
api = HTTP.base_uri("https://api.example.com/v1")
|
|
135
|
+
api.get("users") # GET https://api.example.com/v1/users
|
|
136
|
+
api.get("users/1") # GET https://api.example.com/v1/users/1
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Relative paths are resolved per [RFC 3986](https://www.rfc-editor.org/rfc/rfc3986#section-5).
|
|
140
|
+
Combine with `persistent` to reuse the connection:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
HTTP.base_uri("https://api.example.com/v1").persistent do |http|
|
|
144
|
+
http.get("users")
|
|
145
|
+
http.get("posts")
|
|
146
|
+
end
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Thread Safety
|
|
150
|
+
|
|
151
|
+
Configured sessions are safe to share across threads:
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
# Build a session once, use it from any thread
|
|
155
|
+
session = HTTP.headers("Accept" => "application/json")
|
|
156
|
+
.timeout(10)
|
|
157
|
+
.auth("Bearer token")
|
|
158
|
+
|
|
159
|
+
threads = 10.times.map do
|
|
160
|
+
Thread.new { session.get("https://example.com/api/data") }
|
|
161
|
+
end
|
|
162
|
+
threads.each(&:join)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Chainable configuration methods (`.headers`, `.timeout`, `.auth`, etc.) return
|
|
166
|
+
an `HTTP::Session`, which creates a fresh `HTTP::Client` for every request.
|
|
167
|
+
|
|
168
|
+
Persistent connections (`HTTP.persistent`) return an `HTTP::Session` that pools
|
|
169
|
+
one `HTTP::Client` per origin. The session itself is **not** thread-safe. For
|
|
170
|
+
thread-safe persistent connections, use the
|
|
171
|
+
[connection_pool](https://rubygems.org/gems/connection_pool) gem:
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
pool = ConnectionPool.new(size: 5) { HTTP.persistent("https://example.com") }
|
|
175
|
+
pool.with { |http| http.get("/path") }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Cross-origin redirects are handled transparently — the session opens a separate
|
|
179
|
+
persistent connection for each origin encountered during a redirect chain:
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
HTTP.persistent("https://example.com").follow do |http|
|
|
183
|
+
http.get("/moved-to-other-domain") # follows redirect across origins
|
|
184
|
+
end
|
|
185
|
+
```
|
|
186
|
+
|
|
108
187
|
## Supported Ruby Versions
|
|
109
188
|
|
|
110
189
|
This library aims to support and is [tested against][build-link]
|
|
111
190
|
the following Ruby versions:
|
|
112
191
|
|
|
113
|
-
- JRuby 9.3
|
|
114
|
-
- Ruby 2.6
|
|
115
|
-
- Ruby 2.7
|
|
116
|
-
- Ruby 3.0
|
|
117
|
-
- Ruby 3.1
|
|
118
192
|
- Ruby 3.2
|
|
119
193
|
- Ruby 3.3
|
|
194
|
+
- Ruby 3.4
|
|
195
|
+
- Ruby 4.0
|
|
120
196
|
|
|
121
197
|
If something doesn't work on one of these versions, it's a bug.
|
|
122
198
|
|
|
@@ -132,8 +208,20 @@ exist at the time of a major release, support for that Ruby version may be
|
|
|
132
208
|
dropped.
|
|
133
209
|
|
|
134
210
|
|
|
211
|
+
## Upgrading
|
|
212
|
+
|
|
213
|
+
See [UPGRADING.md] for a detailed migration guide between major versions.
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
## Security
|
|
217
|
+
|
|
218
|
+
See [SECURITY.md] for reporting vulnerabilities.
|
|
219
|
+
|
|
220
|
+
|
|
135
221
|
## Contributing to http.rb
|
|
136
222
|
|
|
223
|
+
See [CONTRIBUTING.md] for guidelines, or the quick version:
|
|
224
|
+
|
|
137
225
|
- Fork http.rb on GitHub
|
|
138
226
|
- Make your changes
|
|
139
227
|
- Ensure all tests pass (`bundle exec rake`)
|
|
@@ -144,7 +232,7 @@ dropped.
|
|
|
144
232
|
|
|
145
233
|
## Copyright
|
|
146
234
|
|
|
147
|
-
Copyright © 2011-
|
|
235
|
+
Copyright © 2011-2026 Tony Arcieri, Erik Berlin, Alexey V. Zapparov, Zachary Anker.
|
|
148
236
|
See LICENSE.txt for further details.
|
|
149
237
|
|
|
150
238
|
|
|
@@ -154,13 +242,22 @@ See LICENSE.txt for further details.
|
|
|
154
242
|
[gem-link]: https://rubygems.org/gems/http
|
|
155
243
|
[license-image]: https://img.shields.io/badge/license-MIT-blue.svg
|
|
156
244
|
[license-link]: https://github.com/httprb/http/blob/main/LICENSE.txt
|
|
157
|
-
[
|
|
158
|
-
[
|
|
159
|
-
[
|
|
160
|
-
[
|
|
245
|
+
[docs-image]: https://github.com/httprb/http/actions/workflows/docs.yml/badge.svg
|
|
246
|
+
[docs-link]: https://github.com/httprb/http/actions/workflows/docs.yml
|
|
247
|
+
[lint-image]: https://github.com/httprb/http/actions/workflows/lint.yml/badge.svg
|
|
248
|
+
[lint-link]: https://github.com/httprb/http/actions/workflows/lint.yml
|
|
249
|
+
[mutant-image]: https://github.com/httprb/http/actions/workflows/mutant.yml/badge.svg
|
|
250
|
+
[mutant-link]: https://github.com/httprb/http/actions/workflows/mutant.yml
|
|
251
|
+
[test-image]: https://github.com/httprb/http/actions/workflows/test.yml/badge.svg
|
|
252
|
+
[test-link]: https://github.com/httprb/http/actions/workflows/test.yml
|
|
253
|
+
[typecheck-image]: https://github.com/httprb/http/actions/workflows/typecheck.yml/badge.svg
|
|
254
|
+
[typecheck-link]: https://github.com/httprb/http/actions/workflows/typecheck.yml
|
|
161
255
|
|
|
162
256
|
[//]: # (links)
|
|
163
257
|
|
|
258
|
+
[contributing.md]: https://github.com/httprb/http/blob/main/CONTRIBUTING.md
|
|
164
259
|
[documentation]: https://github.com/httprb/http/wiki
|
|
165
|
-
[requests]: https://docs.python-requests.org/en/latest/
|
|
166
260
|
[llhttp]: https://llhttp.org/
|
|
261
|
+
[requests]: https://docs.python-requests.org/en/latest/
|
|
262
|
+
[security.md]: https://github.com/httprb/http/blob/main/SECURITY.md
|
|
263
|
+
[upgrading.md]: https://github.com/httprb/http/blob/main/UPGRADING.md
|