async-http 0.86.0 → 0.87.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: 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��'ٔ���`��