async-http 0.78.0 → 0.80.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: 76e78af8d20808d557b1c13c850af0a268de5535726ba07708b2012eb8752029
4
- data.tar.gz: 53bdf9b950394a03ca8c1fd47befe51e8ba51a5cce82aa47c01111df7efd21b4
3
+ metadata.gz: 5a73103da274cc4cac5838409d95a05f1c8a746e0b58dcee062031886061ffb7
4
+ data.tar.gz: da1d5991f78d71c2ab1a3c8ace1d0d8c53831b545bdcfe2f3e93d095bd6389bd
5
5
  SHA512:
6
- metadata.gz: 43c49b50bb88955088b74926e3fe33310f38f4b09d9b9ecdc538a9835c9be5b8be0e172e09794324a53db99e09b0102ae96fc179af13578a758f42644d6f4011
7
- data.tar.gz: fa1a0d97f326bdd72010f07cfe21004b0da8f75fe4556778bd3b918f42e2e85f22bc41cd07e2a64b4395540e531a879480e634a8fe401ee0d0d7c146af8b61d7
6
+ metadata.gz: 4169f9f110a07db5f27b6e083b09b1c6d3f0940269b1d423150993a491c4f3d46dfa4ae227712502b07d4cf949b0186e1e838fa3b77cead2809ee73c30e4500c
7
+ data.tar.gz: a85d33bd88881433c1c33b369027d6ff4f1c095b26ecac5b583b865fe2f8011c6ee7bba6c6f9857c5b1cf1697c4298a5e4c6506da3584d0215682bd4beea9858
checksums.yaml.gz.sig CHANGED
Binary file
@@ -18,11 +18,12 @@ module Async
18
18
 
19
19
  attr_accessor :pool
20
20
 
21
- def closed!
21
+ def closed(error = nil)
22
22
  super
23
23
 
24
24
  if pool = @pool
25
25
  @pool = nil
26
+ # If the connection is not reusable, this will retire it from the connection pool and invoke `#close`.
26
27
  pool.release(self)
27
28
  end
28
29
  end
@@ -50,30 +51,32 @@ module Async
50
51
  task.async(annotation: "Upgrading request...") do
51
52
  # If this fails, this connection will be closed.
52
53
  write_upgrade_body(protocol, body)
54
+ rescue => error
55
+ self.close(error)
53
56
  end
54
57
  elsif request.connect?
55
58
  task.async(annotation: "Tunnneling request...") do
56
59
  write_tunnel_body(@version, body)
60
+ rescue => error
61
+ self.close(error)
57
62
  end
58
63
  else
59
64
  task.async(annotation: "Streaming request...") do
60
65
  # Once we start writing the body, we can't recover if the request fails. That's because the body might be generated dynamically, streaming, etc.
61
66
  write_body(@version, body, false, trailer)
67
+ rescue => error
68
+ self.close(error)
62
69
  end
63
70
  end
64
71
  elsif protocol = request.protocol
65
72
  write_upgrade_body(protocol)
66
73
  else
67
- write_body(@version, body, false, trailer)
74
+ write_body(@version, request.body, false, trailer)
68
75
  end
69
76
 
70
- response = Response.read(self, request)
71
-
72
- return response
73
- rescue
74
- # This will ensure that #reusable? returns false.
75
- self.close
76
-
77
+ return Response.read(self, request)
78
+ rescue => error
79
+ self.close(error)
77
80
  raise
78
81
  end
79
82
  end
@@ -43,6 +43,8 @@ module Async
43
43
 
44
44
  def read_line?
45
45
  @stream.read_until(CRLF)
46
+ rescue Errno::ECONNRESET
47
+ return nil
46
48
  end
47
49
 
48
50
  def read_line
@@ -32,19 +32,23 @@ module Async
32
32
  end
33
33
 
34
34
  def close(error = nil)
35
+ super
36
+
35
37
  unless @closed.resolved?
36
38
  @error = error
37
39
  @closed.value = true
38
40
  end
39
-
40
- super
41
41
  end
42
42
 
43
- def wait
43
+ def wait(persistent = true)
44
44
  if @reading
45
45
  @closed.wait
46
- else
46
+ elsif persistent
47
+ # If the connection can be reused, let's gracefully discard the body:
47
48
  self.discard
49
+ else
50
+ # Else, we don't care about the body, so we can close it immediately:
51
+ self.close
48
52
  end
