async-http 0.86.0 → 0.87.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea4e711204ad0a9af1e1e635a4ce7248683ae570e783bd8648e9d8e9c8c21b9c
4
- data.tar.gz: 14dd2e09b46342b06aebf142f40d8c75aa864cee62df950452ef07e47ec2e7e0
3
+ metadata.gz: 7fb9ca49f85d321261c3a3ee9cccf0459841fc09e5df5981289c6d4a6dc6a973
4
+ data.tar.gz: 2a8310e595b65f51001f0b871de5992476153cd0de3eb175d1060e7743ffe6d2
5
5
  SHA512:
6
- metadata.gz: 7b667f21701e3e9f6d77f7af842b2540c979ebefe9f94a07fda2eb617e5e1327621d51fc7c0caf6e97245228db09d42a2850f2a96c94c3fbc62683837c4995cc
7
- data.tar.gz: 256a13cfc5fd2f3cef207086902893d4ec5753d44af7ae0422c12636cb756b7ca27fe498d2810fe3757d84e5470157900c8d9be51a714e457a0f1f18342dd193
6
+ metadata.gz: 5b2c843acae23369e6fcffffea81ee443bac6caa2bb21acd80a72af00a831326700e0b0c6e57128f300b11bcbaf435f03e59a84c3de17c59b170241a0dce0cfb
7
+ data.tar.gz: b851a56d637736f82cc48b68c00ca4562daa9756548792d4f41c21771150e6b1bd1385eb429cfa43937936454d4719e3535f9273254dc81e26880ce30aa3eeb6
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, 2018-2024, by Samuel Williams.
4
+ # Copyright, 2018-2025, by Samuel Williams.
5
5
 
6
6
  require_relative "connection"
7
7
 
@@ -39,7 +39,16 @@ module Async
39
39
 
40
40
  # We carefully interpret https://tools.ietf.org/html/rfc7230#section-6.3.1 to implement this correctly.
41
41
  begin
42
- write_request(request.authority, request.method, request.path, @version, request.headers)
42
+ target = request.path
43
+ authority = request.authority
44
+
45
+ # If we are using a CONNECT request, we need to use the authority as the target:
46
+ if request.connect?
47
+ target = authority
48
+ authority = nil
49
+ end
50
+
51
+ write_request(authority, request.method, target, @version, request.headers)
43
52
  rescue
44
53
  # If we fail to fully write the request and body, we can retry this request.
45
54
  raise RequestFailed
@@ -1,7 +1,7 @@
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 "../request"
7
7
 
@@ -10,21 +10,45 @@ module Async
10
10
  module Protocol
11
11
  module HTTP1
12
12
  class Request < Protocol::Request
