rack-proxy 0.7.7 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 888784aa8d1d28ae0dc2a1352aa44ba8e639d5cd604043facbb31da3fa1dc759
4
- data.tar.gz: 9ba49effcffcacb930ab08fe2f6a9fd08040b60800b8aa8e5ccc274053f36c4e
3
+ metadata.gz: 12583aa295312c50b4133259be96749c8cb515eca735f3df803008970f5f941a
4
+ data.tar.gz: 765f25cc8fef13acb7b0276ed7d193d35c3ad91acc00074b923b2f1558e384d8
5
5
  SHA512:
6
- metadata.gz: 606ed720fb5b8c67cd1fc3058b9644e88fb2e7768d4fce4606ba0332fac24cadca11a36ab50d97cb7ff5767664864b1c1a2cf5108cd58a66fecfb3b93de37517
7
- data.tar.gz: a91cc8541d7af6c390fe1c0faa3c923942a14cce746eebc3d170b95b45aafc5871a04ad1ec9fee6f0c07500534755c794f76d0c14bccdcf5fdaad06e239aeb07
6
+ metadata.gz: 2f6467276179125820219ff0f553f216dced29a36d0a14e60d03ab5e86e49b06ab601f47f25bbc5aa180cb11be9358a3689137fbe7ff6c6190626d171b80ab92
7
+ data.tar.gz: e8f825b48982e015dedb923dc6bd21c7d7144ec991b9c8e24a65c2d9755daec0bc86df9519c045c9d8689bb0b1c4693966b609a66d6958d77edfd1b4fe016227
data/CHANGELOG.md ADDED
@@ -0,0 +1,259 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project aims to
5
+ follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ Nothing yet.
10
+
11
+ ## [2.0.1] - 2026-09-16
12
+
13
+ ### Fixed
14
+
15
+ - The bounded request body stream accepts `IO#read`'s optional `length`
16
+ argument. Net::HTTP instrumentation layers that read the whole request body
17
+ at once (WebMock's adapter, for example) raised `ArgumentError` against
18
+ 2.0.0, failing the test suite of any app that proxies a request body. (#145)
19
+
20
+ ## [2.0.0] - 2026-09-05
21
+
22
+ ### Breaking changes
23
+
24
+ - Non-streaming requests no longer automatically retry transport failures.
25
+ This prevents replay with consumed request input; applications that require
26
+ retries must implement them with a fresh body and an explicit retry policy.
27
+ - Rack 3 response hooks receive arrays for repeated header values, including
28
+ `Set-Cookie`, and non-streaming statuses are integers. Update hooks that
29
+ assumed newline-separated headers or string statuses. Rack 2 retains its
30
+ newline-separated header representation.
31
+ - Invalid or ambiguous HTTP framing is now rejected, incomplete responses fail,
32
+ and uploads without a known length use fresh chunked framing. Backends must
33
+ accept properly framed HTTP/1.1 requests and send valid, complete responses.
34
+
35
+ ### Security
36
+
37
+ - Reframe decoded request bodies without a `CONTENT_LENGTH` using chunked
38
+ encoding instead of sending body bytes after `Content-Length: 0`. Bound
39
+ known-length input streams so excess bytes cannot become another backend
40
+ request; malformed lengths and prematurely ended uploads return `400`.
41
+ - Reject ambiguous backend framing (`Transfer-Encoding` with `Content-Length`,
42
+ conflicting or invalid lengths, and unsupported transfer codings) with `502`.
43
+ - Strip response headers named by the backend's `Connection` fields as well as
44
+ the standard hop-by-hop headers.
45
+ - Enforce `max_response_length` before buffering each chunk in non-streaming
46
+ mode, including rejecting declared oversized responses before reading them.
47
+ - Detect premature EOF in fixed-length responses: return `502` before sending
48
+ headers, or raise while streaming so the server aborts the incomplete transfer.
49
+ - Disable Net::HTTP transport retries in non-streaming mode as well as streaming
50
+ mode, preventing replay with an already-consumed request body.
51
+
52
+ ### Fixed
53
+
54
+ - Return integer statuses in non-streaming mode and preserve multiple response
55
+ header values as arrays on Rack 3 (including `Set-Cookie`). Rack 2 keeps its
56
+ newline-separated representation.
57
+ - Remove entity headers forbidden by Rack on 1xx/204/304 responses. HEAD and
58
+ 304 representation sizes no longer incorrectly trigger the response body cap.
59
+ - Replace a remaining live-host test with a local fixture and simulate failed
60
+ DNS resolution without sending external DNS queries. Add offline adversarial
61
+ framing, size-limit, retry, and `Rack::Lint` regression checks.
62
+
63
+ ## [1.0.2] - 2026-09-01
64
+
65
+ Housekeeping — no library behavior changes. **No action is needed by users:**
66
+ the shipped gem does not depend on `json` and was never affected by the
67
+ advisory below.
68
+
69
+ ### Security
70
+
71
+ - Development dependency `json` bumped 2.21.1 → 2.21.2 to clear
72
+ CVE-2026-71847 / GHSA-9hj4-r449-hfvc (`JSON::ResumableParser#partial_value`
73
+ dereferences a freed input buffer on truncated duplicate-key streams).
74
+ `json` reaches this repo only transitively (`standard` → `rubocop` → `json`)
75
+ and lives solely in the development `Gemfile.lock`; the bump keeps the CI
76
+ `bundler-audit` gate green.
77
+
78
+ ### Changed
79
+
80
+ - Release workflow: the laggy rubygems full-index await was replaced with a
81
+ versions-API check, so a successful publish no longer fails the run. (#142)
82
+
83
+ ## [1.0.1] - 2026-07-23
84
+
85
+ Docs and housekeeping — no library behavior changes.
86
+
87
+ ### Changed
88
+
89
+ - README modernized: badges, quick start, a "How it works" pipeline overview,
90
+ grouped options, and tightened recipes.
91
+ - Removed the internal modernization roadmap document, completed by 1.0.0.
92
+ - Development dependencies refreshed (rake 13.4.2, test-unit 3.7.8,
93
+ rack-test 2.2.0) and CI bumped to `actions/checkout@v7`. (#136–#139)
94
+
95
+ ## [1.0.0] - 2026-07-18
96
+
97
+ The 2026 modernization + security-hardening release. From 1.0.0 on this
98
+ project follows SemVer strictly: breaking changes only in majors.
99
+
100
+ ### Breaking changes
101
+
102
+ Read this list before upgrading from 0.8.x; everything else below is additive
103
+ or a compatible fix. See the README's "Upgrading" section for migration steps.
104
+
105
+ - **Host-derived (dynamic) backends are refused by default.** With no
106
+ `:backend` and no `env["rack.backend"]`, requests now get `502` unless you
107
+ pass `allow_dynamic_backend: true`. A bare `Rack::Proxy.new` is no longer an
108
+ open proxy. Combine the opt-in with a `backend_allowed?` allowlist.
109
+ - **`net_http_hacked` is gone** — the file, `require "net_http_hacked"`, and
110
+ the `begin_request_hacked`/`end_request_hacked` methods (see Removed).
111
+ - **The bundled examples left the gem** — `require "rack_proxy_examples/..."`
112
+ raises `LoadError`; copy the snippets from `examples/` instead (see Removed).
113
+ - **Backend failures no longer raise.** `OpenSSL::SSL::SSLError`, `EOFError`,
114
+ timeouts, resets, and malformed backend responses now become a `502` triplet
115
+ instead of an exception — `rescue`-based error handling around `proxy.call`
116
+ must inspect the status instead.
117
+ - **Hop-by-hop request headers are no longer forwarded** (`Connection`, `TE`,
118
+ `Transfer-Encoding`, `Proxy-Authorization`, `Upgrade`, anything named by
119
+ `Connection`).
120
+ - **gzip backend bodies are forwarded verbatim in `streaming: false` mode**
121
+ (previously they were transparently inflated); `rewrite_response` hooks that
122
+ read body text must inflate it themselves.
123
+ - **Supported runtimes: Ruby >= 3.0 and Rack >= 2.0, < 4** (was Ruby >= 2.6,
124
+ rack unpinned).
125
+ - Smaller wire/API changes: body-less POST/PUT sends `Content-Length: 0` on
126
+ the streaming path; the streaming body is thread-affine (iterate it on the
127
+ thread that called the app, as mainstream servers do); `HttpStreamingResponse`
128
+ raises `IOError` on use-after-close; early termination closes the backend
129
+ connection instead of draining it.
130
+
131
+ ### Security
132
+
133
+ - Refuse Host-derived backends unless `allow_dynamic_backend: true` is set
134
+ (see Breaking changes) — closes the default open-proxy/SSRF pivot.
135
+ - Strip hop-by-hop headers from the **forwarded request** (Connection, TE,
136
+ Transfer-Encoding, Proxy-Authorization, …, plus any header named by the inbound
137
+ `Connection` header), closing a Content-Length/Transfer-Encoding request-smuggling
138
+ surface. Hop-by-hop headers were previously stripped only from the response.
139
+ - Add `backend_allowed?(backend)` — an overridable per-request allowlist hook,
140
+ consulted for every request (static backends included). A refused backend
141
+ responds `502`.
142
+ - Add `:max_response_length` to cap the backend response size (bounds memory
143
+ against a hostile/huge backend). Enforced incrementally while streaming.
144
+ - Add `:ca_file` / `:cert_store` so private-CA backends can be verified under the
145
+ default `VERIFY_PEER` instead of disabling verification.
146
+ - Add `:open_timeout` / `:write_timeout` to bound connect and per-write stalls
147
+ (previously only `:read_timeout` was configurable).
148
+
149
+ ### Added
150
+
151
+ - `:min_version` / `:max_version` TLS options (mapping to `Net::HTTP#min_version=`
152
+ / `#max_version=`). `:ssl_version` still works but is deprecated (it pins an
153
+ exact protocol and forbids TLS 1.3).
154
+ - `HttpStreamingResponse#close` so Rack servers release the backend connection on
155
+ early termination (HEAD, 304, client disconnect) instead of leaking it until GC.
156
+ - Opt-in request hardening: `strip_credentials: true` drops the client's
157
+ `Cookie`/`Authorization` headers from the forwarded request, and
158
+ `replace_x_forwarded_for: true` forwards only this hop's `REMOTE_ADDR`
159
+ instead of appending to the client-supplied `X-Forwarded-For` chain.
160
+ - Project scaffolding: `SECURITY.md`, `CHANGELOG.md`, `CONTRIBUTING.md`,
161
+ `CLAUDE.md`/`AGENTS.md`, GitHub Actions CI (Ruby 3.1–3.4 × Rack 2/3),
162
+ Dependabot, issue/PR templates, SimpleCov with a ratcheted coverage floor
163
+ (`COVERAGE=1`), and Standard (`standardrb`) + `bundler-audit` enforced by a
164
+ CI lint job.
165
+
166
+ ### Changed
167
+
168
+ - **The streaming path no longer monkey-patches `net/http`.**
169
+ `Rack::HttpStreamingResponse` now runs the public block form of
170
+ `Net::HTTP#request` inside a Fiber (pausing at the response head, resuming
171
+ per body chunk), replacing the 2010-era patch of private `net/http` internals
172
+ in `net_http_hacked.rb`. Behavioral notes: the streaming session sets
173
+ `max_retries = 0` so a transport error can never silently replay the request
174
+ mid-stream; early termination (client abort, HEAD, 204/304) now closes
175
+ the backend connection immediately instead of draining the remaining body;
176
+ and a body-less POST/PUT/PATCH on the streaming path now carries
177
+ `Content-Length: 0` (matching the non-streaming path and plain `Net::HTTP` —
178
+ the old patched path sent no `Content-Length` at all).
179
+ - Backend and construction failures now map to status codes instead of raising a
180
+ `500`: `400` (malformed request URI), `501` (unknown HTTP method), `502`
181
+ (broadened backend-error set incl. `ECONNRESET`, `EPIPE`, read/write timeouts,
182
+ `EOFError`, `OpenSSL::SSL::SSLError`, protocol errors, and malformed backend
183
+ responses — `Net::HTTPBadResponse` / `Net::HTTPHeaderSyntaxError`).
184
+ - gzip-encoded backend responses are forwarded verbatim (Content-Encoding and
185
+ Content-Length preserved) instead of being transparently inflated.
186
+ - Skip all `1xx` interim responses (including `103 Early Hints`) on the streaming
187
+ path, so a backend's `103` is no longer mistaken for the final response.
188
+ - `rack` dependency constrained to `>= 2.0, < 4`; the library now `require`s rack
189
+ itself.
190
+ - Test suite is fully offline (local WEBrick server); the previous live-host
191
+ tests are gated behind `LIVE=1`.
192
+
193
+ ### Deprecated
194
+
195
+ - `:ssl_version` — use `:min_version` / `:max_version`.
196
+
197
+ ### Removed
198
+
199
+ - `lib/net_http_hacked.rb` — the 2010-era monkey-patch of private `Net::HTTP`
200
+ internals. The library stopped using it when streaming moved to the public
201
+ `Net::HTTP` API (see Changed); `require "net_http_hacked"` and the
202
+ `begin_request_hacked` / `end_request_hacked` methods are gone. If external
203
+ code still depends on them, vendor the file from a 0.8.x release — and plan
204
+ to migrate; it breaks under modern net/http refactors.
205
+
206
+ - The bundled examples moved from the gem load path
207
+ (`lib/rack_proxy_examples/`) to [`examples/`](examples/) in the repository.
208
+ `require "rack_proxy_examples/..."` no longer works — copy the example class
209
+ into your app instead (they were never safe to require blindly: each one
210
+ installs itself into the Rails middleware stack when Rails is booted).
211
+
212
+ ## [0.8.3] - 2025
213
+
214
+ ### Fixed
215
+
216
+ - Handle non-rewindable request body streams (Rack 3 input streams need not
217
+ respond to `#rewind`). (#128)
218
+
219
+ ## [0.8.2] - 2025
220
+
221
+ ### Fixed
222
+
223
+ - Harden `build_header_hash` against a top-level `::Headers` constant defined by
224
+ the host app being picked up instead of `Rack::Headers`.
225
+
226
+ ## [0.8.1] - 2025
227
+
228
+ ### Added
229
+
230
+ - `:logger` option, wired to `Net::HTTP#set_debug_output` for wire-level debug
231
+ output. (#80)
232
+
233
+ ## [0.8.0] - 2025
234
+
235
+ ### Changed
236
+
237
+ - **BREAKING:** TLS certificate verification now defaults to `VERIFY_PEER`
238
+ (Ruby's `Net::HTTP` default). Previous versions silently used `VERIFY_NONE` for
239
+ HTTPS backends. Pass `ssl_verify_none: true` (or `verify_mode:`) to opt out. (#113)
240
+
241
+ ### Fixed
242
+
243
+ - Return `502` on backend connection errors instead of raising; correct body
244
+ handling for empty responses and no-entity-body statuses (1xx/204/304). (#58, #122, #123)
245
+
246
+ ---
247
+
248
+ Older releases (≤ 0.7.8) predate this changelog; see the git history and tags.
249
+
250
+ [Unreleased]: https://github.com/ncr/rack-proxy/compare/v2.0.1...HEAD
251
+ [2.0.1]: https://github.com/ncr/rack-proxy/compare/v2.0.0...v2.0.1
252
+ [2.0.0]: https://github.com/ncr/rack-proxy/compare/v1.0.2...v2.0.0
253
+ [1.0.2]: https://github.com/ncr/rack-proxy/compare/v1.0.1...v1.0.2
254
+ [1.0.1]: https://github.com/ncr/rack-proxy/compare/v1.0.0...v1.0.1
255
+ [1.0.0]: https://github.com/ncr/rack-proxy/compare/v0.8.3...v1.0.0
256
+ [0.8.3]: https://github.com/ncr/rack-proxy/compare/v0.8.2...v0.8.3
257
+ [0.8.2]: https://github.com/ncr/rack-proxy/compare/v0.8.1...v0.8.2
258
+ [0.8.1]: https://github.com/ncr/rack-proxy/compare/v0.8.0...v0.8.1
259
+ [0.8.0]: https://github.com/ncr/rack-proxy/compare/v0.7.8...v0.8.0
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2013 Jacek Becela jacek.becela@gmail.com
3
+ Copyright (c) 2010-2026 Jacek Becela and contributors jacek.becela@gmail.com
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal