protocol-http 0.50.1 → 0.51.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/protocol/http/accept_encoding.rb +24 -7
- data/lib/protocol/http/body/head.rb +17 -5
- data/lib/protocol/http/body/stream.rb +1 -1
- data/lib/protocol/http/error.rb +18 -0
- data/lib/protocol/http/headers.rb +22 -19
- data/lib/protocol/http/version.rb +1 -1
- data/readme.md +10 -0
- data/releases.md +10 -0
- data.tar.gz.sig +0 -0
- metadata +3 -3
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7152574d762fbdc22baa9dcd2f9d22931a2da4a9b3e0727af9580b7bebe31a1e
|
4
|
+
data.tar.gz: 8a704017b5e0897741233497d779a40eba812357238105bef7910090c08cf7a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bd538f9a03da7137f2f58c77777859b5a2b6b14bef08f055104427d9c029d4bc75912dcd10f8e385680c127439c78e6980436ee9200656f0a41b8d2342de0e8
|
7
|
+
data.tar.gz: 8a00a43b390046bba90ce8c523aa99cf5aff1a2fd1b3c6b3f480538ef9a201c2c9a6ef5646558feb649625498c95a224ef9ec1c1bfa78caa29f2b1a6128a7e55
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -21,6 +21,7 @@ module Protocol
|
|
21
21
|
# The default wrappers to use for decoding content.
|
22
22
|
DEFAULT_WRAPPERS = {
|
23
23
|
"gzip" => Body::Inflate.method(:for),
|
24
|
+
"identity" => ->(body) { body }, # Identity means no encoding
|
24
25
|
|
25
26
|
# There is no point including this:
|
26
27
|
# 'identity' => ->(body){body},
|
@@ -46,15 +47,31 @@ module Protocol
|
|
46
47
|
|
47
48
|
response = super
|
48
49
|
|
49
|
-
if body = response.body and !body.empty?
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
if body = response.body and !body.empty?
|
51
|
+
if content_encoding = response.headers[CONTENT_ENCODING]
|
52
|
+
# Process encodings in reverse order and remove them when they are decoded:
|
53
|
+
while name = content_encoding.last
|
54
|
+
# Look up wrapper with case-insensitive matching:
|
55
|
+
wrapper = @wrappers[name.downcase]
|
56
|
+
|
57
|
+
if wrapper
|
58
|
+
body = wrapper.call(body)
|
59
|
+
# Remove the encoding we just processed:
|
60
|
+
content_encoding.pop
|
61
|
+
else
|
62
|
+
# Unknown encoding - stop processing here:
|
63
|
+
break
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Update the response body:
|
68
|
+
response.body = body
|
69
|
+
|
70
|
+
# Remove the content-encoding header if we decoded all encodings:
|
71
|
+
if content_encoding.empty?
|
72
|
+
response.headers.delete(CONTENT_ENCODING)
|
54
73
|
end
|
55
74
|
end
|
56
|
-
|
57
|
-
response.body = body
|
58
75
|
end
|
59
76
|
|
60
77
|
return response
|
@@ -12,12 +12,24 @@ module Protocol
|
|
12
12
|
# Represents a body suitable for HEAD requests, in other words, a body that is empty and has a known length.
|
13
13
|
class Head < Readable
|
14
14
|
# Create a head body for the given body, capturing its length and then closing it.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
#
|
16
|
+
# If a body is provided, the length is determined from the body, and the body is closed.
|
17
|
+
# If no body is provided, and the content length is provided, a head body is created with that length.
|
18
|
+
# This is useful for creating a head body when you only know the content length but not the actual body, which may happen in adapters for HTTP applications where the application may not provide a body for HEAD requests, but the content length is known.
|
19
|
+
#
|
20
|
+
# @parameter body [Readable | Nil] the body to create a head for.
|
21
|
+
# @parameter length [Integer | Nil] the content length of the body, if known.
|
22
|
+
# @returns [Head | Nil] the head body, or nil if the body is nil.
|
23
|
+
def self.for(body, length = nil)
|
24
|
+
if body
|
25
|
+
head = self.new(body.length)
|
26
|
+
body.close
|
27
|
+
return head
|
28
|
+
elsif length
|
29
|
+
return self.new(length)
|
30
|
+
end
|
19
31
|
|
20
|
-
return
|
32
|
+
return nil
|
21
33
|
end
|
22
34
|
|
23
35
|
# Initialize the head body with the given length.
|
@@ -47,7 +47,7 @@ module Protocol
|
|
47
47
|
#
|
48
48
|
# If buffer is given, then the read data will be placed into buffer instead of a newly created String object.
|
49
49
|
#
|
50
|
-
# @
|
50
|
+
# @parameter length [Integer] the amount of data to read
|
51
51
|
# @parameter buffer [String] the buffer which will receive the data
|
52
52
|
# @returns [String] a buffer containing the data
|
53
53
|
def read(length = nil, buffer = nil)
|
data/lib/protocol/http/error.rb
CHANGED
@@ -8,5 +8,23 @@ module Protocol
|
|
8
8
|
# A generic, HTTP protocol error.
|
9
9
|
class Error < StandardError
|
10
10
|
end
|
11
|
+
|
12
|
+
# Represents a bad request error (as opposed to a server error).
|
13
|
+
# This is used to indicate that the request was malformed or invalid.
|
14
|
+
module BadRequest
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised when a singleton (e.g. `content-length`) header is duplicated in a request or response.
|
18
|
+
class DuplicateHeaderError < Error
|
19
|
+
include BadRequest
|
20
|
+
|
21
|
+
# @parameter key [String] The header key that was duplicated.
|
22
|
+
def initialize(key)
|
23
|
+
super("Duplicate singleton header key: #{key.inspect}")
|
24
|
+
end
|
25
|
+
|
26
|
+
# @attribute [String] key The header key that was duplicated.
|
27
|
+
attr :key
|
28
|
+
end
|
11
29
|
end
|
12
30
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2018-2025, by Samuel Williams.
|
5
5
|
|
6
|
+
require_relative "error"
|
7
|
+
|
6
8
|
require_relative "header/split"
|
7
9
|
require_relative "header/multiple"
|
8
10
|
|
@@ -196,9 +198,18 @@ module Protocol
|
|
196
198
|
# @parameter key [String] the header key.
|
197
199
|
# @parameter value [String] the header value to assign.
|
198
200
|
def add(key, value)
|
199
|
-
|
201
|
+
# The value MUST be a string, so we convert it to a string to prevent errors later on.
|
202
|
+
value = value.to_s
|
203
|
+
|
204
|
+
if @indexed
|
205
|
+
merge_into(@indexed, key.downcase, value)
|
206
|
+
end
|
207
|
+
|
208
|
+
@fields << [key, value]
|
200
209
|
end
|
201
210
|
|
211
|
+
alias []= add
|
212
|
+
|
202
213
|
# Set the specified header key to the specified value, replacing any existing header keys with the same name.
|
203
214
|
#
|
204
215
|
# @parameter key [String] the header key to replace.
|
@@ -212,7 +223,7 @@ module Protocol
|
|
212
223
|
# Merge the headers into this instance.
|
213
224
|
def merge!(headers)
|
214
225
|
headers.each do |key, value|
|
215
|
-
self
|
226
|
+
self.add(key, value)
|
216
227
|
end
|
217
228
|
|
218
229
|
return self
|
@@ -223,31 +234,19 @@ module Protocol
|
|
223
234
|
self.dup.merge!(headers)
|
224
235
|
end
|
225
236
|
|
226
|
-
# Append the value to the given key. Some values can be appended multiple times, others can only be set once.
|
227
|
-
#
|
228
|
-
# @parameter key [String] The header key.
|
229
|
-
# @parameter value [String] The header value.
|
230
|
-
def []= key, value
|
231
|
-
if @indexed
|
232
|
-
merge_into(@indexed, key.downcase, value)
|
233
|
-
end
|
234
|
-
|
235
|
-
@fields << [key, value]
|
236
|
-
end
|
237
|
-
|
238
237
|
# The policy for various headers, including how they are merged and normalized.
|
239
238
|
POLICY = {
|
240
239
|
# Headers which may only be specified once:
|
241
|
-
"content-type" => false,
|
242
240
|
"content-disposition" => false,
|
243
241
|
"content-length" => false,
|
244
|
-
"
|
245
|
-
"referer" => false,
|
246
|
-
"host" => false,
|
242
|
+
"content-type" => false,
|
247
243
|
"from" => false,
|
244
|
+
"host" => false,
|
248
245
|
"location" => false,
|
249
246
|
"max-forwards" => false,
|
247
|
+
"referer" => false,
|
250
248
|
"retry-after" => false,
|
249
|
+
"user-agent" => false,
|
251
250
|
|
252
251
|
# Custom headers:
|
253
252
|
"connection" => Header::Connection,
|
@@ -267,6 +266,7 @@ module Protocol
|
|
267
266
|
"etag" => Header::ETag,
|
268
267
|
"if-match" => Header::ETags,
|
269
268
|
"if-none-match" => Header::ETags,
|
269
|
+
"if-range" => false,
|
270
270
|
|
271
271
|
# Headers which may be specified multiple times, but which can't be concatenated:
|
272
272
|
"www-authenticate" => Multiple,
|
@@ -332,7 +332,10 @@ module Protocol
|
|
332
332
|
hash[key] = policy.new(value)
|
333
333
|
end
|
334
334
|
else
|
335
|
-
|
335
|
+
if hash.key?(key)
|
336
|
+
raise DuplicateHeaderError, key
|
337
|
+
end
|
338
|
+
|
336
339
|
hash[key] = value
|
337
340
|
end
|
338
341
|
end
|
data/readme.md
CHANGED
@@ -24,6 +24,16 @@ Please see the [project documentation](https://socketry.github.io/protocol-http/
|
|
24
24
|
|
25
25
|
Please see the [project releases](https://socketry.github.io/protocol-http/releases/index) for all releases.
|
26
26
|
|
27
|
+
### v0.51.0
|
28
|
+
|
29
|
+
- `Protocol::HTTP::Headers` now raise a `DuplicateHeaderError` when a duplicate singleton header (e.g. `content-length`) is added.
|
30
|
+
- `Protocol::HTTP::Headers#add` now coerces the value to a string when adding a header, ensuring consistent behaviour.
|
31
|
+
- `Protocol::HTTP::Body::Head.for` now accepts an optional `length` parameter, allowing it to create a head body even when the body is not provided, based on the known content length.
|
32
|
+
|
33
|
+
### v0.50.0
|
34
|
+
|
35
|
+
- Drop support for Ruby v3.1.
|
36
|
+
|
27
37
|
### v0.48.0
|
28
38
|
|
29
39
|
- Add support for parsing `accept`, `accept-charset`, `accept-encoding` and `accept-language` headers into structured values.
|
data/releases.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Releases
|
2
2
|
|
3
|
+
## v0.51.0
|
4
|
+
|
5
|
+
- `Protocol::HTTP::Headers` now raise a `DuplicateHeaderError` when a duplicate singleton header (e.g. `content-length`) is added.
|
6
|
+
- `Protocol::HTTP::Headers#add` now coerces the value to a string when adding a header, ensuring consistent behaviour.
|
7
|
+
- `Protocol::HTTP::Body::Head.for` now accepts an optional `length` parameter, allowing it to create a head body even when the body is not provided, based on the known content length.
|
8
|
+
|
9
|
+
## v0.50.0
|
10
|
+
|
11
|
+
- Drop support for Ruby v3.1.
|
12
|
+
|
3
13
|
## v0.48.0
|
4
14
|
|
5
15
|
- Add support for parsing `accept`, `accept-charset`, `accept-encoding` and `accept-language` headers into structured values.
|
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.51.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -47,7 +47,7 @@ cert_chain:
|
|
47
47
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
48
48
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
49
49
|
-----END CERTIFICATE-----
|
50
|
-
date:
|
50
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
51
51
|
dependencies: []
|
52
52
|
executables: []
|
53
53
|
extensions: []
|
@@ -122,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
122
|
- !ruby/object:Gem::Version
|
123
123
|
version: '0'
|
124
124
|
requirements: []
|
125
|
-
rubygems_version: 3.6.
|
125
|
+
rubygems_version: 3.6.9
|
126
126
|
specification_version: 4
|
127
127
|
summary: Provides abstractions to handle HTTP protocols.
|
128
128
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|