async-http 0.76.0 → 0.78.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/async/http/h2spec.rb +6 -6
  4. data/bake/async/http.rb +3 -3
  5. data/lib/async/http/body/hijack.rb +4 -4
  6. data/lib/async/http/body/pipe.rb +1 -1
  7. data/lib/async/http/body/writable.rb +3 -3
  8. data/lib/async/http/body.rb +3 -3
  9. data/lib/async/http/client.rb +15 -18
  10. data/lib/async/http/endpoint.rb +10 -10
  11. data/lib/async/http/internet/instance.rb +1 -1
  12. data/lib/async/http/internet.rb +5 -5
  13. data/lib/async/http/middleware/location_redirector.rb +8 -8
  14. data/lib/async/http/mock/endpoint.rb +2 -2
  15. data/lib/async/http/mock.rb +1 -1
  16. data/lib/async/http/protocol/http.rb +2 -2
  17. data/lib/async/http/protocol/http1/client.rb +19 -6
  18. data/lib/async/http/protocol/http1/connection.rb +6 -7
  19. data/lib/async/http/protocol/http1/finishable.rb +58 -0
  20. data/lib/async/http/protocol/http1/request.rb +3 -3
  21. data/lib/async/http/protocol/http1/response.rb +10 -2
  22. data/lib/async/http/protocol/http1/server.rb +38 -15
  23. data/lib/async/http/protocol/http1.rb +3 -3
  24. data/lib/async/http/protocol/http10.rb +1 -1
  25. data/lib/async/http/protocol/http11.rb +1 -1
  26. data/lib/async/http/protocol/http2/client.rb +4 -4
  27. data/lib/async/http/protocol/http2/connection.rb +12 -12
  28. data/lib/async/http/protocol/http2/input.rb +2 -2
  29. data/lib/async/http/protocol/http2/output.rb +2 -2
  30. data/lib/async/http/protocol/http2/request.rb +4 -4
  31. data/lib/async/http/protocol/http2/response.rb +14 -4
  32. data/lib/async/http/protocol/http2/server.rb +3 -3
  33. data/lib/async/http/protocol/http2/stream.rb +12 -4
  34. data/lib/async/http/protocol/http2.rb +3 -3
  35. data/lib/async/http/protocol/https.rb +3 -3
  36. data/lib/async/http/protocol/request.rb +7 -3
  37. data/lib/async/http/protocol/response.rb +7 -3
  38. data/lib/async/http/protocol.rb +3 -3
  39. data/lib/async/http/proxy.rb +4 -3
  40. data/lib/async/http/reference.rb +2 -2
  41. data/lib/async/http/relative_location.rb +1 -1
  42. data/lib/async/http/server.rb +13 -13
  43. data/lib/async/http/statistics.rb +4 -4
  44. data/lib/async/http/version.rb +1 -1
  45. data/lib/async/http.rb +5 -5
  46. data/readme.md +11 -0
  47. data/releases.md +11 -0
  48. data.tar.gz.sig +0 -0
  49. metadata +7 -6
  50. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd45f82b4d28a3e9a72bbdd7eaec1877b69cfce59a3d67b49a09b99b59b42fa4
4
- data.tar.gz: 05ceb7e93478b63e53bc9a16b829cc2c34efdc22953143192a5a60b310aa04b1
3
+ metadata.gz: 76e78af8d20808d557b1c13c850af0a268de5535726ba07708b2012eb8752029
4
+ data.tar.gz: 53bdf9b950394a03ca8c1fd47befe51e8ba51a5cce82aa47c01111df7efd21b4
5
5
  SHA512:
