protocol-http 0.47.1 → 0.48.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8281f44eb94360f117cba9ef4770386d57b72049ec2200e45041f7b93193147
4
- data.tar.gz: 0e93ed313a1a91971568b575b58db52857f15da6a92fe8764294f2b6ef2335c6
3
+ metadata.gz: 183d448e1ac64631b122da7f8a34c4f506ef5792efdffad906077d206cb7cdd9
4
+ data.tar.gz: 848e8e30617a473bd955419605a06625a9dd3735e42239fd11d5fbcfdbe5ca86
5
5
  SHA512:
6
- metadata.gz: 4f5765e41ef7706b20f8c82812099dc5e79fa6f5c9036332688e5dde9ea0a41a52d44a2442aa33d3514f977939f70c32b40fa858179d4bada70df5b70227e7ab
7
- data.tar.gz: 8835f1c4351794d80db3c917b374648a2090c89619b9bd9deb556955a86eb230118814930d2b8d363838b49f0d2a75d7cee0f8f91bbc2393146cc8cecc9c4f68
6
+ metadata.gz: 58cfc6bf62399c067ccdd1cb5f4e3d5ff02acd3603918f4e1aaadfcb39d505f2a0ec1e60e8f3cf542f9ae615ada5363c72bd652f1513494f50b67911cbe4d6a0
7
+ data.tar.gz: 23befb46df9d7bc48928e08400dec1a11f9028bf0d3cf7549f3f2f2273d833984ea4c1ed37eaa4e68e99d255fd1df98e78c3133c9971d65488f0d06eb41d5c08
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "middleware"
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "readable"
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "middleware"
7
7
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
  # Copyright, 2022, by Herrick Fang.
6
6
 