49
53
  end
50
54
 
@@ -22,7 +22,7 @@ module Async
22
22
  @ready = Async::Notification.new
23
23
  end
24
24
 
25
- def closed!
25
+ def closed(error = nil)
26
26
  super
27
27
 
28
28
  @ready.signal
@@ -38,14 +38,12 @@ module Async
38
38
  end
39
39
 
40
40
  def next_request
41
- # Wait for the connection to become idle before reading the next request:
42
- unless idle?
41
+ if closed?
42
+ return nil
43
+ elsif !idle?
43
44
  @ready.wait
44
45
  end
45
46
 
46
- # The default is true.
47
- return unless @persistent
48
-
49
47
  # Read an incoming request:
50
48
  return unless request = Request.read(self)
51
49
 
@@ -90,38 +88,41 @@ module Async
90
88
  # We force a 101 response if the protocol is upgraded - HTTP/2 CONNECT will return 200 for success, but this won't be understood by HTTP/1 clients:
91
89
  write_response(@version, 101, response.headers)
92
90
 
93
- stream = write_upgrade_body(protocol)
94
-
95
91
  # At this point, the request body is hijacked, so we don't want to call #finish below.
96
92
  request = nil
97
93
  response = nil
98
94
 
99
- # We must return here as no further request processing can be done:
100
- return body.call(stream)
95
+ if body.stream?
96
+ return body.call(write_upgrade_body(protocol))
97
+ else
98
+ write_upgrade_body(protocol, body)
99
+ end
101
100
  elsif response.status == 101
102
101
  # This code path is to support legacy behavior where the response status is set to 101, but the protocol is not upgraded. This may not be a valid use case, but it is supported for compatibility. We expect the response headers to contain the `upgrade` header.
103
102
  write_response(@version, response.status, response.headers)
104
103
 
105
- stream = write_tunnel_body(version)
106
-
107
104
  # Same as above:
108
105
  request = nil
109
106
  response = nil
110
107
 
111
- # We must return here as no further request processing can be done:
112
- return body&.call(stream)
108
+ if body.stream?
109
+ return body.call(write_tunnel_body(version))
110
+ else
111
+ write_tunnel_body(version, body)
112
+ end
113
113
  else
114
114
  write_response(@version, response.status, response.headers)
115
115
 
116
116
  if request.connect? and response.success?
117
- stream = write_tunnel_body(version)
118
-
119
117
  # Same as above:
120
118
  request = nil
121
119
  response = nil
122
120
 
123
- # We must return here as no further request processing can be done:
124
- return body.call(stream)
121
+ if body.stream?
122
+ return body.call(write_tunnel_body(version))
123
+ else
124
+ write_tunnel_body(version, body)
125
+ end
125
126
  else
126
127
  head = request.head?
127
128
 
@@ -143,8 +144,12 @@ module Async
143
144
  request&.finish
144
145
  end
145
146
 
146
- # Discard or wait for the input body to be consumed:
147
- finishable&.wait
147
+ if finishable
148
+ finishable.wait(@persistent)
149
+ else
150
+ # Do not remove this line or you will unleash the gods of concurrency hell.
151
+ task.yield
152
+ end
148
153
  rescue => error
149
154
  raise
150
155
  ensure
@@ -17,7 +17,8 @@ module Async
17
17
 
18
18
  @task = nil
19
19
 
20
- @window_updated = Async::Condition.new
20
+ @guard = ::Mutex.new
21
+ @window_updated = ::ConditionVariable.new
21
22
  end
22
23
 
23
24
  attr :trailer
@@ -33,17 +34,26 @@ module Async
33
34
  end
34
35
 
35
36
  def window_updated(size)
36
- @window_updated.signal
37
+ @guard.synchronize do
38
+ @window_updated.signal
39
+ end
37
40
  end
38
41
 
39
42
  def write(chunk)
40
43
  until chunk.empty?
41
44
  maximum_size = @stream.available_frame_size
42
45
 
43
- while maximum_size <= 0
44
- @window_updated.wait
45
-
46
- maximum_size = @stream.available_frame_size
46
+ # We try to avoid synchronization if possible:
47
+ if maximum_size <= 0
48
+ @guard.synchronize do
49
+ maximum_size = @stream.available_frame_size
50
+
51
+ while maximum_size <= 0
52
+ @window_updated.wait(@guard)
53
+
54
+ maximum_size = @stream.available_frame_size
55
+ end
56
+ end
47
57
  end