6
- metadata.gz: 8b293794ba1fb14494a7187a0c1255674ea771df8cc587c6fa031abca25b8bf803f32ba4889d772d53fb8f4dce0705938f1013ab72c22353b4e09c7cc54f4467
7
- data.tar.gz: b0c407ee2c817bd8436bff520ae09744f44e35ba79bd992e76a783be52911fdedb0b397ab12c3cd1ffb00b3042bfc5d429f11b5252e16edbc2bab178172d747d
6
+ metadata.gz: 43c49b50bb88955088b74926e3fe33310f38f4b09d9b9ecdc538a9835c9be5b8be0e172e09794324a53db99e09b0102ae96fc179af13578a758f42644d6f4011
7
+ data.tar.gz: fa1a0d97f326bdd72010f07cfe21004b0da8f75fe4556778bd3b918f42e2e85f22bc41cd07e2a64b4395540e531a879480e634a8fe401ee0d0d7c146af8b61d7
checksums.yaml.gz.sig CHANGED
Binary file
@@ -21,12 +21,12 @@ end
21
21
  private
22
22
 
23
23
  def server
24
- require 'async'
25
- require 'async/container'
26
- require 'async/http/server'
27
- require 'io/endpoint/host_endpoint'
24
+ require "async"
25
+ require "async/container"
26
+ require "async/http/server"
27
+ require "io/endpoint/host_endpoint"
28
28
 
29
- endpoint = IO::Endpoint.tcp('127.0.0.1', 7272)
29
+ endpoint = IO::Endpoint.tcp("127.0.0.1", 7272)
30
30
 
31
31
  container = Async::Container.new
32
32
 
@@ -34,7 +34,7 @@ def server
34
34
 
35
35
  container.run(count: 1) do
36
36
  server = Async::HTTP::Server.for(endpoint, protocol: Async::HTTP::Protocol::HTTP2, scheme: "https") do |request|
37
- Protocol::HTTP::Response[200, {'content-type' => 'text/plain'}, ["Hello World"]]
37
+ Protocol::HTTP::Response[200, {"content-type" => "text/plain"}, ["Hello World"]]
38
38
  end
39
39
 
40
40
  Async do
data/bake/async/http.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2023, by Samuel Williams.
4
+ # Copyright, 2020-2024, by Samuel Williams.
5
5
 
6
6
  # Fetch the specified URL and print the response.
7
7
  # @param url [String] the URL to parse and fetch.
8
8
  # @param method [String] the HTTP method to use.
9
9
  def fetch(url, method:)
10
- require 'async/http/internet'
11
- require 'kernel/sync'
10
+ require "async/http/internet"
11
+ require "kernel/sync"
12
12
 
13
13
  terminal = Console::Terminal.for($stdout)
14
14
  terminal[:request] = terminal.style(:blue, nil, :bold)
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2023, by Samuel Williams.
4
+ # Copyright, 2019-2024, by Samuel Williams.
5
5
 
6
- require 'protocol/http/body/readable'
7
- require 'protocol/http/body/stream'
6
+ require "protocol/http/body/readable"
7
+ require "protocol/http/body/stream"
8
8
 
9
- require_relative 'writable'
9
+ require_relative "writable"
10
10
 
11
11
  module Async
12
12
  module HTTP
@@ -4,7 +4,7 @@
4
4
  # Copyright, 2019-2024, by Samuel Williams.
5
5
  # Copyright, 2020, by Bruno Sutic.
6
6
 
7
- require_relative 'writable'
7
+ require_relative "writable"
8
8
 
9
9
  module Async
10
10
  module HTTP
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2023, by Samuel Williams.
4
+ # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
- require 'protocol/http/body/writable'
7
- require 'async/queue'
6
+ require "protocol/http/body/writable"
7
+ require "async/queue"
8
8
 
9
9
  module Async
10
10
  module HTTP
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2023, by Samuel Williams.
4
+ # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
- require 'protocol/http/body/buffered'
7
- require_relative 'body/writable'
6
+ require "protocol/http/body/buffered"
7
+ require_relative "body/writable"
8
8
 
9
9
  module Async
10
10
  module HTTP
@@ -4,16 +4,16 @@
4
4
  # Copyright, 2017-2024, by Samuel Williams.
5
5
  # Copyright, 2022, by Ian Ker-Seymer.
6
6
 
7
- require 'io/endpoint'
7
+ require "io/endpoint"
8
8
 
9
- require 'async/pool/controller'
9
+ require "async/pool/controller"
10
10
 
11
- require 'protocol/http/body/completable'
12
- require 'protocol/http/methods'
11
+ require "protocol/http/body/completable"
12
+ require "protocol/http/methods"
13
13
 