7
7
  require_relative "url"
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require_relative "split"
7
+ require_relative "quoted_string"
8
+ require_relative "../error"
9
+
10
+ module Protocol
11
+ module HTTP
12
+ module Header
13
+ # The `accept-content-type` header represents a list of content-types that the client can accept.
14
+ class Accept < Array
15
+ # Regular expression used to split values on commas, with optional surrounding whitespace, taking into account quoted strings.
16
+ SEPARATOR = /
17
+ (?: # Start non-capturing group
18
+ "[^"\\]*" # Match quoted strings (no escaping of quotes within)
19
+ | # OR
20
+ [^,"]+ # Match non-quoted strings until a comma or quote
21
+ )+
22
+ (?=,|\z) # Match until a comma or end of string
23
+ /x
24
+
25
+ ParseError = Class.new(Error)
26
+
27
+ MEDIA_RANGE = /\A(?<type>#{TOKEN})\/(?<subtype>#{TOKEN})(?<parameters>.*)\z/
28
+
29
+ PARAMETER = /\s*;\s*(?<key>#{TOKEN})=((?<value>#{TOKEN})|(?<quoted_value>#{QUOTED_STRING}))/
30
+
31
+ # A single entry in the Accept: header, which includes a mime type and associated parameters. A media range can include wild cards, but a media type is a specific type and subtype.
32
+ MediaRange = Struct.new(:type, :subtype, :parameters) do
33
+ def initialize(type, subtype = "*", parameters = {})
34
+ super(type, subtype, parameters)
35
+ end
36
+
37
+ def <=> other
38
+ other.quality_factor <=> self.quality_factor
39
+ end
40
+
41
+ private def parameters_string
42
+ return "" if parameters == nil or parameters.empty?
43
+
44
+ parameters.collect do |key, value|
45
+ ";#{key.to_s}=#{QuotedString.quote(value.to_s)}"
46
+ end.join
47
+ end
48
+
49
+ def to_s
50
+ "#{type}/#{subtype}#{parameters_string}"
51
+ end
52
+
53
+ alias to_str to_s
54
+
55
+ def quality_factor
56
+ parameters.fetch("q", 1.0).to_f
57
+ end
58
+ end
59
+
60
+ # Parse the `accept` header value into a list of content types.
61
+ #
62
+ # @parameter value [String] the value of the header.
63
+ def initialize(value = nil)
64
+ if value
65
+ super(value.scan(SEPARATOR).map(&:strip))
66
+ end
67
+ end
68
+
69
+ # Adds one or more comma-separated values to the header.
70
+ #
71
+ # The input string is split into distinct entries and appended to the array.
72
+ #
73
+ # @parameter value [String] the value or values to add, separated by commas.
74
+ def << (value)
75
+ self.concat(value.scan(SEPARATOR).map(&:strip))
76
+ end
77
+
78
+ # Serializes the stored values into a comma-separated string.
79
+ #
80
+ # @returns [String] the serialized representation of the header values.
81
+ def to_s
82
+ join(",")
83
+ end
84
+
85
+ # Parse the `accept` header.
86
+ #
87
+ # @returns [Array(Charset)] the list of content types and their associated parameters.
88
+ def media_ranges
89
+ self.map do |value|
90
+ self.parse_media_range(value)
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def parse_media_range(value)
97
+ if match = value.match(MEDIA_RANGE)
98
+ type = match[:type]
99
+ subtype = match[:subtype]
100
+ parameters = {}
101
+
102
+ match[:parameters].scan(PARAMETER) do |key, value, quoted_value|
103
+ if quoted_value
104
+ value = QuotedString.unquote(quoted_value)
105
+ end
106
+
107
+ parameters[key] = value
108
+ end
109
+
110
+ return MediaRange.new(type, subtype, parameters)
111
+ else
112
+ raise ParseError, "Invalid media type: #{value.inspect}"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require_relative "split"
7
+ require_relative "quoted_string"
8
+ require_relative "../error"
9
+
10
+ module Protocol
11
+ module HTTP
12
+ module Header
13
+ # The `accept-charset` header represents a list of character sets that the client can accept.
14
+ class AcceptCharset < Split
15
+ ParseError = Class.new(Error)
16
+
17
+ # https://tools.ietf.org/html/rfc7231#section-5.3.3
18
+ CHARSET = /\A(?<name>#{TOKEN})(;q=(?<q>#{QVALUE}))?\z/
19
+
20
+ Charset = Struct.new(:name, :q) do
21
+ def quality_factor
22
+ (q || 1.0).to_f
23
+ end
24
+
25
+ def <=> other
26
+ other.quality_factor <=> self.quality_factor
27
+ end
28
+ end
29
+
30
+ # Parse the `accept-charset` header value into a list of character sets.
31
+ #
32
+ # @returns [Array(Charset)] the list of character sets and their associated quality factors.
33
+ def charsets
34
+ self.map do |value|
35
+ if match = value.match(CHARSET)
36
+ Charset.new(match[:name], match[:q])
37
+ else
38
+ raise ParseError.new("Could not parse character set: #{value.inspect}")
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require_relative "split"
7
+ require_relative "quoted_string"
8
+ require_relative "../error"
9
+
10
+ module Protocol
11
+ module HTTP
12
+ module Header
13
+ # The `accept-encoding` header represents a list of encodings that the client can accept.
14
+ class AcceptEncoding < Split
15
+ ParseError = Class.new(Error)
16
+
17
+ # https://tools.ietf.org/html/rfc7231#section-5.3.1
18
+ QVALUE = /0(\.[0-9]{0,3})?|1(\.[0]{0,3})?/
19
+
20
+ # https://tools.ietf.org/html/rfc7231#section-5.3.4
21
+ ENCODING = /\A(?<name>#{TOKEN})(;q=(?<q>#{QVALUE}))?\z/
22
+
23
+ Encoding = Struct.new(:name, :q) do
24
+ def quality_factor
25
+ (q || 1.0).to_f
26
+ end
27
+
28
+ def <=> other
29
+ other.quality_factor <=> self.quality_factor
30
+ end
31
+ end
32
+
33
+ # Parse the `accept-encoding` header value into a list of encodings.
34
+ #
35
+ # @returns [Array(Charset)] the list of character sets and their associated quality factors.
36
+ def encodings
37
+ self.map do |value|
38
+ if match = value.match(ENCODING)
39
+ Encoding.new(match[:name], match[:q])
40
+ else
41
+ raise ParseError.new("Could not parse encoding: #{value.inspect}")
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ require_relative "split"
7
+ require_relative "quoted_string"
8
+ require_relative "../error"
9
+
10
+ module Protocol
11
+ module HTTP
12
+ module Header
13
+ # The `accept-language` header represents a list of languages that the client can accept.
14
+ class AcceptLanguage < Split
15
+ ParseError = Class.new(Error)
16
+
17
+ # https://tools.ietf.org/html/rfc3066#section-2.1
18
+ NAME = /\*|[A-Z]{1,8}(-[A-Z0-9]{1,8})*/i
19
+
20
+ # https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9
21
+ QVALUE = /0(\.[0-9]{0,6})?|1(\.[0]{0,6})?/
22
+
23
+ # https://greenbytes.de/tech/webdav/rfc7231.html#quality.values
24
+ LANGUAGE = /\A(?<name>#{NAME})(\s*;\s*q=(?<q>#{QVALUE}))?\z/
25
+
26
+ Language = Struct.new(:name, :q) do
27
+ def quality_factor
28
+ (q || 1.0).to_f
29
+ end
30
+
31
+ def <=> other
32
+ other.quality_factor <=> self.quality_factor
33
+ end
34
+ end
35
+
36
+ # Parse the `accept-language` header value into a list of languages.
37
+ #
38
+ # @returns [Array(Charset)] the list of character sets and their associated quality factors.
39
+ def languages
40
+ self.map do |value|
41
+ if match = value.match(LANGUAGE)
42
+ Language.new(match[:name], match[:q])
43
+ else
44
+ raise ParseError.new("Could not parse language: #{value.inspect}")
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
  # Copyright, 2023, by Thomas Morgan.
6
6
 
7
7
  require_relative "split"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2024, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
  # Copyright, 2024, by Thomas Morgan.
6
6
 
7
7
  require_relative "split"
@@ -53,4 +53,4 @@ module Protocol
53
53
  end
54
54
  end
55
55
  end
56
- end
56
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "multiple"
7
7
  require_relative "../cookie"
@@ -32,4 +32,4 @@ module Protocol
32
32
  end
33
33
  end
34
34
  end
35
- end
35
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module HTTP
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
  # Copyright, 2023, by Thomas Morgan.
6
6
 
7
7
  require_relative "split"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module HTTP
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2025, by Samuel Williams.
5
+
6
+ module Protocol
7
+ module HTTP
8
+ module Header
9
+ # According to https://tools.ietf.org/html/rfc7231#appendix-C
10
+ TOKEN = /[!#$%&'*+\-.^_`|~0-9A-Z]+/i
11
+
12
+ QUOTED_STRING = /"(?:.(?!(?<!\\)"))*.?"/
13
+
14
+ # https://tools.ietf.org/html/rfc7231#section-5.3.1
15
+ QVALUE = /0(\.[0-9]{0,3})?|1(\.[0]{0,3})?/
16
+
17
+ # Handling of HTTP quoted strings.
18
+ module QuotedString
19
+ # Unquote a "quoted-string" value according to <https://tools.ietf.org/html/rfc7230#section-3.2.6>. It should already match the QUOTED_STRING pattern above by the parser.
20
+ def self.unquote(value, normalize_whitespace = true)
21
+ value = value[1...-1]
22
+
23
+ value.gsub!(/\\(.)/, '\1')
24
+
25
+ if normalize_whitespace
26
+ # LWS = [CRLF] 1*( SP | HT )
27
+ value.gsub!(/[\r\n]+\s+/, " ")
28
+ end
29
+
30
+ return value
31
+ end
32
+
33
+ QUOTES_REQUIRED = /[()<>@,;:\\"\/\[\]?={} \t]/
34
+
35
+ # Quote a string for HTTP header values if required.
36
+ #
37
+ # @raises [ArgumentError] if the value contains invalid characters like control characters or newlines.
38
+ def self.quote(value, force = false)
39
+ # Check if quoting is required:
40
+ if value =~ QUOTES_REQUIRED or force
41
+ "\"#{value.gsub(/["\\]/, '\\\\\0')}\""
42
+ else
43
+ value
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module HTTP
@@ -30,7 +30,7 @@ module Protocol
30
30
  #
31
31
  # @parameter value [String] the value or values to add, separated by commas.
32
32
  def << value
33
- self.push(*value.split(COMMA))
33
+ self.concat(value.split(COMMA))
34
34
  end
35
35
 
36
36
  # Serializes the stored values into a comma-separated string.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
4
+ # Copyright, 2020-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "split"
7
7
 
@@ -28,4 +28,4 @@ module Protocol
28
28
  end
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2024, by Samuel Williams.
4
+ # Copyright, 2018-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "header/split"
7
7
  require_relative "header/multiple"
8
+
8
9
  require_relative "header/cookie"
9
10
  require_relative "header/connection"
10
11
  require_relative "header/cache_control"
@@ -15,6 +16,11 @@ require_relative "header/authorization"
15
16
  require_relative "header/date"
16
17
  require_relative "header/priority"
17
18
 
19
+ require_relative "header/accept"
20
+ require_relative "header/accept_charset"
21
+ require_relative "header/accept_encoding"
22
+ require_relative "header/accept_language"
23
+
18
24
  module Protocol
19
25
  module HTTP
20
26
  # @namespace
@@ -277,6 +283,12 @@ module Protocol
277
283
  "last-modified" => Header::Date,
278
284
  "if-modified-since" => Header::Date,
279
285
  "if-unmodified-since" => Header::Date,
286
+
287
+ # Accept headers:
288
+ "accept" => Header::Accept,
289
+ "accept-charset" => Header::AcceptCharset,
290
+ "accept-encoding" => Header::AcceptEncoding,
291
+ "accept-language" => Header::AcceptLanguage,
280
292
  }.tap{|hash| hash.default = Split}
281
293
 
282
294
  # Delete all header values for the given key, and return the merged value.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "methods"
7
7
  require_relative "headers"
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2017-2024, by Samuel Williams.
4
+ # Copyright, 2024-2025, by Samuel Williams.
5
5
 
6
6
  module Protocol
7
7
  module HTTP
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2023, by Samuel Williams.
4
+ # Copyright, 2018-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "url"
7
7
 
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Protocol
7
7
  module HTTP
8
- VERSION = "0.47.1"
8
+ VERSION = "0.48.0"
9
9
  end
10
10
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2018-2024, by Samuel Williams.
3
+ Copyright, 2018-2025, by Samuel Williams.
4
4
  Copyright, 2019, by Yuta Iwama.
5
5
  Copyright, 2020, by Olle Jonsson.
6
6
  Copyright, 2020, by Bryan Powell.
data/readme.md CHANGED
@@ -24,6 +24,10 @@ 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.48.0
28
+
29
+ - Add support for parsing `accept`, `accept-charset`, `accept-encoding` and `accept-language` headers into structured values.
30
+
27
31
  ### v0.46.0
28
32
 
29
33
  - Add support for `priority:` header.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.48.0
4
+
5
+ - Add support for parsing `accept`, `accept-charset`, `accept-encoding` and `accept-language` headers into structured values.
6
+
3
7
  ## v0.46.0
4
8
 
5
9
  - Add support for `priority:` header.
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.47.1
4
+ version: 0.48.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -15,7 +15,6 @@ authors:
15
15
  - Marcelo Junior
16
16
  - Olle Jonsson
17
17
  - Yuta Iwama
18
- autorequire:
19
18
  bindir: bin
20
19
  cert_chain:
21
20
  - |
@@ -47,10 +46,8 @@ cert_chain:
47
46
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
48
47
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
49
48
  -----END CERTIFICATE-----
50
- date: 2024-12-04 00:00:00.000000000 Z
49
+ date: 2025-01-24 00:00:00.000000000 Z
51
50
  dependencies: []
52
- description:
53
- email:
54
51
  executables: []
55
52
  extensions: []
56
53
  extra_rdoc_files: []
@@ -75,6 +72,10 @@ files:
75
72
  - lib/protocol/http/content_encoding.rb
76
73
  - lib/protocol/http/cookie.rb
77
74
  - lib/protocol/http/error.rb
75
+ - lib/protocol/http/header/accept.rb
76
+ - lib/protocol/http/header/accept_charset.rb
77
+ - lib/protocol/http/header/accept_encoding.rb
78
+ - lib/protocol/http/header/accept_language.rb
78
79
  - lib/protocol/http/header/authorization.rb
79
80
  - lib/protocol/http/header/cache_control.rb
80
81
  - lib/protocol/http/header/connection.rb
@@ -84,6 +85,7 @@ files:
84
85
  - lib/protocol/http/header/etags.rb
85
86
  - lib/protocol/http/header/multiple.rb
86
87
  - lib/protocol/http/header/priority.rb
88
+ - lib/protocol/http/header/quoted_string.rb
87
89
  - lib/protocol/http/header/split.rb
88
90
  - lib/protocol/http/header/vary.rb
89
91
  - lib/protocol/http/headers.rb
@@ -105,7 +107,6 @@ licenses:
105
107
  metadata:
106
108
  documentation_uri: https://socketry.github.io/protocol-http/
107
109
  source_code_uri: https://github.com/socketry/protocol-http.git
108
- post_install_message:
109
110
  rdoc_options: []
110
111
  require_paths:
111
112
  - lib
@@ -120,8 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
121
  - !ruby/object:Gem::Version
121
122
  version: '0'
122
123
  requirements: []
123
- rubygems_version: 3.5.22
124
- signing_key:
124
+ rubygems_version: 3.6.2
125
125
  specification_version: 4
126
126
  summary: Provides abstractions to handle HTTP protocols.
127
127
  test_files: []
metadata.gz.sig CHANGED
Binary file