48
58
 
49
59
  break unless chunk = send_data(chunk, maximum_size)
@@ -62,9 +62,9 @@ module Async
62
62
  end
63
63
 
64
64
  # TODO this might need to be in an ensure block:
65
- if @input and frame.end_stream?
66
- @input.close_write
65
+ if input = @input and frame.end_stream?
67
66
  @input = nil
67
+ input.close_write
68
68
  end
69
69
  rescue ::Protocol::HTTP2::HeaderError => error
70
70
  Console.logger.debug(self, error)
@@ -123,6 +123,8 @@ module Async
123
123
 
124
124
  # Called when the output terminates normally.
125
125
  def finish_output(error = nil)
126
+ return if self.closed?
127
+
126
128
  trailer = @output&.trailer
127
129
 
128
130
  @output = nil
@@ -152,14 +154,14 @@ module Async
152
154
  def closed(error)
153
155
  super
154
156
 
155
- if @input
156
- @input.close_write(error)
157
+ if input = @input
157
158
  @input = nil
159
+ input.close_write(error)
158
160
  end
159
161
 
160
- if @output
161
- @output.stop(error)
162
+ if output = @output
162
163
  @output = nil
164
+ output.stop(error)
163
165
  end
164
166
 
165
167
  if pool = @pool and @connection
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module HTTP
8
- VERSION = "0.78.0"
8
+ VERSION = "0.80.0"
9
9
  end
10
10
  end
data.tar.gz.sig CHANGED
@@ -1,4 +1 @@
1
- M7>d[܌c��a���0 d}bB�զ�UƐ��(�)��e���
2
- ^�Ƶ=U���Z��'�cOt3JlLO�K6�4�1:$�t��6�ݚ���)�[y��q��^�a7��.x쥃��U�ɀ�N�*5�T�Y������
3
- h%!5��c;Z[j�sX�L�����}>m}7e��p|9"̕$�4������k'Me_�{s1�?8/Li�Na���-ZI�4���1��G�$a]��ŋ��*���~-N�D8��&�����"��pr:���P;2��:a[��UB�� )|�}4[��ق�`����lq
4
- ��8=�5���Si/�ﻲH���^ �fO
1
+ ug;oFa�l��C�7vt}}�5�X�n��l�Q�6�^h��:tQ[���3d9%���@:B�/�1�����0�KJ�� �LU����o'y O{��.醠K\/���|�k<{p*P��)X��"k���1�c��`~!�V�7=��m�){3BT>���0��6+B�B�Q�w�q3��'ˇ%�.nYZ8�7��q�����u�]���`C4<C��ѿߨ!_���=YE�!�w��DŽ��ǒ�:X8�SL+�59����b��Ձ���,����2D?F���|\;�S����?����q��\������Ӝ2n���rP�7YVUԠ,z���xs��
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.78.0
4
+ version: 0.80.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-09-22 00:00:00.000000000 Z
61
+ date: 2024-10-02 00:00:00.000000000 Z
62
62
  dependencies:
63
63
  - !ruby/object:Gem::Dependency
64
64
  name: async
@@ -136,28 +136,28 @@ dependencies:
136
136
  requirements:
137
137
  - - "~>"
138
138
  - !ruby/object:Gem::Version
139
- version: '0.25'
139
+ version: '0.27'
140
140
  type: :runtime
141
141
  prerelease: false
142
142
  version_requirements: !ruby/object:Gem::Requirement
143
143
  requirements:
144
144
  - - "~>"
145
145
  - !ruby/object:Gem::Version
146
- version: '0.25'
146
+ version: '0.27'
147
147
  - !ruby/object:Gem::Dependency
148
148
  name: protocol-http2
149
149
  requirement: !ruby/object:Gem::Requirement
150
150
  requirements:
151
151
  - - "~>"
152
152
  - !ruby/object:Gem::Version
153
- version: '0.18'
153
+ version: '0.19'
154
154
  type: :runtime
155
155
  prerelease: false
156
156
  version_requirements: !ruby/object:Gem::Requirement
157
157
  requirements:
158
158
  - - "~>"
159
159
  - !ruby/object:Gem::Version
160
- version: '0.18'
160
+ version: '0.19'
161
161
  - !ruby/object:Gem::Dependency
162
162
  name: traces
163
163
  requirement: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file