Repository navigation
Expand file tree
/
Copy pathCHANGELOG
More file actions
541 lines (383 loc) · 35.1 KB
/
Copy pathCHANGELOG
File metadata and controls
541 lines (383 loc) · 35.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
# http/CHANGELOG
## 20261018
1.7.0: lib/HTTP.rb --> lib/http.rb
1. lib/HTTP.rb --> lib/http.rb, so that it resolves the same on case-sensitive filesystems.
2. + test/loading_test.rb: lib/ carries http.rb, and require 'http.rb' in a fresh process defines HTTP and HTTP::VERSION.
3. ~ test/helper.rb: + skip_webmocks_http_rb_adapter()
4. ~ HTTP::VERSION: /1.6.0/1.7.0/
## 20261011
1.6.0: The response's uri is the URI it came from, which, where redirects were followed, is where they ended.
Nothing recorded where a response had come from: the request objects are made from a path rather than a URI, so Net::HTTP left response.uri nil, and a caller whose request was redirected had no way of knowing where to. A spider resolving the links on a page against the page's address needs it, as does anything noticing that it has been sent to a login page.
1. ~ lib/HTTP/REDIRECT.rb: + HTTP.response_uri, which leaves out any credentials embedded in the URI, a response being something which is passed around and printed.
2. ~ HTTP.request: response.uri is set to response_uri of the URI requested, so that after redirects it is the last of them.
3. ~ HTTP::TooManyRedirects: the message names the URI of the redirect not followed as well as its Location.
4. ~ test/HTTP/REDIRECT_test.rb: + the final URI without a redirect, after one, with no_redirect, and without embedded credentials; the URI of the redirect TooManyRedirects carries. All fail against 1.5.0.
5. ~ README.md: + the response's uri, under Redirections, and in the Limiting redirections example.
6. ~ HTTP::VERSION: /1.5.0/1.6.0/
## 20261011
1.5.0: + max_redirects; + HTTP::TooManyRedirects.
Redirects were followed without limit, each by a call nested in the last, so a redirect loop ran until SystemStackError, which against a local server came after 2,179 requests. Now no more than max_redirects are followed, 20 unless given, which is where browsers stop, and one more raises HTTP::TooManyRedirects.
1. ~ lib/HTTP/REDIRECT.rb: + HTTP::REDIRECT::MAX (20); + HTTP::TooManyRedirects, whose response is the redirect which was not followed.
2. ~ HTTP.redirect_options: + max_redirects, which the redirect is made with one fewer of.
3. ~ HTTP.request: + max_redirects option, which defaults to HTTP::REDIRECT::MAX and is not passed through to Net::HTTP; HTTP::TooManyRedirects is raised at a redirect when none are left. max_redirects: 0 raises at the first redirect, where no_redirect: true returns it, and no_redirect wins where both are given.
4. ~ test/HTTP/REDIRECT_test.rb: + as many redirects followed as allowed, TooManyRedirects for one more with the redirect not followed, 0 raising at the first, no_redirect winning over it, a loop stopped at the default, and the option not passed through to Net::HTTP; max_redirects among the options left as they were. All fail against 1.4.0, which passed max_redirects through to Net::HTTP, where there is no max_redirects= for it.
5. ~ README.md: + Limiting redirections; + max_redirects among the options which aren't passed through to Net::HTTP.
6. ~ HTTP::VERSION: /1.4.0/1.5.0/
## 20261011
1.4.0: The method on a redirect is as RFC 9110 has it: a DELETE redirected by a 301 or 302 is now a DELETE, a PUT a PUT, and a HEAD a HEAD.
Every 301, 302, and 303 was followed with a GET, whatever the method. RFC 9110 allows a 301 or 302 to make a POST a GET, for historical reasons, and nothing else: a PUT, a PATCH, a DELETE, an OPTIONS, or a TRACE was turned into a GET, which did something other than was asked, and a HEAD was too, which fetched the body a HEAD is made to avoid. A 303 does make the method a GET, except for a HEAD, which stays one. Those which were made a GET will now be repeated as themselves, a DELETE included, which is what the specification asks but which differs from what was done before, so anyone whose redirected DELETE, PUT, or PATCH was quietly becoming a GET will find it isn't.
1. ~ lib/HTTP/REDIRECT.rb: + HTTP.redirect_method: 307 and 308 keep the method; 303 makes it a GET, a HEAD excepted; 301 and 302 make a POST a GET and keep the rest.
2. ~ HTTP.request: a redirect is made with redirect_method, through request_with_body where the request had a body to repeat and request_without_body otherwise, rather than through the named method. Content-Type is left behind only where the method changes, and a body repeated keeps it through body_headers, as 1.3.11 has a 307 or 308 do, which matters the more now that a PUT or PATCH redirected by a 301 or 302 is repeated with its body rather than made a GET.
3. ~ HTTP.request: a method without a named helper, such as PROPFIND made with request_without_body, is followed. A 307 or 308 was followed with send(request_method), which raised NoMethodError for one.
4. ~ test/HTTP/{delete,head,options,patch,put,trace}_test.rb: a 301 or 302 is expected to be followed with the method itself rather than with GET.
5. ~ test/HTTP/REDIRECT_test.rb: + the method through each of 301, 302, 303, 307, and 308: POST, PUT with its body, DELETE, HEAD, and PROPFIND. The ones which keep a method other than GET or POST fail against 1.3.11, and PROPFIND by 307 and 308 raised. The PUT examples assert its Content-Type as well as its body.
6. ~ README.md: + how the method is kept, under Redirections, with a table of each method through each redirect.
7. ~ HTTP::VERSION: /1.3.11/1.4.0/
## 20261011
1.3.11: A repeated body keeps the Content-Type it was sent with.
A 307 or 308 repeats the request with its body, and form data, `HTTP.post(uri, {a: 1})`, was repeated without its Content-Type: `form_data=` sets application/x-www-form-urlencoded upon the request object rather than among the headers given, and the request repeated is a new one, made from those headers. So the server was sent `a=1` and no type to read it by. A body sent with a Content-Type among its headers, JSON or XML, kept it, which is why it went unnoticed. As old as the 307 handling: 1.3.2 does the same.
1. ~ lib/HTTP/REDIRECT.rb: + HTTP.body_headers, which adds the request object's Content-Type to the headers where they carry none of their own.
2. ~ HTTP.request: a 307 or 308 is followed with body_headers, and then redirect_headers, rather than redirect_headers alone.
3. ~ test/HTTP/REDIRECT_test.rb: + form data's Content-Type kept through a 307 and through a 308, both failing against 1.3.10, and a Content-Type given among the headers kept in preference to it, which passes either way, being a guard.
4. ~ HTTP::VERSION: /1.3.10/1.3.11/
## 20261011
1.3.10: A block is yielded to once, with the response.
With a block, a followed redirect yielded the final response to it, and then yielded again whatever the block had returned, since that is what the redirected request returned and it was taken for the response: a block which returned an Array was handed that Array. With no_redirect set, the block was yielded the redirect and the redirect was then followed regardless, the branch yielding without returning, so the block was yielded to three times and a request was made which had been asked not to be.
1. ~ HTTP.request: a followed redirect returns what the redirected request returns, which has already been yielded where there is a block, rather than yielding it again.
2. ~ HTTP.request: no_redirect is a condition of following rather than a branch of its own, so that the redirect is yielded or returned as any other response is, and not followed.
3. ~ test/HTTP/REDIRECT_test.rb: + one yield with the final response when a redirect is followed, and one with the redirect when no_redirect is set. Both fail against 1.3.9.
4. ~ HTTP::VERSION: /1.3.9/1.3.10/
## 20261011
1.3.9: Only a 301, 302, 303, 307, or 308 with a Location is followed.
Any 3xx was taken for a redirect. A 304 Not Modified carries no Location, so URI#merge was handed nil and raised ArgumentError, as did any 3xx without one. And a 300 Multiple Choices was followed to whatever its Location named, though it is a list of choices for the caller, the Location being only the server's preference among them. These are answers rather than redirects, and are now returned as they are.
1. ~ lib/HTTP/REDIRECT.rb: + HTTP::REDIRECT::CODES (301, 302, 303, 307, 308); + HTTP.redirect?, which is true of a response with one of those codes and a Location.
2. ~ HTTP.request: follows what redirect? is true of, rather than whatever begins with a 3.
3. ~ test/HTTP/REDIRECT_test.rb: + 300 and 304 returned as they are, as is a 302 without a Location. All three fail against 1.3.8: the 300 and the 304 were followed, and the 302 raised.
4. ~ README.md: + which responses are followed, under Redirections.
5. ~ HTTP::VERSION: /1.3.8/1.3.9/
## 20261011
1.3.8: Headers are carried through a 301, 302, or 303.
A 301, 302, or 303 was followed with no headers at all, so a User-Agent, an Accept, or a Cookie given to the request was not sent to where it was redirected, whereas a 307 or 308 sent them all. Now every redirect carries them, less the credentials which 1.3.6 keeps to their origin, and less Content-Type where the request is made a GET, there being no body for it to describe.
1. ~ HTTP.redirect_headers: + drop_content_type:, which leaves Content-Type behind.
2. ~ HTTP.request: a 301, 302, or 303 is followed with redirect_headers, dropping Content-Type, rather than with no headers.
3. ~ test/HTTP/REDIRECT_test.rb: + headers carried through each of 301, 302, 303, 307, and 308, and Content-Type left behind when a POST becomes a GET; credentials dropped for another origin by 301, 302, and 303 as well as by 307 and 308. The 301, 302, and 303 examples fail against 1.3.7.
4. ~ README.md: + Redirections, on what is carried through a redirect and what is not.
5. ~ HTTP::VERSION: /1.3.7/1.3.8/
## 20261011
1.3.7: The options hash is no longer altered, so no_redirect, retries, and basic authentication survive a call and a redirect.
HTTP.request took no_redirect, username, password, and the retry options out of the caller's hash with delete. A hash passed twice had lost no_redirect by the second call, which then followed the redirect it was asked not to. And the redirect was made with what was left of the hash, so retries and basic authentication were lost at the first redirect, even to the same origin.
1. ~ HTTP.request: works on a copy of the options hash, leaving the caller's as it was.
2. ~ HTTP.request: a redirect is made with the options as given, less what goes no further than the origin.
3. ~ lib/HTTP/REDIRECT.rb: + HTTP.redirect_options, which drops username and password where a redirect goes to another origin, as 1.3.6 does the credential headers.
4. ~ test/HTTP/REDIRECT_test.rb: + the options hash left as it was, no_redirect kept for a second call, retries kept after a redirect, and basic authentication kept for the same origin and dropped for another. All but the last fail against 1.3.6, which dropped it for every origin.
5. ~ HTTP::VERSION: /1.3.6/1.3.7/
## 20261011
1.3.6: Authorization and Cookie headers go no further than the origin they were given to.
A 307 or 308 was followed with every header it was given, so an Authorization or Cookie header meant for one host was sent to whichever host the Location named. A 301, 302, or 303 sent no headers on at all, so it did not leak, though only because it lost everything else too. Following curl and browsers, credentials now stay with their origin: the same scheme, host, and port.
1. + lib/HTTP/REDIRECT.rb: HTTP::REDIRECT::CREDENTIAL_HEADERS (Authorization, Cookie); HTTP.same_origin?, and HTTP.redirect_headers, which drops the credential headers, whatever their case, where a redirect goes to another origin.
2. ~ HTTP.request: a 307 or 308 is followed with redirect_headers rather than the headers as given.
3. + test/HTTP/REDIRECT_test.rb: credentials kept for the same origin, and dropped for another host by 307 and by 308, for another scheme, and for another port, with other headers carried on. All but the first fail against 1.3.5.
4. ~ HTTP::VERSION: /1.3.5/1.3.6/
## 20261011
1.3.5: Non-ASCII is URL-encoded in full, and without a warning.
A query argument holding a multibyte character was encoded one byte per character, so only the first byte of each went out: 'Älaskår' became '%C3lask%C3r' where it should have been '%C3%84lask%C3%A5r', and a server decoding it got invalid UTF-8. The warning this was first noticed by, "historical binary regexp match /.../n against UTF-8 string", came from the same line and is only a warning, but dropping the /n alone would have left the bytes truncated, which is what kept the warning from seeming to matter.
1. ~ Thoran::String::Urlencode#urlencode: /$1.size/$1.bytesize/, so that each byte of a character is encoded rather than the first only.
2. ~ Thoran::String::Urlencode#urlencode: - /n flag. Matched against a UTF-8 string, a binary regexp warns on current Ruby, and the match is the same without it: a run of non-ASCII characters is still matched whole and then unpacked byte by byte, and a binary string is still matched byte-wise.
3. ~ Thoran/String/Urlencode/urlencode.rb: /0.4.0/0.4.1/ in the file's own header.
4. + test/Thoran/String/Urlencode/urlencode_test.rb: unreserved and reserved characters, a space, two and three byte characters, a binary string, the absence of a warning, and the url_encode alias. The multibyte, warning, and alias examples fail against 1.3.4.
5. ~ HTTP::VERSION: /1.3.4/1.3.5/
## 20261011
1.3.4: ~ LICENSE: /2026/2009-2026/
1. ~ LICENSE: the copyright years run from 2009, which is when the README dates the library from. The first commit, 2015, is when its history was imported rather than when it began, so the usual rule of taking the year of the first commit would understate it here.
2. ~ HTTP::VERSION: /1.3.3/1.3.4/
## 20260910
1.3.3: ~ lib/HTTP.rb: + require 'HTTP/VERSION'; + test/HTTP/VERSION_test.rb
1. ~ lib/HTTP.rb: + `require 'HTTP/VERSION'`, last among the requires. The file has been present and unreached, so `require 'http.rb'` left HTTP::VERSION undefined and the gemspec was the only thing loading it.
2. + test/HTTP/VERSION_test.rb: that HTTP::VERSION is a string, that it is three numbers separated by dots, and that it matches the newest entry in the changelog. Modelled on moby's, which is where the convention comes from.
3. The test loads the library rather than VERSION.rb, which is the whole of its value: run against v1.3.2 it fails with "uninitialized constant HTTP::VERSION". Nine libraries were in that state and not one of them carried this test, which is how it went unseen.
4. ~ HTTP::VERSION: /1.3.2/1.3.3/
## 20260819
1.3.2: ~ http.rb.gemspec: spec.files reordered, the globs first.
1. ~ http.rb.gemspec: spec.files reordered, the two Dir globs first and the loose files alphabetically after them, as moby and measurand have it. The globs are what the gem is and the rest is paperwork, so adding a file to the paperwork now never disturbs them. This gemspec had been pinned first with the globs last, which namo shared and impuri left at its 0.12.1. The same 35 files ship, in the same gem; only the order in the source changes.
2. ~ HTTP::VERSION: /1.3.1/1.3.2/
## 20260713
1.3.1: Use Thoran Namespace for URL-encoding extensions.
The String#url_encode and Hash#x_www_form_urlencode extensions reopened the core classes directly. Both now live in named modules under the Thoran:: namespace — Thoran::String::Urlencode and Thoran::Hash::XWwwFormUrlencode — mixed into String and Hash.
1. + Thoran::String::Urlencode#urlencode
2. - String#url_encode
3. + Thoran::Hash::XWwwFormUrlencode#x_www_form_urlencode
4. ~ Hash#x_www_form_urlencode: Requires the Thoran namespaced equivalent.
5. ~ HTTP::VERSION: /1.3.0/1.3.1/
6. ~ CHANGELOG: + 1.3.1 entry
## 20260610
1.3.0: Rename VERBS to METHODS; VERBS retained as a deprecated alias.
RFC 9110 calls these "methods", not "verbs". HTTP::VERBS becomes HTTP::METHODS and HTTP::RETRY::VERBS becomes HTTP::RETRY::METHODS, with the old names kept as deprecated aliases (via deprecate_constant) so nothing breaks. The call surface — the named methods, the options hash, HTTP.request, request_with_body/request_without_body — is unchanged. The aliases are scheduled for removal in 2.0.0; that removal is the breaking change the major bump is reserved for.
1. /lib/HTTP/verbs.rb/lib/HTTP/METHODS.rb/: the file is now named for the METHODS module it defines, matching RETRY.rb and VERSION.rb.
2. ~ HTTP/METHODS.rb: /VERBS/METHODS/ for the WITHOUT_BODY/WITH_BODY container; + VERBS deprecated alias; /verb/request_method/ in the block variable.
3. ~ HTTP.rb: require 'HTTP/METHODS' in place of require 'HTTP/verbs'.
4. ~ HTTP/RETRY.rb: /VERBS/METHODS/ for the default retry method list; + VERBS deprecated alias. retry_config now accepts the :retry_methods option (preferred) and still honours :retry_verbs as a backwards-compatible alias; its internal config key is /verbs/methods/.
5. ~ HTTP/request.rb: the 307/308 redirect handler now references METHODS::WITH_BODY, and the retry guard reads config[:methods]; /verb/request_method/.
6. ~ test/HTTP/RETRY_test.rb: + retry_methods opt-in and retry_methods-over-retry_verbs precedence cases; the option-leak test now covers both :retry_methods and :retry_verbs.
7. + test/HTTP/METHODS_test.rb
8. ~ README.md: retry_methods documented as the option key, with retry_verbs noted as still accepted; the retry default is shown as HTTP::RETRY::METHODS.
9. ~ HTTP::VERSION: /1.2.1/1.3.0/
10. ~ CHANGELOG: + 1.3.0 entry
## 20260610
1.2.1: Split the request builders into their own files.
request_with_body and request_without_body, added in 1.2.0, each move into their own file, matching the one-method-per-file layout used throughout lib/. Purely internal reorganisation — the methods, their signatures, and their behaviour are unchanged — so it is a patch, not a minor.
1. + lib/HTTP/request_without_body.rb: HTTP.request_without_body, extracted from verbs.rb; requires net/http and the Hash#x_www_form_urlencode extension.
2. + lib/HTTP/request_with_body.rb: HTTP.request_with_body, extracted from verbs.rb; requires net/http and json.
3. ~ HTTP/verbs.rb: the request builders are extracted; the file now requires the two new files and keeps the VERBS constant and the named-method generation.
4. ~ HTTP::VERSION: /1.2.0/1.2.1/
5. ~ CHANGELOG: + 1.2.1 entry
## 20260610
1.2.0: Extract request_without_body and request_with_body.
The logic for building request objects — constructing the Net::HTTP request class, encoding bodies, and assembling query strings — lived inside the define_method loops and was unreachable except through the eight named methods. Downstream gems needing a method without a named helper (notably webdav's PROPFIND) had to build raw Net::HTTP request objects and bypass that logic entirely. Those two loop bodies are now module functions, callable directly as HTTP.request_without_body(method, ...) and HTTP.request_with_body(method, ...); the named methods delegate to them and behave identically.
1. ~ HTTP/verbs.rb: + request_without_body() and request_with_body() module functions; the WITHOUT_BODY and WITH_BODY define_method loops now delegate to them.
2. + test/HTTP/request_without_body_test.rb
3. + test/HTTP/request_with_body_test.rb
4. ~ README.md: + Constructing requests for other methods section.
5. ~ HTTP::VERSION: /1.1.0/1.2.0/
6. ~ CHANGELOG: + 1.2.0 entry
## 20260609
1.1.0: Basic auth via the options hash.
Until now basic authentication was only available through credentials embedded in the URI, which forced callers needing programmatic credentials (notably the webdav gem) to construct their own Net::HTTP request objects and bypass the verb methods entirely. The options hash now accepts username: and password:, extracted the same way no_redirect is, so they never leak through to Net::HTTP. This is additive: URI credentials still work as a fallback, and explicit options take precedence over them.
1. ~ HTTP/request.rb: Extract :username and :password from the options hash; basic_auth now prefers the explicit credentials and falls back to the URI credentials.
2. + test/HTTP/basic_auth_test.rb
3. ~ README.md: + Basic authentication usage section; document the username and password options.
4. ~ HTTP::VERSION: /1.0.0/1.1.0/
5. ~ CHANGELOG: + 1.1.0 entry
## 20260522
1.0.0: API stability declaration.
The verb interface (HTTP.get, HTTP.post, HTTP.put, HTTP.delete, HTTP.head, HTTP.options, HTTP.patch, HTTP.trace), the options hash, the redirect handling, the response predicates, and the retry configuration have been stable in shape for several releases. This release declares that commitment publicly: from here, any breaking change requires a major version bump.
1. ~ HTTP::VERSION: /0.26.0/1.0.0/
2. ~ CHANGELOG: + 1.0.0 entry
## 20260522
0.26.0: Documentation and housekeeping polish before 1.0.
1. ~ README.md: Opening blurb now lists all supported verbs (get, head, options, trace, post, put, patch, delete) rather than claiming only GET/POST support.
2. - TODO: All entries were marked (Done as of …); CHANGELOG carries the same history more legibly.
3. ~ http.rb.gemspec: /http:\/\/github.com\/thoran\/HTTP/https:\/\/github.com\/thoran\/http/. Lowercase matches the actual repo; https since GitHub no longer serves plain http.
4. ~ HTTP::VERSION: /0.25.0/0.26.0/
5. ~ CHANGELOG: + 0.26.0 entry
## 20260522
0.25.0: Remove unused internal machinery; require Ruby >= 3.2.
1. ~ HTTP/verbs.rb: /"Net::HTTP::#{verb.to_s.capitalize}".to_const/Net::HTTP.const_get(verb.to_s.capitalize)/. The recursive String#to_const was overkill for a single-level lookup inside Net::HTTP; const_get does it directly.
2. - lib/String/to_const.rb
3. - lib/Thoran/String/ToConst/to_const.rb
4. - lib/Thoran/Array/AllButFirst/all_but_first.rb (was only used by to_const)
5. - lib/Thoran/Array/FirstX/firstX.rb (was only used by all_but_first)
6. ~ lib/HTTP.rb: Remove $LOAD_PATH.unshift; rubygems puts lib/ on the load path for installed gems and bundler does the same for local development.
7. ~ http.rb.gemspec: /required_ruby_version = '>= 2.7'/required_ruby_version = '>= 3.2'/. Aligns with the minitest 6.0 floor used in development; the runtime would still load on 2.7, but claiming compatibility with a Ruby the test suite can't be run against is a fiction worth ending before 1.0.
8. ~ HTTP::VERSION: /0.24.0/0.25.0/
9. ~ CHANGELOG: + 0.25.0 entry
## 20260522
0.24.0: ok? predicate now means 200 specifically.
1. ~ Net::HTTPResponse::StatusPredicates: ok? is now defined as @code == '200' rather than aliased to successful?. The alias semantics (any 2xx) misled — "OK" is the reason-phrase for 200 specifically, not the 2xx class. Migration: callers wanting any-2xx should use successful? (or its alias success?).
2. + test/Net/HTTPResponse/StatusPredicates_test.rb: Specs for ok? against 200, other 2xx codes, and a 4xx code.
3. ~ README.md: Status-predicate section rewritten — single coherent reference for the predicate set, with ok? listed as 200-specific.
4. ~ HTTP::VERSION: /0.23.0/0.24.0/
5. ~ CHANGELOG: + 0.24.0 entry
## 20260522
0.23.0: Fix cross-scheme redirect SSL leak; clamp negative Retry-After.
1. ~ HTTP.request: Compute http-object SSL configuration via options.merge instead of mutating the caller's options hash with auto-derived use_ssl and verify_mode. The previous ||= writes meant an HTTPS→HTTP redirect carried use_ssl: true through to the recursive call against the HTTP host, attempting an SSL handshake on the plain-HTTP port. Cross-scheme redirects in both directions now re-derive use_ssl from each URI.
2. ~ HTTP.retry_after: Clamp the HTTP-date branch via delta && [delta, 0].max. A past Retry-After HTTP-date previously returned a negative delta; Kernel.sleep raises ArgumentError on negatives.
3. ~ test/HTTP/get_test.rb: + cross-scheme redirection specs (HTTPS→HTTP and HTTP→HTTPS) using a Net::HTTP.new stub to capture each Net::HTTP instance and assert use_ssl? per hop.
4. ~ test/HTTP/RETRY_test.rb: + specs for past-date Retry-After (clamps to 0) and negative-integer Retry-After (returns nil).
5. ~ HTTP::VERSION: /0.22.0/0.23.0/
6. ~ CHANGELOG: + 0.23.0 entry; fix 0.13.2 date typo (202503030 → 20250330).
## 20260522
0.22.0: Convert specs from RSpec to Minitest.
1. ~ spec/ → test/: All spec files moved to test/ and rewritten in Minitest spec style with `let`, double-quoted descriptions, and `_(...).must_*` expectations. On the TODO since at least 0.17.0; completed before 1.0 to ship into stability on the test framework that's here to stay.
2. ~ spec/spec_helper.rb → test/helper.rb: Rewrite for Minitest; preserve the webmock http_rb_adapter collision workaround. + MockResponse Struct used as a header-stand-in in HTTP.retry_after specs in place of instance_double(Net::HTTPResponse).
3. ~ Rakefile: Use Rake::TestTask instead of RSpec::Core::RakeTask.
4. ~ http.rb.gemspec: -rspec; +minitest; +minitest-mock (minitest 6 extracted Mock/stub into a separate gem); files glob /spec/test/.
5. ~ HTTP.request: /response.header['location']/response['location']/ — Net::HTTPResponse#header has been deprecated for years; the documented replacement is #[]. Surfaced by Minitest's default reporter showing stderr warnings inline where RSpec was hiding them.
6. ~ TODO: Annotate "Convert specs from RSpec to Minitest" as (Done as of 0.22.0).
7. ~ HTTP::VERSION: /0.21.0/0.22.0/
8. ~ CHANGELOG: + 0.22.0 entry
9. ~ CHANGELOG: Reformat all entries with Markdown-style headings — `## YYYYMMDD` date headings, version line no longer `#`-prefixed.
10. ~ http.rb.gemspec: Pin minitest to `~> 6.0` to lock the major and avoid bundler quietly resolving to 5.x off a stale lockfile.
## 20260522
0.21.0: Add specs for options, trace, and patch verbs.
1. + spec/HTTP/options_spec.rb: Specs for HTTP.options. These were owed since 0.18.0 when the verb was added via the metaprogramming refactor.
2. + spec/HTTP/trace_spec.rb: Specs for HTTP.trace. Owed since 0.18.0.
3. + spec/HTTP/patch_spec.rb: Specs for HTTP.patch. Owed since 0.18.0.
4. ~ HTTP::VERSION: /0.20.0/0.21.0/
5. ~ CHANGELOG: + 0.21.0 entry
## 20260522
0.20.0: Add opt-in retry logic with exponential backoff.
1. + lib/HTTP/RETRY.rb: Retry helpers (with_retries, backoff_delay, retry_after) and constants (HTTP::RETRY::EXCEPTIONS, STATUS_CODES, VERBS).
2. ~ HTTP.request: Retry on transient network exceptions and retry-worthy HTTP status codes (429, 502, 503, 504) when enabled. Exponential backoff with jitter. Honours Retry-After when present. Disabled by default; opt in via the retries option. Configurable via new options: retries (default 0), retry_delay (default 1.0), retry_status_codes, retry_exceptions, retry_verbs. Only idempotent verbs (get, head, options, put, delete, trace) retry by default; opt in to POST/PATCH retries via retry_verbs.
3. + spec/HTTP/RETRY_spec.rb: Specs for retry behaviour and the helpers.
4. ~ README.md: + Retries section.
5. ~ TODO: Annotate "Add retry logic to HTTP.request" as (Done as of 0.20.0); also annotate three previously-completed items as (Done as of 0.18.2), (Done as of 0.18.3), and (Done as of 0.19.0).
6. ~ HTTP::VERSION: /0.19.0/0.20.0/
7. ~ CHANGELOG: + 0.20.0 entry
## 20260522
0.19.0: Change default verify_mode to VERIFY_PEER.
1. ~ HTTP.request: Default verify_mode changed from OpenSSL::SSL::VERIFY_NONE to OpenSSL::SSL::VERIFY_PEER. Callers needing the old behaviour can pass verify_mode: OpenSSL::SSL::VERIFY_NONE explicitly through the options hash.
2. ~ spec/HTTP/get_spec.rb: + specs for default verify_mode and explicit VERIFY_NONE override; /verify_mode: 0/verify_mode: OpenSSL::SSL::VERIFY_PEER/ in redirect specs.
3. ~ spec/HTTP/post_spec.rb: /verify_mode: 0/verify_mode: OpenSSL::SSL::VERIFY_PEER/ in redirect specs.
4. ~ spec/HTTP/put_spec.rb: /verify_mode: 0/verify_mode: OpenSSL::SSL::VERIFY_PEER/ in redirect specs.
5. ~ spec/HTTP/delete_spec.rb: /verify_mode: 0/verify_mode: OpenSSL::SSL::VERIFY_PEER/ in redirect specs.
6. ~ README.md: Note the new verify_mode default and how to opt back into VERIFY_NONE.
7. ~ HTTP::VERSION: /0.18.3/0.19.0/
8. ~ CHANGELOG: + 0.19.0 entry
## 20260521
0.18.3: Fix verb preservation on 307/308 redirects.
1. ~ HTTP.request: Use original verb when following 307 or 308 redirects, per RFC 7231 §6.4.7 and RFC 7538. 301/302/303 keep legacy GET-on-redirect behaviour.
2. ~ spec/HTTP/post_spec.rb: + specs for 307/308 verb preservation and 307 body preservation.
3. ~ spec/HTTP/put_spec.rb: + spec for 307 verb preservation.
4. ~ spec/HTTP/delete_spec.rb: + spec for 307 verb preservation.
5. ~ spec/spec_helper.rb: Skip webmock's http_rb adapter, which collides with this gem's HTTP module on case-insensitive filesystems.
6. ~ HTTP::VERSION: /0.18.2/0.18.3/
7. ~ CHANGELOG: + 0.18.3 entry
## 20260520
0.18.2: Fix relative redirect URL construction.
1. ~ HTTP.request: Use URI#merge for redirect URL construction. Preserves original scheme, elides default ports, and resolves relative paths per RFC 3986.
2. ~ spec/HTTP/get_spec.rb: Update relative-redirect stubs to elide default port; + context for HTTPS relative redirect.
3. ~ spec/HTTP/post_spec.rb: Update relative-redirect stubs to elide default port.
4. ~ spec/HTTP/put_spec.rb: Update relative-redirect stubs to elide default port.
5. ~ spec/HTTP/delete_spec.rb: Update relative-redirect stubs to elide default port.
6. ~ HTTP::VERSION: /0.18.1/0.18.2/
7. ~ CHANGELOG: + 0.18.2 entry
## 20260508
0.18.1: Remove incorrectly added WebDAV verbs.
1. - lib/Net/HTTP/Report.rb
2. ~ HTTP::VERBS: - require_relative '../Net/HTTP/Report'
3. ~ HTTP::VERBS::WITH_BODY: - propfind, proppatch, mkcol, copy, move, lock, unlock, report
4. - spec/HTTP/propfind_spec.rb
5. - spec/Net/HTTP/Report_spec.rb
6. ~ HTTP::VERSION: /0.18.0/0.18.1/
7. ~ CHANGELOG: + 0.18.1 entry
## 20260507
0.18.0: Add all missing HTTP verbs; use meta-programming to define verb methods.
1. + HTTP/verbs.rb; including:
+ HTTP::VERBS::WITHOUT_BODY: get, delete, head, options, trace
+ HTTP::VERBS::WITH_BODY: post, put, patch, propfind, proppatch, mkcol, copy, move, lock, unlock, report
2. + lib/Net/HTTP/Report.rb: Add Net::HTTP::Report, which is missing from Ruby's standard library. See RFC 3253.
3. - lib/HTTP/delete.rb
4. - lib/HTTP/get.rb
5. - lib/HTTP/post.rb
6. - lib/HTTP/put.rb
7. + String/to_const.rb
8. + Thoran/Array/AllButFirst/all_but_first.rb
9. + Thoran/Array/FirstX/firstX.rb
10. + Thoran/String/ToConst/to_const.rb
11. + LICENSE
12. + Rakefile
13. + spec/HTTP/head_spec.rb
14. + spec/HTTP/propfind_spec.rb
15. + spec/Net/HTTP/Report_spec.rb
16. ~ HTTP::VERSION: /0.17.0/0.18.0/
17. /CHANGELOG.txt/CHANGELOG/
18. /TODO.txt/TODO/
19. ~ CHANGELOG: + 0.18.0 entry
20. ~ http.rb.gemspec: /s/spec/; - date; + Rakefile; + development_dependencies
21. ~ Gemfile: /group :test/gemspec/
22. ~ .gitignore: Using a common one with lots of entries.
23. ~ README.md: /http.rb/http/; Trimmed the Description; Usage has more code blocks, making the comments Markdown sub-sections.
## 20260325
0.17.0: Extract HTTP.request method; consolidate set_headers.
1. + HTTP.request: Extract common plumbing (connection, SSL, auth, redirect, response) from verb methods.
2. ~ HTTP.get: Delegate to HTTP.request.
3. ~ HTTP.delete: Delegate to HTTP.request.
4. ~ HTTP.post: Delegate to HTTP.request.
5. ~ HTTP.put: Delegate to HTTP.request.
6. + Net::HTTPRequest#set_headers: Consolidate per-verb set_headers into single method on superclass.
7. - Net::HTTP::Get#set_headers
8. - Net::HTTP::Post#set_headers
9. - Net::HTTP::Put#set_headers
10. - Net::HTTP::Delete#set_headers
11. + TODO.txt
12. ~ HTTP::VERSION: /0.16.1/0.17.0/
13. ~ CHANGELOG.txt: + 0.17.0 entry
14. ~ http.rb.gemspec: Change date.
## 20250908
0.16.1: Allow any case for the content-type key.
1. ~ HTTP.post: Check for any case for content-type key.
2. ~ HTTP.put: Check for any case for content-type key.
3. ~ spec/HTTP/post_spec.rb: + specs for different content-type key cases.
4. ~ spec/HTTP/put_spec.rb: + specs for different content-type key cases.
5. ~ spec/HTTP/put_spec.rb: Fix some erroneous references to (P|p)ost.
6. ~ HTTP::VERSION: /0.16.0/0.16.1/
7. ~ CHANGELOG.txt: + 0.16.1 entry
8. ~ http.rb.gemspec: Change date.
## 20250809
0.16.0: Allow passing of a raw payload for POST/PUT.
1. ~ HTTP.post: Check for Content-Type and whether a string.
2. ~ HTTP.put: Check for Content-Type and whether a string.
3. ~ spec/HTTP/post_spec.rb: + raw form data example
4. ~ spec/HTTP/post_spec.rb: + raw JSON example
5. ~ spec/HTTP/put_spec.rb: + raw form data example
6. ~ spec/HTTP/put_spec.rb: + raw JSON example
7. ~ HTTP::VERSION: /0.15.1/0.16.0/
8. ~ CHANGELOG.txt: + 0.16.0 entry; Small edit on 0.15.1.
9. ~ http.rb.gemspec: Change date.
## 20250721
0.15.1: Fix PUT; require delete and put in the load file.
1. + require 'HTTP/put'
2. + require 'HTTP/delete'
3. ~ HTTP/put.rb: Params in the body!
3. ~ spec/HTTP/put_spec.rb: Remove copy-pasta rubbish.
4. ~ spec/HTTP/post_spec.rb: Mostly formatting.
4. ~ HTTP::VERSION: /0.15.0/0.15.1/
5. ~ CHANGELOG.txt
6. ~ http.rb.gemspec: Change date.
## 20250716
0.15.0: + PUT
1. + HTTP.put
2. + Net::HTTP::Put#set_headers
3. + spec/HTTP/put_spec.rb
4. ~ HTTP::VERSION: /0.14.3/0.15.0/
5. ~ CHANGELOG.txt
6. ~ http.rb.gemspec: Change date.
## 20250711
0.14.0: + DELETE
1. + HTTP.delete
2. + Net::HTTP::Delete#set_headers
3. + spec/HTTP/delete_spec.rb
4. ~ spec/HTTP/get_spec.rb: /require/require_relative/
5. ~ spec/HTTP/post_spec.rb: /require/require_relative/
6. ~ HTTP::VERSION: /0.13.3/0.14.0/
7. ~ CHANGELOG.txt
8. ~ http.rb.gemspec: Change date.
## 20250501
0.13.3: Handle when there's a redirect to a URL with arguments, so as to not add an additional '?' at the end.
1. ~ HTTP.get: Check if the args hash is empty.
2. ~ HTTP::VERSION: /0.13.2/0.13.3/
3. ~ http.rb.gemspec: Change date.
## 20250330
0.13.2: Change repo name to match gem name (/HTTP/http.rb/); + Use HTTP::VERSION; /require/require_relative/
1. ~ README.md: /HTTP/http.rb/, /HTTP.rb/http.rb/
2. + HTTP::VERSION
3. ~ http.rb.gemspec: Use HTTP::VERSION.
4. ~ HTTP.get: /require/require_relative/
5. ~ HTTP.post: /require/require_relative/
## 20250304
0.13.1: /HTTP.rb.gemspec/http.rb.gemspec/
1. /HTTP.rb.gemspec/http.rb.gemspec/ (Wonder no more!)
## 20250304
0.13.0: Extend Net::HTTPResponse to allow use of predicate methods for statuses and optionally prevent redirections.
1. + lib/Net/HTTPResponse/StatusPredicates.rb
2. ~ HTTP/get.rb: + require 'Net/HTTPResponse/StatusPredicates'
3. ~ HTTP/post.rb: + require 'Net/HTTPResponse/StatusPredicates'
4. ~ HTTP.get(): Allow redirects to not be followed with no_redirect option.
5. ~ HTTP.post(): Allow redirects to not be followed with no_redirect option.
6. ~ spec/HTTP/get_spec.rb: Add success? and redirection? expectations throughout as is correct.
7. ~ spec/HTTP/post_spec.rb: Add success? and redirection? expectations throughout as is correct.
8. ~ README.md: Demonstrate usage of response status predicates.
9. ~ README.md: Demonstrate usage of no_redirect option.
10. ~ http.rb.gemspec: /0.12.1/0.13.0/
11. /http.rb.gemspec/HTTP.rb.gemspec/ (I wonder if that's going to cause issues for rubygems.org...)
12. ~ CHANGELOG.txt
## 20250207
0.12.1: Correctly handle POST'ing JSON data.
1. ~ HTTP.post(): Check if the Content-Type is 'application/json' and assign the body JSON data otherwise assign the supplied hash to the form data.
2. ~ spec/HTTP/post_spec.rb: + spec for when a request is being made with JSON data
3. ~ spec/HTTP/post_spec.rb: Assign a headers variable to make the spec more readable.
4. ~ spec/HTTP/post_spec.rb: Remove spaces between outer-most and second outer-most blocks.
5. ~ spec/HTTP/get_spec.rb: Remove spaces between outer-most and second outer-most blocks.
6. ~ README.md: Add # With JSON data section
7. ~ http.rb.gemspec: /0.12.0/0.12.1/
8. + CHANGELOG.txt