async-http 0.72.0 → 0.74.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: 8b358f54acd8cf0943e35f30865d7f505025bad37a2c37e0dda5f8438efe3b25
4
- data.tar.gz: a8a9eee82cc0723cf8101ef727072d4518a38ddb7e68f5f0f2d15027e92e83a9
3
+ metadata.gz: 5a21c7008b5509bd6f8bdffd7dad87a7679bdc9f32584cc71fa2b468518cd57c
4
+ data.tar.gz: 2836fc0ef066dfeb60240dce08dd88c07201250b948cfb04617ab52e9d20371c
5
5
  SHA512:
6
- metadata.gz: 7f5720d8ac42c48afb19bd5c387db2da015b2d210836c6d1a7abfe3cd3a4df85587c92b9bbdee61fce397302c66c8ca303c123d9e7f9a2201b26602ea0240e58
7
- data.tar.gz: 91a543963515d1375953da096781b7b9d5a161e20bafc6aa067fbf0e09ff546ae3b48e18a5d8ca06dc5173184546898d415310b6bfbded5605040bce08443010
6
+ metadata.gz: c249984efd9030c199c6b1199dfb4ededdd25a7db33e5156c0ecec2a5d883d703bc976216da13c33426d4814514676f80296687293c53cb4ddc33f44ff4f38a3
7
+ data.tar.gz: f707e1908dc79b1e16f2be6546f1781003f4d88e21307fd5172d27198b61a08f87e350a43f784445a761cda89cb674669b552e77ef1e9de4cfaeb4095040ffa9
checksums.yaml.gz.sig CHANGED
@@ -1 +1,2 @@
1
- &���_��lB�k M��ϟ��D��Ɋ�`��n�-��v3��>�W��#O$�|a��S��On�r:ׯ�U9l�<���E��0|Rj8z?��h��n���@V��a��f0�^L��srRS�/��2؛�.ps)Ho��GSB����f5G����&�Zr
1
+  B��[�����`x�~A PC8_'w�m�uQ����g��%~��{�6|��mP"+��uxwL��Vx���W�K��^�a�&��߸L�F{OW�]pY<|�ޕCŷ&�]wM�E�RkP$ce����X\�"�MIk bU��f�V?$J���P~t�ؒ���w~�u+���M�����s���(,%`����~,�d��K�!�StG�� ���Djۓ+^��-���~���"�\�Z�7ȽU�L�C%D3L)�q��A�6[]ʐG�=ga�^rs��6LQ=�CL�����bQ7g&�㑋C�?(m�N9IT��l@Q���
2
+ +yy�m�O.��u05T,�zTBX�{O��H��[����G� �
@@ -39,14 +39,14 @@ module Async
39
39
  # @parameter url [String] The URL to request, e.g. `https://www.codeotaku.com`.
40
40
  # @parameter headers [Hash | Protocol::HTTP::Headers] The headers to send with the request.
41
41
  # @parameter body [String | Protocol::HTTP::Body] The body to send with the request.
42
- def call(method, url, headers = nil, body = nil, &block)
42
+ def call(verb, url, *arguments, **options, &block)
43
43
  endpoint = Endpoint[url]
44
44
  client = self.client_for(endpoint)
45
45
 
46
- body = Body::Buffered.wrap(body)
47
- headers = ::Protocol::HTTP::Headers[headers]
46
+ options[:authority] ||= endpoint.authority
47
+ options[:scheme] ||= endpoint.scheme
48
48
 
49
- request = ::Protocol::HTTP::Request.new(endpoint.scheme, endpoint.authority, method, endpoint.path, nil, headers, body)
49
+ request = ::Protocol::HTTP::Request[verb, endpoint.path, *arguments, **options]
50
50
 
51
51
  response = client.call(request)
52
52
 
@@ -68,8 +68,8 @@ module Async
68
68
  end
69
69
 
70
70
  ::Protocol::HTTP::Methods.each do |name, verb|
71
- define_method(verb.downcase) do |url, headers = nil, body = nil, &block|
72
- self.call(verb, url, headers, body, &block)
71
+ define_method(verb.downcase) do |url, *arguments, **options, &block|
72
+ self.call(verb, url, *arguments, **options, &block)
73
73
  end
74
74
  end
75
75
 
@@ -24,7 +24,7 @@ module Async
24
24
  # 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
25
  protocol = headers.delete('upgrade')
26
26
 
27
- super(nil, authority, method, path, version, headers, body, protocol)
27
+ super(nil, authority, method, path, version, headers, body, protocol, self.public_method(:write_interim_response))
28
28
  end
29
29
 
30
30
  def connection
@@ -39,8 +39,8 @@ module Async
39
39
  @connection.hijack!
40
40
  end
41
41
 
42
- def write_interim_response(response)
43
- @connection.write_interim_response(response.version, response.status, response.headers)
42
+ def write_interim_response(status, headers = nil)
43
+ @connection.write_interim_response(@version, status, headers)
44
44
  end
45
45
  end
46
46
  end
@@ -17,6 +17,8 @@ module Async
17
17
 
18
18
  if response.final?
19
19
  return response
20
+ else
21
+ request.send_interim_response(response.status, response.headers)
20
22
  end
21
23
  end
22
24
  end
@@ -23,6 +23,8 @@ module Async
23
23
  attr :request
24
24
 
25
25
  def receive_initial_headers(headers, end_stream)
26
+ @headers = ::Protocol::HTTP::Headers.new
27
+
26
28
  headers.each do |key, value|
27
29
  if key == SCHEME
28
30
  raise ::Protocol::HTTP2::HeaderError, "Request scheme already specified!" if @request.scheme
@@ -85,7 +87,7 @@ module Async
85
87
  end
86
88
 
87
89
  def initialize(stream)
88
- super(nil, nil, nil, nil, VERSION, nil)
90
+ super(nil, nil, nil, nil, VERSION, nil, nil, nil, self.public_method(:write_interim_response))
89
91
 
90
92
  @stream = stream
91
93
  end
@@ -117,10 +119,6 @@ module Async
117
119
  [STATUS, response.status],
118
120
  ]
119
121
 
120
- if protocol = response.protocol
121
- protocol_headers << [PROTOCOL, protocol]
122
- end
123
-
124
122
  if length = response.body&.length
125
123
  protocol_headers << [CONTENT_LENGTH, length]
126
124
  end
@@ -142,14 +140,16 @@ module Async
142
140
  end
143
141
  end
144
142
 
145
- def write_interim_response(response)
146
- protocol_headers = [
147
- [STATUS, response.status]
143
+ def write_interim_response(status, headers = nil)
144
+ interim_response_headers = [
145
+ [STATUS, status]
148
146
  ]
149
147
 
150
- headers = ::Protocol::HTTP::Headers::Merged.new(protocol_headers, response.headers)
148
+ if headers
149
+ interim_response_headers = ::Protocol::HTTP::Headers::Merged.new(interim_response_headers, headers)
150
+ end
151
151
 
152
- @stream.send_headers(nil, headers)
152
+ @stream.send_headers(nil, interim_response_headers)
153
153
  end
154
154
  end
155
155
  end
@@ -38,18 +38,25 @@ module Async
38
38
 
39
39
  # This should be invoked from the background reader, and notifies the task waiting for the headers that we are done.
40
40
  def receive_initial_headers(headers, end_stream)
41
+ # While in theory, the response pseudo-headers may be extended in the future, currently they only response pseudo-header is :status, so we can assume it is always the first header.
42
+ status_header = headers.shift
43
+
44
+ if status_header.first != ':status'
45
+ raise ProtocolError, "Invalid response headers: #{headers.inspect}"
46
+ end
47
+
48
+ status = Integer(status_header.last)
49
+
50
+ if status >= 100 && status < 200
51
+ return receive_interim_headers(status, headers)
52
+ end
53
+
54
+ @response.status = status
55
+ @headers = ::Protocol::HTTP::Headers.new
56
+
41
57
  headers.each do |key, value|
42
58
  # It's guaranteed that this should be the first header:
43
- if key == STATUS
44
- status = Integer(value)
45
-
46
- # Ignore informational headers:
47
- return if status >= 100 && status < 200
48
-
49
- @response.status = Integer(value)
50
- elsif key == PROTOCOL
51
- @response.protocol = value
52
- elsif key == CONTENT_LENGTH
59
+ if key == CONTENT_LENGTH
53
60
  @length = Integer(value)
54
61
  else
55
62
  add_header(key, value)
@@ -74,6 +81,16 @@ module Async
74
81
  return headers
75
82
  end
76
83
 
84
+ def receive_interim_headers(status, headers)
85
+ if headers.any?
86
+ headers = ::Protocol::HTTP::Headers[headers]
87
+ else
88
+ headers = nil
89
+ end
90
+
91
+ @response.request.send_interim_response(status, headers)
92
+ end
93
+
77
94
  # Notify anyone waiting on the response headers to be received (or failure).
78
95
  def notify!
79
96
  if notification = @notification
@@ -51,10 +51,9 @@ module Async
51
51
  end
52
52
 
53
53
  def process_headers(frame)
54
- if frame.end_stream? && @headers
54
+ if @headers and frame.end_stream?
55
55
  self.receive_trailing_headers(super, frame.end_stream?)
56
56
  else
57
- @headers ||= ::Protocol::HTTP::Headers.new
58
57
  self.receive_initial_headers(super, frame.end_stream?)
59
58
  end
60
59
 
@@ -25,7 +25,7 @@ module Async
25
25
  false
26
26
  end
27
27
 
28
- def write_interim_response(response)
28
+ def write_interim_response(status, headers = nil)
29
29
  end
30
30
 
31
31
  def peer
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module HTTP
8
- VERSION = "0.72.0"
8
+ VERSION = "0.74.0"
9
9
  end
10
10
  end
data/readme.md CHANGED
@@ -12,6 +12,18 @@ Please see the [project documentation](https://socketry.github.io/async-http/) f
12
12
 
13
13
  - [Testing](https://socketry.github.io/async-http/guides/testing/index) - This guide explains how to use `Async::HTTP` clients and servers in your tests.
14
14
 
15
+ ## Releases
16
+
17
+ Please see the [project releases](https://socketry.github.io/async-http/releases/index) for all releases.
18
+
19
+ ### v0.74.0
20
+
21
+ - [`Async::HTTP::Internet` accepts keyword arguments](https://socketry.github.io/async-http/releases/index#async::http::internet-accepts-keyword-arguments)
22
+
23
+ ### v0.73.0
24
+
25
+ - [Update support for `interim_response`](https://socketry.github.io/async-http/releases/index#update-support-for-interim_response)
26
+
15
27
  ## See Also
16
28
 
17
29
  - [benchmark-http](https://github.com/socketry/benchmark-http) — A benchmarking tool to report on web server concurrency.
data/releases.md ADDED
@@ -0,0 +1,51 @@
1
+ # Releases
2
+
3
+ ## v0.74.0
4
+
5
+ ### `Async::HTTP::Internet` accepts keyword arguments
6
+
7
+ `Async::HTTP::Internet` now accepts keyword arguments for making a request, e.g.
8
+
9
+ ``` ruby
10
+ internet = Async::HTTP::Internet.instance
11
+
12
+ # This will let you override the authority (HTTP/1.1 host header, HTTP/2 :authority header):
13
+ internet.get("https://proxy.local", authority: "example.com")
14
+
15
+ # This will let you override the scheme:
16
+ internet.get("https://example.com", scheme: "http")
17
+ ```
18
+
19
+ ## v0.73.0
20
+
21
+ ### Update support for `interim_response`
22
+
23
+ `Protocol::HTTP::Request` now supports an `interim_response` callback, which will be called with the interim response status and headers. This works on both the client and the server:
24
+
25
+ ``` ruby
26
+ # Server side:
27
+ def call(request)
28
+ if request.headers['expect'].include?('100-continue')
29
+ request.send_interim_response(100)
30
+ end
31
+
32
+ # ...
33
+ end
34
+
35
+ # Client side:
36
+ body = Async::HTTP::Body::Writable.new
37
+
38
+ interim_repsonse = proc do |status, headers|
39
+ if status == 100
40
+ # Continue sending the body...
41
+ body.write("Hello, world!")
42
+ body.close
43
+ end
44
+ end
45
+
46
+ Async::HTTP::Internet.instance.post("https://example.com", body, interim_response: interim_response) do |response|
47
+ unless response.success?
48
+ body.close
49
+ end
50
+ end
51
+ ```
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.72.0
4
+ version: 0.74.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -58,7 +58,7 @@ cert_chain:
58
58
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
59
59
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
60
60
  -----END CERTIFICATE-----
61
- date: 2024-08-29 00:00:00.000000000 Z
61
+ date: 2024-08-31 00:00:00.000000000 Z
62
62
  dependencies:
63
63
  - !ruby/object:Gem::Dependency
64
64
  name: async
@@ -122,14 +122,14 @@ dependencies:
122
122
  requirements:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
- version: '0.29'
125
+ version: '0.30'
126
126
  type: :runtime
127
127
  prerelease: false
128
128
  version_requirements: !ruby/object:Gem::Requirement
129
129
  requirements:
130
130
  - - "~>"
131
131
  - !ruby/object:Gem::Version
132
- version: '0.29'
132
+ version: '0.30'
133
133
  - !ruby/object:Gem::Dependency
134
134
  name: protocol-http1
135
135
  requirement: !ruby/object:Gem::Requirement
@@ -224,6 +224,7 @@ files:
224
224
  - lib/async/http/version.rb
225
225
  - license.md
226
226
  - readme.md
227
+ - releases.md
227
228
  homepage: https://github.com/socketry/async-http
228
229
  licenses:
229
230
  - MIT
metadata.gz.sig CHANGED
Binary file