14
- require 'traces/provider'
14
+ require "traces/provider"
15
15
 
16
- require_relative 'protocol'
16
+ require_relative "protocol"
17
17
 
18
18
  module Async
19
19
  module HTTP
@@ -140,7 +140,7 @@ module Async
140
140
  def inspect
141
141
  "#<#{self.class} authority=#{@authority.inspect}>"
142
142
  end
143
-
143
+
144
144
  Traces::Provider(self) do
145
145
  def call(request)
146
146
  attributes = {
@@ -151,30 +151,30 @@ module Async
151
151
  }
152
152
 
153
153
  if protocol = request.protocol
154
- attributes['http.protocol'] = protocol
154
+ attributes["http.protocol"] = protocol
155
155
  end
156
156
 
157
157
  if length = request.body&.length
158
- attributes['http.request.length'] = length
158
+ attributes["http.request.length"] = length
159
159
  end
160
160
 
161
- Traces.trace('async.http.client.call', attributes: attributes) do |span|
161
+ Traces.trace("async.http.client.call", attributes: attributes) do |span|
162
162
  if context = Traces.trace_context
163
- request.headers['traceparent'] = context.to_s
163
+ request.headers["traceparent"] = context.to_s
164
164
  # request.headers['tracestate'] = context.state
165
165
  end
166
166
 
167
167
  super.tap do |response|
168
168
  if version = response&.version
169
- span['http.version'] = version
169
+ span["http.version"] = version
170
170
  end
171
171
 
172
172
  if status = response&.status
173
- span['http.status_code'] = status
173
+ span["http.status_code"] = status
174
174
  end
175
175
 
176
176
  if length = response.body&.length
177
- span['http.response.length'] = length
177
+ span["http.response.length"] = length
178
178
  end
179
179
  end
180
180
  end
@@ -186,10 +186,7 @@ module Async
186
186
  def make_response(request, connection)
187
187
  response = request.call(connection)
188
188
 
189
- # The connection won't be released until the body is completely read/released.
190
- ::Protocol::HTTP::Body::Completable.wrap(response) do
191
- @pool.release(connection)
192
- end
189
+ response.pool = @pool
193
190
 
194
191
  return response
195
192
  end
@@ -7,22 +7,22 @@
7
7
  # Copyright, 2024, by Igor Sidorov.
8
8
  # Copyright, 2024, by Hal Brodigan.
9
9
 
10
- require 'io/endpoint'
11
- require 'io/endpoint/host_endpoint'
12
- require 'io/endpoint/ssl_endpoint'
10
+ require "io/endpoint"
11
+ require "io/endpoint/host_endpoint"
12
+ require "io/endpoint/ssl_endpoint"
13
13
 
14
- require_relative 'protocol/http'
15
- require_relative 'protocol/https'
14
+ require_relative "protocol/http"
15
+ require_relative "protocol/https"
16
16
 
17
17
  module Async
18
18
  module HTTP
19
19
  # Represents a way to connect to a remote HTTP server.
20
20
  class Endpoint < ::IO::Endpoint::Generic
21
21
  SCHEMES = {
22
- 'http' => URI::HTTP,
23
- 'https' => URI::HTTPS,
24
- 'ws' => URI::WS,
25
- 'wss' => URI::WSS,
22
+ "http" => URI::HTTP,
23
+ "https" => URI::HTTPS,
24
+ "ws" => URI::WS,
25
+ "wss" => URI::WSS,
26
26
  }
27
27
 
28
28
  def self.parse(string, endpoint = nil, **options)
@@ -102,7 +102,7 @@ module Async
102
102
  end
103
103
 
104
104
  def secure?
105
- ['https', 'wss'].include?(self.scheme)
105
+ ["https", "wss"].include?(self.scheme)
106
106
  end
107
107
 
108
108
  def protocol
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2021-2024, by Samuel Williams.
5
5
 
6
- require_relative '../internet'
6
+ require_relative "../internet"
7
7
 
8
8
  ::Thread.attr_accessor :async_http_internet_instance
9
9
 
