async-http 0.76.0 → 0.78.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.
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