13
+ def self.valid_path?(target)
14
+ if target.start_with?("/")
15
+ return true
16
+ elsif target == "*"
17
+ return true
18
+ else
19
+ return false
20
+ end
21
+ end
22
+
23
+ URI_PATTERN = %r{\A(?<scheme>[^:/]+)://(?<authority>[^/]+)(?<path>.*)\z}
24
+
13
25
  def self.read(connection)
14
- if parts = connection.read_request
15
- self.new(connection, *parts)
26
+ connection.read_request do |authority, method, target, version, headers, body|
27
+ if method == ::Protocol::HTTP::Methods::CONNECT
28
+ # We put the target into the authority field for CONNECT requests, as per HTTP/2 semantics.
29
+ self.new(connection, nil, target, method, nil, version, headers, body)
30
+ elsif valid_path?(target)
31
+ # This is a valid request.
32
+ self.new(connection, nil, authority, method, target, version, headers, body)
33
+ elsif match = target.match(URI_PATTERN)
34
+ # We map the incoming absolute URI target to the scheme, authority, and path fields of the request.
35
+ self.new(connection, match[:scheme], match[:authority], method, match[:path], version, headers, body)
36
+ else
37
+ # This is an invalid request.
38
+ raise ::Protocol::HTTP1::BadRequest.new("Invalid request target: #{target}")
39
+ end
16
40
  end
17
41
  end
18
42
 
19
43
  UPGRADE = "upgrade"
20
44
 
21
- def initialize(connection, authority, method, path, version, headers, body)
45
+ def initialize(connection, scheme, authority, method, path, version, headers, body)
22
46
  @connection = connection
23
47
 
24
48
  # HTTP/1 requests with an upgrade header (which can contain zero or more values) are extracted into the protocol field of the request, and we expect a response to select one of those protocols with a status code of 101 Switching Protocols.
25
49
  protocol = headers.delete("upgrade")
26
50
 
27
- super(nil, authority, method, path, version, headers, body, protocol, self.public_method(:write_interim_response))
51
+ super(scheme, authority, method, path, version, headers, body, protocol, self.public_method(:write_interim_response))
28
52
  end
29
53
 
30
54
  def connection
@@ -1,7 +1,7 @@
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 "../request"
7
7
  require_relative "stream"
@@ -99,7 +99,7 @@ module Async
99
99
  end
100
100
 
101
101
  def valid?
102
- @scheme and @method and @path
102
+ @scheme and @method and (@path or @method == ::Protocol::HTTP::Methods::CONNECT)
103
103
  end
104
104
 
105
105
  def hijack?
@@ -1,7 +1,7 @@
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 "../response"
7
7
  require_relative "stream"
@@ -204,9 +204,12 @@ module Async
204
204
  pseudo_headers = [
205
205
  [SCHEME, request.scheme],
206
206
  [METHOD, request.method],
207
- [PATH, request.path],
208
207
  ]
209
208
 
209
+ if path = request.path
210
+ pseudo_headers << [PATH, path]
211
+ end
212
+
210
213
  # To ensure that the HTTP/1.1 request line can be reproduced accurately, this pseudo-header field MUST be omitted when translating from an HTTP/1.1 request that has a request target in origin or asterisk form (see [RFC7230], Section 5.3). Clients that generate HTTP/2 requests directly SHOULD use the :authority pseudo-header field instead of the Host header field.
211
214
  if authority = request.authority
212
215
  pseudo_headers << [AUTHORITY, authority]
@@ -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
 
6
6
  require_relative "client"
7
7
  require_relative "endpoint"
@@ -82,7 +82,7 @@ module Async
82
82
  def connect(&block)
83
83
  input = Body::Writable.new
84
84
 
85
- response = @client.connect(@address.to_s, @headers, input)
85
+ response = @client.connect(authority: @address, headers: @headers, body: input)
86
86
 
87
87
  if response.success?
88
88
  pipe = Body::Pipe.new(response.body, input)
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module HTTP
8
- VERSION = "0.86.0"
8
+ VERSION = "0.87.0"
9
9
  end
10
10
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2017-2024, by Samuel Williams.
3
+ Copyright, 2017-2025, by Samuel Williams.
4
4
  Copyright, 2018, by Viacheslav Koval.
5
5
  Copyright, 2018, by Janko Marohnić.
6
6
  Copyright, 2019, by Denis Talakevich.
data/readme.md CHANGED
@@ -16,6 +16,10 @@ Please see the [project documentation](https://socketry.github.io/async-http/) f
16
16
 
17
17
  Please see the [project releases](https://socketry.github.io/async-http/releases/index) for all releases.
18
18
 
19
+ ### v0.87.0
20
+
21
+ - [Unify HTTP/1 and HTTP/2 `CONNECT` semantics](https://socketry.github.io/async-http/releases/index#unify-http/1-and-http/2-connect-semantics)
22
+
19
23
  ### v0.86.0
20
24
 
21
25
  - Add support for HTTP/2 `NO_RFC7540_PRIORITIES`. See <https://www.rfc-editor.org/rfc/rfc9218.html> for more details.
data/releases.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Releases
2
2
 
3
+ ## v0.87.0
4
+
5
+ ### Unify HTTP/1 and HTTP/2 `CONNECT` semantics
6
+
7
+ HTTP/1 has a request line "target" which takes different forms depending on the kind of request. For `CONNECT` requests, the target is the authority (host and port) of the target server, e.g.
8
+
9
+ CONNECT example.com:443 HTTP/1.1
10
+
11
+ In HTTP/2, the `CONNECT` method uses the `:authority` pseudo-header to specify the target, e.g.
12
+
13
+ ``` http
14
+ [HEADERS FRAME]
15
+ :method: connect
16
+ :authority: example.com:443
17
+ ```
18
+
19
+ In HTTP/1, the `Request#path` attribute was previously used to store the target, and this was incorrectly mapped to the `:path` pseudo-header in HTTP/2. This has been corrected, and the `Request#authority` attribute is now used to store the target for both HTTP/1 and HTTP/2, and mapped accordingly. Thus, to make a `CONNECT` request, you should set the `Request#authority` attribute, e.g.
20
+
21
+ ``` ruby
22
+ response = client.connect(authority: "example.com:443")
23
+ ```
24
+
25
+ For HTTP/1, the authority is mapped back to the request line target, and for HTTP/2, it is mapped to the `:authority` pseudo-header.
26
+
3
27
  ## v0.86.0
4
28
 
5
29
  - Add support for HTTP/2 `NO_RFC7540_PRIORITIES`. See <https://www.rfc-editor.org/rfc/rfc9218.html> for more details.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.86.0
4
+ version: 0.87.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -26,7 +26,6 @@ authors:
26
26
  - Trevor Turk
27
27
  - Viacheslav Koval
28
28
  - dependabot[bot]
29
- autorequire:
30
29
  bindir: bin
31
30
  cert_chain:
32
31
  - |
@@ -58,7 +57,7 @@ cert_chain:
58
57
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
59
58
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
60
59
  -----END CERTIFICATE-----
61
- date: 2024-12-01 00:00:00.000000000 Z
60
+ date: 2025-01-29 00:00:00.000000000 Z
62
61
  dependencies:
63
62
  - !ruby/object:Gem::Dependency
64
63
  name: async
@@ -117,77 +116,75 @@ dependencies:
117
116
  - !ruby/object:Gem::Version
118
117
  version: '0.6'
119
118
  - !ruby/object:Gem::Dependency
120
- name: protocol-http
119
+ name: metrics
121
120
  requirement: !ruby/object:Gem::Requirement
122
121
  requirements:
123
122
  - - "~>"
124
123
  - !ruby/object:Gem::Version
125
- version: '0.43'
124
+ version: '0.12'
126
125
  type: :runtime
127
126
  prerelease: false
128
127
  version_requirements: !ruby/object:Gem::Requirement
129
128
  requirements:
130
129
  - - "~>"
131
130
  - !ruby/object:Gem::Version
132
- version: '0.43'
131
+ version: '0.12'
133
132
  - !ruby/object:Gem::Dependency
134
- name: protocol-http1
133
+ name: protocol-http
135
134
  requirement: !ruby/object:Gem::Requirement
136
135
  requirements:
137
- - - ">="
136
+ - - "~>"
138
137
  - !ruby/object:Gem::Version
139
- version: 0.28.1
138
+ version: '0.49'
140
139
  type: :runtime
141
140
  prerelease: false
142
141
  version_requirements: !ruby/object:Gem::Requirement
143
142
  requirements:
144
- - - ">="
143
+ - - "~>"
145
144
  - !ruby/object:Gem::Version
146
- version: 0.28.1
145
+ version: '0.49'
147
146
  - !ruby/object:Gem::Dependency
148
- name: protocol-http2
147
+ name: protocol-http1
149
148
  requirement: !ruby/object:Gem::Requirement
150
149
  requirements:
151
150
  - - "~>"
152
151
  - !ruby/object:Gem::Version
153
- version: '0.22'
152
+ version: '0.30'
154
153
  type: :runtime
155
154
  prerelease: false
156
155
  version_requirements: !ruby/object:Gem::Requirement
157
156
  requirements:
158
157
  - - "~>"
159
158
  - !ruby/object:Gem::Version
160
- version: '0.22'
159
+ version: '0.30'
161
160
  - !ruby/object:Gem::Dependency
162
- name: traces
161
+ name: protocol-http2
163
162
  requirement: !ruby/object:Gem::Requirement
164
163
  requirements:
165
164
  - - "~>"
166
165
  - !ruby/object:Gem::Version
167
- version: '0.10'
166
+ version: '0.22'
168
167
  type: :runtime
169
168
  prerelease: false
170
169
  version_requirements: !ruby/object:Gem::Requirement
171
170
  requirements:
172
171
  - - "~>"
173
172
  - !ruby/object:Gem::Version
174
- version: '0.10'
173
+ version: '0.22'
175
174
  - !ruby/object:Gem::Dependency
176
- name: metrics
175
+ name: traces
177
176
  requirement: !ruby/object:Gem::Requirement
178
177
  requirements:
179
178
  - - "~>"
180
179
  - !ruby/object:Gem::Version
181
- version: '0.12'
180
+ version: '0.10'
182
181
  type: :runtime
183
182
  prerelease: false
184
183
  version_requirements: !ruby/object:Gem::Requirement
185
184
  requirements:
186
185
  - - "~>"
187
186
  - !ruby/object:Gem::Version
188
- version: '0.12'
189
- description:
190
- email:
187
+ version: '0.10'
191
188
  executables: []
192
189
  extensions: []
193
190
  extra_rdoc_files: []
@@ -244,7 +241,6 @@ licenses:
244
241
  metadata:
245
242
  documentation_uri: https://socketry.github.io/async-http/
246
243
  source_code_uri: https://github.com/socketry/async-http.git
247
- post_install_message:
248
244
  rdoc_options: []
249
245
  require_paths:
250
246
  - lib
@@ -259,8 +255,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
259
255
  - !ruby/object:Gem::Version
260
256
  version: '0'
261
257
  requirements: []
262
- rubygems_version: 3.5.22
263
- signing_key:
258
+ rubygems_version: 3.6.2
264
259
  specification_version: 4
265
260
  summary: A HTTP client and server library.
266
261
  test_files: []
metadata.gz.sig CHANGED
@@ -1,2 +1,2 @@
1
- ����"���+^d��_�za�r{�NC:���(O�U����x|���r��hÕ�<��YҾT#�8ج�]���n'͑���EVH@QD
2
- G4R_��.O��mxN0xa/$��`�TJ2���ׯQ0 ����aÏ��e�JL�{�  ��.� �`%�v��� ����z@�Gk��8�Ȃ�]��]H��GpAHIjI:�֬��rXRQPt�*EoQ�U��}K�D�od%s>^��Ps�M���9��X� %T�tI(p�t�d���os� fR�v@|��z�\ }T!�u��uԔU`ΰ8�*\�����&hT��� ��CG�F�OQR^_+h }aJ�գh�E�ڪ+a� 9�
1
+ ��H��;�w1$O��i�\�q>�������ؕ���5����ʪe��5��P4ǭ;�JmVO��������bC����W��:��W..4ګb�� UDw��Kx ���&��VYt
2
+ 1�{��g��\uw��e����-q�Ɓƃ=B�<i)�Ԝ��0=-Y2Q��x]��so[^b��*��`ܼV���yM��-�7bg{{[{D ����z�_ K>0���Og��ץ��9x)nY]��ow��f 'yD��G3B��ba��TQ���t+`X��'ٔ���`��