protocol-http 0.57.0 → 0.58.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
- checksums.yaml.gz.sig +0 -0
- data/context/streaming.md +2 -2
- data/lib/protocol/http/header/generic.rb +30 -0
- data/lib/protocol/http/headers.rb +52 -21
- data/lib/protocol/http/version.rb +1 -1
- data/readme.md +6 -4
- data/releases.md +6 -0
- data.tar.gz.sig +0 -0
- metadata +2 -1
- metadata.gz.sig +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 971bece5e113d3f945faf8b8ce44858e97f0e6282e3a264b6e6fca1e57c8e71c
|
|
4
|
+
data.tar.gz: 8d1139a2022dbe96710d7e0286a5c30c2384e14fcba3e0907428361b25c3a703
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 69d17f997389daf2332cacc0d5ac407897e2dc2a45c3e329f23dfc9b18f7075b425e10c43fff27ff1728f64e92a6843e3291be5103e9ee8c72d1f810c2603c01
|
|
7
|
+
data.tar.gz: '09676f19f6b3bd4d6290b5dccd8f93d2c6409e82926fa74a9b21f39f4fa92df0d289ef8fac6b0460a9de2784d78d7114d262f9a5088f66518ef60b9d60a877f4'
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/context/streaming.md
CHANGED
|
@@ -38,7 +38,7 @@ Async do
|
|
|
38
38
|
Protocol::HTTP::Response[200, {}, output]
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
server_task = Async
|
|
41
|
+
server_task = Async{server.run}
|
|
42
42
|
|
|
43
43
|
client = Async::HTTP::Client.new(endpoint)
|
|
44
44
|
|
|
@@ -104,7 +104,7 @@ Async do
|
|
|
104
104
|
Protocol::HTTP::Response[200, {}, output]
|
|
105
105
|
end
|
|
106
106
|
|
|
107
|
-
server_task = Async
|
|
107
|
+
server_task = Async{server.run}
|
|
108
108
|
|
|
109
109
|
client = Async::HTTP::Client.new(endpoint)
|
|
110
110
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2025, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require_relative "split"
|
|
7
|
+
|
|
8
|
+
module Protocol
|
|
9
|
+
module HTTP
|
|
10
|
+
module Header
|
|
11
|
+
# Represents generic or custom headers that can be used in trailers.
|
|
12
|
+
#
|
|
13
|
+
# This class is used as the default policy for headers not explicitly defined in the POLICY hash.
|
|
14
|
+
#
|
|
15
|
+
# It allows generic headers to be used in HTTP trailers, which is important for:
|
|
16
|
+
# - Custom application headers.
|
|
17
|
+
# - gRPC status headers (grpc-status, grpc-message).
|
|
18
|
+
# - Headers used by proxies and middleware.
|
|
19
|
+
# - Future HTTP extensions.
|
|
20
|
+
class Generic < Split
|
|
21
|
+
# Whether this header is acceptable in HTTP trailers.
|
|
22
|
+
# Generic headers are allowed in trailers by default to support extensibility.
|
|
23
|
+
# @returns [Boolean] `true`, generic headers are allowed in trailers.
|
|
24
|
+
def self.trailer?
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -20,6 +20,7 @@ require_relative "header/priority"
|
|
|
20
20
|
require_relative "header/trailer"
|
|
21
21
|
require_relative "header/server_timing"
|
|
22
22
|
require_relative "header/digest"
|
|
23
|
+
require_relative "header/generic"
|
|
23
24
|
|
|
24
25
|
require_relative "header/accept"
|
|
25
26
|
require_relative "header/accept_charset"
|
|
@@ -158,7 +159,26 @@ module Protocol
|
|
|
158
159
|
return trailer(&block)
|
|
159
160
|
end
|
|
160
161
|
|
|
162
|
+
# Enumerate all the headers in the header, if there are any.
|
|
163
|
+
#
|
|
164
|
+
# @yields {|key, value| ...} The header key and value.
|
|
165
|
+
# @parameter key [String] The header key.
|
|
166
|
+
# @parameter value [String] The raw header value.
|
|
167
|
+
def header(&block)
|
|
168
|
+
return to_enum(:header) unless block_given?
|
|
169
|
+
|
|
170
|
+
if @tail and @tail < @fields.size
|
|
171
|
+
@fields.first(@tail).each(&block)
|
|
172
|
+
else
|
|
173
|
+
@fields.each(&block)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
161
177
|
# Enumerate all headers in the trailer, if there are any.
|
|
178
|
+
#
|
|
179
|
+
# @yields {|key, value| ...} The header key and value.
|
|
180
|
+
# @parameter key [String] The header key.
|
|
181
|
+
# @parameter value [String] The raw header value.
|
|
162
182
|
def trailer(&block)
|
|
163
183
|
return to_enum(:trailer) unless block_given?
|
|
164
184
|
|
|
@@ -191,7 +211,7 @@ module Protocol
|
|
|
191
211
|
# @parameter key [String] The header key.
|
|
192
212
|
# @parameter value [String] The raw header value.
|
|
193
213
|
def each(&block)
|
|
194
|
-
|
|
214
|
+
@fields.each(&block)
|
|
195
215
|
end
|
|
196
216
|
|
|
197
217
|
# @returns [Boolean] Whether the headers include the specified key.
|
|
@@ -227,9 +247,18 @@ module Protocol
|
|
|
227
247
|
#
|
|
228
248
|
# @parameter key [String] the header key.
|
|
229
249
|
# @parameter value [String] the header value to assign.
|
|
230
|
-
|
|
250
|
+
# @parameter trailer [Boolean] whether this header is being added as a trailer.
|
|
251
|
+
def add(key, value, trailer: self.trailer?)
|
|
231
252
|
value = value.to_s
|
|
232
253
|
|
|
254
|
+
if trailer
|
|
255
|
+
policy = @policy[key.downcase]
|
|
256
|
+
|
|
257
|
+
if !policy or !policy.trailer?
|
|
258
|
+
raise InvalidTrailerError, key
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
233
262
|
if @indexed
|
|
234
263
|
merge_into(@indexed, key.downcase, value)
|
|
235
264
|
end
|
|
@@ -297,6 +326,10 @@ module Protocol
|
|
|
297
326
|
end
|
|
298
327
|
|
|
299
328
|
# The policy for various headers, including how they are merged and normalized.
|
|
329
|
+
#
|
|
330
|
+
# A policy may be `false` to indicate that the header may only be specified once and is a simple string.
|
|
331
|
+
#
|
|
332
|
+
# Otherwise, the policy is a class which implements the header normalization logic, including `parse` and `coerce` class methods.
|
|
300
333
|
POLICY = {
|
|
301
334
|
# Headers which may only be specified once:
|
|
302
335
|
"content-disposition" => false,
|
|
@@ -315,8 +348,11 @@ module Protocol
|
|
|
315
348
|
"user-agent" => false,
|
|
316
349
|
"trailer" => Header::Trailer,
|
|
317
350
|
|
|
318
|
-
#
|
|
351
|
+
# Connection handling:
|
|
319
352
|
"connection" => Header::Connection,
|
|
353
|
+
"upgrade" => Header::Split,
|
|
354
|
+
|
|
355
|
+
# Cache handling:
|
|
320
356
|
"cache-control" => Header::CacheControl,
|
|
321
357
|
"te" => Header::TE,
|
|
322
358
|
"vary" => Header::Vary,
|
|
@@ -354,16 +390,21 @@ module Protocol
|
|
|
354
390
|
|
|
355
391
|
# Accept headers:
|
|
356
392
|
"accept" => Header::Accept,
|
|
393
|
+
"accept-ranges" => Header::Split,
|
|
357
394
|
"accept-charset" => Header::AcceptCharset,
|
|
358
395
|
"accept-encoding" => Header::AcceptEncoding,
|
|
359
396
|
"accept-language" => Header::AcceptLanguage,
|
|
360
397
|
|
|
398
|
+
# Content negotiation headers:
|
|
399
|
+
"content-encoding" => Header::Split,
|
|
400
|
+
"content-range" => false,
|
|
401
|
+
|
|
361
402
|
# Performance headers:
|
|
362
403
|
"server-timing" => Header::ServerTiming,
|
|
363
404
|
|
|
364
405
|
# Content integrity headers:
|
|
365
406
|
"digest" => Header::Digest,
|
|
366
|
-
}.tap{|hash| hash.default =
|
|
407
|
+
}.tap{|hash| hash.default = Header::Generic}
|
|
367
408
|
|
|
368
409
|
# Delete all header values for the given key, and return the merged value.
|
|
369
410
|
#
|
|
@@ -403,25 +444,14 @@ module Protocol
|
|
|
403
444
|
# @parameter hash [Hash] The hash to merge into.
|
|
404
445
|
# @parameter key [String] The header key.
|
|
405
446
|
# @parameter value [String] The raw header value.
|
|
406
|
-
|
|
407
|
-
protected def merge_into(hash, key, value, trailer = @tail)
|
|
447
|
+
protected def merge_into(hash, key, value)
|
|
408
448
|
if policy = @policy[key]
|
|
409
|
-
# Check if we're adding to trailers and this header is allowed:
|
|
410
|
-
if trailer && !policy.trailer?
|
|
411
|
-
raise InvalidTrailerError, key
|
|
412
|
-
end
|
|
413
|
-
|
|
414
449
|
if current_value = hash[key]
|
|
415
450
|
current_value << value
|
|
416
451
|
else
|
|
417
452
|
hash[key] = policy.parse(value)
|
|
418
453
|
end
|
|
419
454
|
else
|
|
420
|
-
# By default, headers are not allowed in trailers:
|
|
421
|
-
if trailer
|
|
422
|
-
raise InvalidTrailerError, key
|
|
423
|
-
end
|
|
424
|
-
|
|
425
455
|
if hash.key?(key)
|
|
426
456
|
raise DuplicateHeaderError, key
|
|
427
457
|
end
|
|
@@ -437,13 +467,14 @@ module Protocol
|
|
|
437
467
|
# @returns [Hash] A hash table of `{key, value}` pairs.
|
|
438
468
|
def to_h
|
|
439
469
|
unless @indexed
|
|
440
|
-
|
|
470
|
+
indexed = {}
|
|
441
471
|
|
|
442
|
-
@fields.
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
merge_into(@indexed, key.downcase, value, trailer)
|
|
472
|
+
@fields.each do |key, value|
|
|
473
|
+
merge_into(indexed, key.downcase, value)
|
|
446
474
|
end
|
|
475
|
+
|
|
476
|
+
# Deferred assignment so that exceptions in `merge_into` don't leave us in an inconsistent state:
|
|
477
|
+
@indexed = indexed
|
|
447
478
|
end
|
|
448
479
|
|
|
449
480
|
return @indexed
|
data/readme.md
CHANGED
|
@@ -30,6 +30,12 @@ Please see the [project documentation](https://socketry.github.io/protocol-http/
|
|
|
30
30
|
|
|
31
31
|
Please see the [project releases](https://socketry.github.io/protocol-http/releases/index) for all releases.
|
|
32
32
|
|
|
33
|
+
### v0.58.0
|
|
34
|
+
|
|
35
|
+
- Move trailer validation to `Headers#add` method to ensure all additions are checked at the time of addition as this is a hard requirement.
|
|
36
|
+
- Introduce `Headers#header` method to enumerate only the main headers, excluding trailers. This can be used after invoking `Headers#trailer!` to avoid race conditions.
|
|
37
|
+
- Fix `Headers#to_h` so that indexed headers are not left in an inconsistent state if errors occur during processing.
|
|
38
|
+
|
|
33
39
|
### v0.57.0
|
|
34
40
|
|
|
35
41
|
- Always use `#parse` when parsing header values from strings to ensure proper normalization and validation.
|
|
@@ -83,10 +89,6 @@ Please see the [project releases](https://socketry.github.io/protocol-http/relea
|
|
|
83
89
|
|
|
84
90
|
- Add support for parsing `accept`, `accept-charset`, `accept-encoding` and `accept-language` headers into structured values.
|
|
85
91
|
|
|
86
|
-
### v0.46.0
|
|
87
|
-
|
|
88
|
-
- Add support for `priority:` header.
|
|
89
|
-
|
|
90
92
|
## See Also
|
|
91
93
|
|
|
92
94
|
- [protocol-http1](https://github.com/socketry/protocol-http1) — HTTP/1 client/server implementation using this
|
data/releases.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.58.0
|
|
4
|
+
|
|
5
|
+
- Move trailer validation to `Headers#add` method to ensure all additions are checked at the time of addition as this is a hard requirement.
|
|
6
|
+
- Introduce `Headers#header` method to enumerate only the main headers, excluding trailers. This can be used after invoking `Headers#trailer!` to avoid race conditions.
|
|
7
|
+
- Fix `Headers#to_h` so that indexed headers are not left in an inconsistent state if errors occur during processing.
|
|
8
|
+
|
|
3
9
|
## v0.57.0
|
|
4
10
|
|
|
5
11
|
- Always use `#parse` when parsing header values from strings to ensure proper normalization and validation.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: protocol-http
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.58.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -94,6 +94,7 @@ files:
|
|
|
94
94
|
- lib/protocol/http/header/digest.rb
|
|
95
95
|
- lib/protocol/http/header/etag.rb
|
|
96
96
|
- lib/protocol/http/header/etags.rb
|
|
97
|
+
- lib/protocol/http/header/generic.rb
|
|
97
98
|
- lib/protocol/http/header/multiple.rb
|
|
98
99
|
- lib/protocol/http/header/priority.rb
|
|
99
100
|
- lib/protocol/http/header/server_timing.rb
|
metadata.gz.sig
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
^�eG�{d65o���u����abH��]��+�>�ҁg������j'���S��6
|
|
2
|
+
�n�q�(�6j��:��|ʱ����"�p�tD磩.#ac�F����B&Za����^PYL�����^��w��(Yj�cRay�� ��ʃ�H|\�]�Μ]�dAo�08�\Rî�;�@��J�Ы����I�Y��1���Z�/�O=����o6�*��a���+���#u�����+6Ml8�~a�`��=4��K̬� ��ӭ0hN�
|
|
3
|
+
@}L��O�pS5�������
|
|
4
|
+
:b����
|