@@ -4,12 +4,12 @@
4
4
  # Copyright, 2018-2024, by Samuel Williams.
5
5
  # Copyright, 2024, by Igor Sidorov.
6
6
 
7
- require_relative 'client'
8
- require_relative 'endpoint'
7
+ require_relative "client"
8
+ require_relative "endpoint"
9
9
 
10
- require 'protocol/http/middleware'
11
- require 'protocol/http/body/buffered'
12
- require 'protocol/http/accept_encoding'
10
+ require "protocol/http/middleware"
11
+ require "protocol/http/body/buffered"
12
+ require "protocol/http/accept_encoding"
13
13
 
14
14
  module Async
15
15
  module HTTP
@@ -3,10 +3,10 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative '../reference'
6
+ require_relative "../reference"
7
7
 
8
- require 'protocol/http/middleware'
9
- require 'protocol/http/body/rewindable'
8
+ require "protocol/http/middleware"
9
+ require "protocol/http/body/rewindable"
10
10
 
11
11
  module Async
12
12
  module HTTP
@@ -34,10 +34,10 @@ module Async
34
34
 
35
35
  # Header keys which should be deleted when changing a request from a POST to a GET as defined by <https://fetch.spec.whatwg.org/#request-body-header-name>.
36
36
  PROHIBITED_GET_HEADERS = [
37
- 'content-encoding',
38
- 'content-language',
39
- 'content-location',
40
- 'content-type',
37
+ "content-encoding",
38
+ "content-language",
39
+ "content-location",
40
+ "content-type",
41
41
  ]
42
42
 
43
43
  # maximum_hops is the max number of redirects. Set to 0 to allow 1 request with no redirects.
@@ -91,7 +91,7 @@ module Async
91
91
  hops += 1
92
92
 
93
93
  # Get the redirect location:
94
- unless location = response.headers['location']
94
+ unless location = response.headers["location"]
95
95
  return response
96
96
  end
97
97
 
@@ -3,9 +3,9 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative '../protocol'
6
+ require_relative "../protocol"
7
7
 
8
- require 'async/queue'
8
+ require "async/queue"
9
9
 
10
10
  module Async
11
11
  module HTTP
@@ -3,4 +3,4 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2024, by Samuel Williams.
5
5
 
6
- require_relative 'mock/endpoint'
6
+ require_relative "mock/endpoint"
@@ -4,8 +4,8 @@
4
4
  # Copyright, 2024, by Thomas Morgan.
5
5
  # Copyright, 2024, by Samuel Williams.
6
6
 
7
- require_relative 'http1'
8
- require_relative 'http2'
7
+ require_relative "http1"
8
+ require_relative "http2"
9
9
 
10
10
  module Async
11
11
  module HTTP
@@ -3,18 +3,32 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
- require_relative 'connection'
6
+ require_relative "connection"
7
7
 
8
8
  module Async
9
9
  module HTTP
10
10
  module Protocol
11
11
  module HTTP1
12
12
  class Client < Connection
13
+ def initialize(...)
14
+ super
15
+
16
+ @pool = nil
17
+ end
18
+
19
+ attr_accessor :pool
20
+
21
+ def closed!
22
+ super
23
+
24
+ if pool = @pool
25
+ @pool = nil
26
+ pool.release(self)
27
+ end
28
+ end
29
+
13
30
  # Used by the client to send requests to the remote server.
14
31
  def call(request, task: Task.current)
15
- # We need to keep track of connections which are not in the initial "ready" state.
16
- @ready = false
17
-
18
32
  Console.logger.debug(self) {"#{request.method} #{request.path} #{request.headers.inspect}"}
19
33
 
20
34
  # Mark the start of the trailers:
@@ -54,12 +68,11 @@ module Async
54
68
  end
55
69
 
56
70
  response = Response.read(self, request)
57
- @ready = true
58
71
 
59
72
  return response
60
73
  rescue
61
74
  # This will ensure that #reusable? returns false.
62
- @stream.close
75
+ self.close
63
76
 
64
77
  raise
65
78
  end
@@ -3,10 +3,10 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
- require 'protocol/http1'
6
+ require "protocol/http1"
7
7
 
