async-http 0.72.0 → 0.74.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: 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