8
- require_relative 'request'
9
- require_relative 'response'
8
+ require_relative "request"
9
+ require_relative "response"
10
10
 
11
11
  module Async
12
12
  module HTTP
@@ -16,12 +16,11 @@ module Async
16
16
  def initialize(stream, version)
17
17
  super(stream)
18
18
 
19
- @ready = true
20
19
  @version = version
21
20
  end
22
21
 
23
22
  def to_s
24
- "\#<#{self.class} negotiated #{@version}, currently #{@ready ? 'ready' : 'in-use'}>"
23
+ "\#<#{self.class} negotiated #{@version}, #{@state}>"
25
24
  end
26
25
 
27
26
  def as_json(...)
@@ -62,11 +61,11 @@ module Async
62
61
 
63
62
  # Can we use this connection to make requests?
64
63
  def viable?
65
- @ready && @stream&.readable?
64
+ self.idle? && @stream&.readable?
66
65
  end
67
66
 
68
67
  def reusable?
69
- @ready && @persistent && @stream && !@stream.closed?
68
+ @persistent && @stream && !@stream.closed?
70
69
  end
71
70
  end
72
71
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2024, by Samuel Williams.
5
+
6
+ require "protocol/http/body/wrapper"
7
+ require "async/variable"
8
+
9
+ module Async
10
+ module HTTP
11
+ module Protocol
12
+ module HTTP1
13
+ # Keeps track of whether a body is being read, and if so, waits for it to be closed.
14
+ class Finishable < ::Protocol::HTTP::Body::Wrapper
15
+ def initialize(body)
16
+ super(body)
17
+
18
+ @closed = Async::Variable.new
19
+ @error = nil
20
+
21
+ @reading = false
22
+ end
23
+
24
+ def reading?
25
+ @reading
26
+ end
27
+
28
+ def read
29
+ @reading = true
30
+
31
+ super
32
+ end
33
+
34
+ def close(error = nil)
35
+ unless @closed.resolved?
36
+ @error = error
37
+ @closed.value = true
38
+ end
39
+
40
+ super
41
+ end
42
+
43
+ def wait
44
+ if @reading
45
+ @closed.wait
46
+ else
47
+ self.discard
48
+ end
49
+ end
50
+
51
+ def inspect
52
+ "#<#{self.class} closed=#{@closed} error=#{@error}> | #{super}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -3,7 +3,7 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
- require_relative '../request'
6
+ require_relative "../request"
7
7
 
8
8
  module Async
9
9
  module HTTP
@@ -16,13 +16,13 @@ module Async
16
16
  end
17
17
  end
18
18
 
19
- UPGRADE = 'upgrade'
19
+ UPGRADE = "upgrade"
20
20
 
21
21
  def initialize(connection, authority, method, path, version, headers, body)
22
22
  @connection = connection
23
23
 
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
- protocol = headers.delete('upgrade')
25
+ protocol = headers.delete("upgrade")
26
26
 
27
27
  super(nil, authority, method, path, version, headers, body, protocol, self.public_method(:write_interim_response))
28
28
  end
@@ -4,7 +4,7 @@
4
4
  # Copyright, 2018-2024, by Samuel Williams.
5
5
  # Copyright, 2023, by Josh Huber.
6
6
 
7
- require_relative '../response'
7
+ require_relative "../response"
8
8
 
9
9
  module Async
10
10
  module HTTP
@@ -23,7 +23,7 @@ module Async
23
23
  end
24
24
  end
25
25
 
26
- UPGRADE = 'upgrade'
26
+ UPGRADE = "upgrade"
27
27
 
28
28
  # @attribute [String] The HTTP response line reason.
29
29
  attr :reason
@@ -39,6 +39,14 @@ module Async
39
39
  super(version, status, headers, body, protocol)
40
40
  end
41
41
 
42
+ def pool=(pool)
43
+ if @connection.idle? or @connection.closed?
44
+ pool.release(@connection)
45
+ else
46
+ @connection.pool = pool
47
+ end
48
+ end
49
+
42
50
  def connection
43
51
  @connection
44
52
  end
@@ -6,24 +6,43 @@
6
6
  # Copyright, 2023, by Thomas Morgan.
7
7
  # Copyright, 2024, by Anton Zhuravsky.
8
8
 
9
- require_relative 'connection'
10
- require 'console/event/failure'
9
+ require_relative "connection"
10
+ require_relative "finishable"
11
+
12
+ require "console/event/failure"
11
13
 
12
14
  module Async
13
15
  module HTTP
14
16
  module Protocol
15
17
  module HTTP1
16
18
  class Server < Connection
19
+ def initialize(...)
20
+ super
21
+
22
+ @ready = Async::Notification.new
23
+ end
24
+
25
+ def closed!
26
+ super
27
+
28
+ @ready.signal
29
+ end
30
+
17
31
  def fail_request(status)
18
32
  @persistent = false
19
33
  write_response(@version, status, {})
20
34
  write_body(@version, nil)
21
35
  rescue => error
22
36
  # At this point, there is very little we can do to recover:
23
- Console::Event::Failure.for(error).emit(self, "Failed to write failure response.", severity: :debug)
37
+ Console::Event::Failure.for(error).emit(self, "Failed to write failure response!", severity: :debug)
24
38
  end
25
39
 
26
40
  def next_request
41
+ # Wait for the connection to become idle before reading the next request:
42
+ unless idle?
43
+ @ready.wait
44
+ end
45
+
27
46
  # The default is true.
28
47
  return unless @persistent
29
48
 
@@ -35,7 +54,7 @@ module Async
35
54
  end
36
55
 
37
56
  return request
38
- rescue ::Protocol::HTTP1::BadRequest
57
+ rescue ::Protocol::HTTP1::BadRequest => error
39
58
  fail_request(400)
40
59
  # Conceivably we could retry here, but we don't really know how bad the error is, so it's better to just fail:
41
60
  raise
@@ -46,7 +65,13 @@ module Async
46
65
  task.annotate("Reading #{self.version} requests for #{self.class}.")
47
66
 
48
67
  while request = next_request
68
+ if body = request.body
69
+ finishable = Finishable.new(body)
70
+ request.body = finishable
71
+ end
72
+
49
73
  response = yield(request, self)
74
+ version = request.version
50
75
  body = response&.body
51
76
 
52
77
  if hijacked?
@@ -77,7 +102,7 @@ module Async
77
102
  # 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.
78
103
  write_response(@version, response.status, response.headers)
79
104
 
80
- stream = write_tunnel_body(request.version)
105
+ stream = write_tunnel_body(version)
81
106
 
82
107
  # Same as above:
83
108
  request = nil
@@ -89,7 +114,7 @@ module Async
89
114
  write_response(@version, response.status, response.headers)
90
115
 
91
116
  if request.connect? and response.success?
92
- stream = write_tunnel_body(request.version)
117
+ stream = write_tunnel_body(version)
93
118
 
94
119
  # Same as above:
95
120
  request = nil
@@ -99,29 +124,27 @@ module Async
99
124
  return body.call(stream)
100
125
  else
101
126
  head = request.head?
102
- version = request.version
103
127
 
104
128
  # Same as above:
105
- request = nil unless request.body
129
+ request = nil
106
130
  response = nil
107
131
 
108
132
  write_body(version, body, head, trailer)
109
133
  end
110
134
  end
111
135
 
112
- # We are done with the body, you shouldn't need to call close on it:
136
+ # We are done with the body:
113
137
  body = nil
114
138
  else
115
139
  # If the request failed to generate a response, it was an internal server error:
116
140
  write_response(@version, 500, {})
117
- write_body(request.version, nil)
141
+ write_body(version, nil)
142
+
143
+ request&.finish
118
144
  end
119
145
 
120
- # Gracefully finish reading the request body if it was not already done so.
121
- request&.each{}
122
-
123
- # This ensures we yield at least once every iteration of the loop and allow other fibers to execute.
124
- task.yield
146
+ # Discard or wait for the input body to be consumed:
147
+ finishable&.wait
125
148
  rescue => error
126
149
  raise
127
150
  ensure