async-http 0.76.0 → 0.77.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bake/async/http/h2spec.rb +6 -6
- data/bake/async/http.rb +3 -3
- data/lib/async/http/body/finishable.rb +56 -0
- data/lib/async/http/body/hijack.rb +4 -4
- data/lib/async/http/body/pipe.rb +1 -1
- data/lib/async/http/body/writable.rb +3 -3
- data/lib/async/http/body.rb +3 -3
- data/lib/async/http/client.rb +16 -18
- data/lib/async/http/endpoint.rb +10 -10
- data/lib/async/http/internet/instance.rb +1 -1
- data/lib/async/http/internet.rb +5 -5
- data/lib/async/http/middleware/location_redirector.rb +8 -8
- data/lib/async/http/mock/endpoint.rb +2 -2
- data/lib/async/http/mock.rb +1 -1
- data/lib/async/http/protocol/http.rb +2 -2
- data/lib/async/http/protocol/http1/client.rb +19 -6
- data/lib/async/http/protocol/http1/connection.rb +6 -7
- data/lib/async/http/protocol/http1/request.rb +3 -3
- data/lib/async/http/protocol/http1/response.rb +10 -2
- data/lib/async/http/protocol/http1/server.rb +20 -12
- data/lib/async/http/protocol/http1.rb +3 -3
- data/lib/async/http/protocol/http10.rb +1 -1
- data/lib/async/http/protocol/http11.rb +1 -1
- data/lib/async/http/protocol/http2/client.rb +4 -4
- data/lib/async/http/protocol/http2/connection.rb +12 -12
- data/lib/async/http/protocol/http2/input.rb +2 -2
- data/lib/async/http/protocol/http2/output.rb +2 -2
- data/lib/async/http/protocol/http2/request.rb +4 -4
- data/lib/async/http/protocol/http2/response.rb +14 -4
- data/lib/async/http/protocol/http2/server.rb +3 -3
- data/lib/async/http/protocol/http2/stream.rb +12 -4
- data/lib/async/http/protocol/http2.rb +3 -3
- data/lib/async/http/protocol/https.rb +3 -3
- data/lib/async/http/protocol/request.rb +3 -3
- data/lib/async/http/protocol/response.rb +3 -3
- data/lib/async/http/protocol.rb +3 -3
- data/lib/async/http/proxy.rb +4 -3
- data/lib/async/http/reference.rb +2 -2
- data/lib/async/http/relative_location.rb +1 -1
- data/lib/async/http/server.rb +13 -13
- data/lib/async/http/statistics.rb +4 -4
- data/lib/async/http/version.rb +1 -1
- data/lib/async/http.rb +5 -5
- data/readme.md +11 -0
- data/releases.md +11 -0
- data.tar.gz.sig +0 -0
- metadata +7 -6
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a6e20407a7969b8eebeaf3f3a2dac09bdb3fe48130454ae49f46251a03b5c98
|
4
|
+
data.tar.gz: a827ae19dc5c7f60ed338357091f556d1e48b183fe8ab0c119d75547fce4a6cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 116770838b19e96fdc9ed4e1db8af834f0ed8676542d1090ed88c90d02ac0b978bd94378b41edc151108d86e61c39d2fbb9680d217790e1b1cb3f2ceed2aa64e
|
7
|
+
data.tar.gz: 2b05b93835b83052a89127f12db03fdcd79007b6b0f396134d9818352e48ffaf012057c0b818a56633f3e8b510e7861438e8016d2519bd4d0dec425dfd1113f7
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/bake/async/http/h2spec.rb
CHANGED
@@ -21,12 +21,12 @@ end
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def server
|
24
|
-
require
|
25
|
-
require
|
26
|
-
require
|
27
|
-
require
|
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(
|
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, {
|
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-
|
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
|
11
|
-
require
|
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)
|
@@ -0,0 +1,56 @@
|
|
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 Body
|
12
|
+
# Keeps track of whether a body is being read, and if so, waits for it to be closed.
|
13
|
+
class Finishable < ::Protocol::HTTP::Body::Wrapper
|
14
|
+
def initialize(body)
|
15
|
+
super(body)
|
16
|
+
|
17
|
+
@closed = Async::Variable.new
|
18
|
+
@error = nil
|
19
|
+
|
20
|
+
@reading = false
|
21
|
+
end
|
22
|
+
|
23
|
+
def reading?
|
24
|
+
@reading
|
25
|
+
end
|
26
|
+
|
27
|
+
def read
|
28
|
+
@reading = true
|
29
|
+
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def close(error = nil)
|
34
|
+
unless @closed.resolved?
|
35
|
+
@error = error
|
36
|
+
@closed.value = true
|
37
|
+
end
|
38
|
+
|
39
|
+
super
|
40
|
+
end
|
41
|
+
|
42
|
+
def wait
|
43
|
+
if @reading
|
44
|
+
@closed.wait
|
45
|
+
else
|
46
|
+
self.discard
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
"#<#{self.class} closed=#{@closed} error=#{@error}> | #{super}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2019-
|
4
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "protocol/http/body/readable"
|
7
|
+
require "protocol/http/body/stream"
|
8
8
|
|
9
|
-
require_relative
|
9
|
+
require_relative "writable"
|
10
10
|
|
11
11
|
module Async
|
12
12
|
module HTTP
|
data/lib/async/http/body/pipe.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "protocol/http/body/writable"
|
7
|
+
require "async/queue"
|
8
8
|
|
9
9
|
module Async
|
10
10
|
module HTTP
|
data/lib/async/http/body.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
7
|
-
require_relative
|
6
|
+
require "protocol/http/body/buffered"
|
7
|
+
require_relative "body/writable"
|
8
8
|
|
9
9
|
module Async
|
10
10
|
module HTTP
|
data/lib/async/http/client.rb
CHANGED
@@ -4,16 +4,17 @@
|
|
4
4
|
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2022, by Ian Ker-Seymer.
|
6
6
|
|
7
|
-
require
|
7
|
+
require "io/endpoint"
|
8
8
|
|
9
|
-
require
|
9
|
+
require "async/pool/controller"
|
10
10
|
|
11
|
-
require
|
12
|
-
require
|
11
|
+
require "protocol/http/body/completable"
|
12
|
+
require "protocol/http/methods"
|
13
13
|
|
14
|
-
require
|
14
|
+
require "traces/provider"
|
15
15
|
|
16
|
-
require_relative
|
16
|
+
require_relative "protocol"
|
17
|
+
require_relative "body/finishable"
|
17
18
|
|
18
19
|
module Async
|
19
20
|
module HTTP
|
@@ -140,7 +141,7 @@ module Async
|
|
140
141
|
def inspect
|
141
142
|
"#<#{self.class} authority=#{@authority.inspect}>"
|
142
143
|
end
|
143
|
-
|
144
|
+
|
144
145
|
Traces::Provider(self) do
|
145
146
|
def call(request)
|
146
147
|
attributes = {
|
@@ -151,30 +152,30 @@ module Async
|
|
151
152
|
}
|
152
153
|
|
153
154
|
if protocol = request.protocol
|
154
|
-
attributes[
|
155
|
+
attributes["http.protocol"] = protocol
|
155
156
|
end
|
156
157
|
|
157
158
|
if length = request.body&.length
|
158
|
-
attributes[
|
159
|
+
attributes["http.request.length"] = length
|
159
160
|
end
|
160
161
|
|
161
|
-
Traces.trace(
|
162
|
+
Traces.trace("async.http.client.call", attributes: attributes) do |span|
|
162
163
|
if context = Traces.trace_context
|
163
|
-
request.headers[
|
164
|
+
request.headers["traceparent"] = context.to_s
|
164
165
|
# request.headers['tracestate'] = context.state
|
165
166
|
end
|
166
167
|
|
167
168
|
super.tap do |response|
|
168
169
|
if version = response&.version
|
169
|
-
span[
|
170
|
+
span["http.version"] = version
|
170
171
|
end
|
171
172
|
|
172
173
|
if status = response&.status
|
173
|
-
span[
|
174
|
+
span["http.status_code"] = status
|
174
175
|
end
|
175
176
|
|
176
177
|
if length = response.body&.length
|
177
|
-
span[
|
178
|
+
span["http.response.length"] = length
|
178
179
|
end
|
179
180
|
end
|
180
181
|
end
|
@@ -186,10 +187,7 @@ module Async
|
|
186
187
|
def make_response(request, connection)
|
187
188
|
response = request.call(connection)
|
188
189
|
|
189
|
-
|
190
|
-
::Protocol::HTTP::Body::Completable.wrap(response) do
|
191
|
-
@pool.release(connection)
|
192
|
-
end
|
190
|
+
response.pool = @pool
|
193
191
|
|
194
192
|
return response
|
195
193
|
end
|
data/lib/async/http/endpoint.rb
CHANGED
@@ -7,22 +7,22 @@
|
|
7
7
|
# Copyright, 2024, by Igor Sidorov.
|
8
8
|
# Copyright, 2024, by Hal Brodigan.
|
9
9
|
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
10
|
+
require "io/endpoint"
|
11
|
+
require "io/endpoint/host_endpoint"
|
12
|
+
require "io/endpoint/ssl_endpoint"
|
13
13
|
|
14
|
-
require_relative
|
15
|
-
require_relative
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
[
|
105
|
+
["https", "wss"].include?(self.scheme)
|
106
106
|
end
|
107
107
|
|
108
108
|
def protocol
|
data/lib/async/http/internet.rb
CHANGED
@@ -4,12 +4,12 @@
|
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2024, by Igor Sidorov.
|
6
6
|
|
7
|
-
require_relative
|
8
|
-
require_relative
|
7
|
+
require_relative "client"
|
8
|
+
require_relative "endpoint"
|
9
9
|
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
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
|
6
|
+
require_relative "../reference"
|
7
7
|
|
8
|
-
require
|
9
|
-
require
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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[
|
94
|
+
unless location = response.headers["location"]
|
95
95
|
return response
|
96
96
|
end
|
97
97
|
|
data/lib/async/http/mock.rb
CHANGED
@@ -3,18 +3,32 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
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
|
-
|
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
|
6
|
+
require "protocol/http1"
|
7
7
|
|
8
|
-
require_relative
|
9
|
-
require_relative
|
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},
|
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
|
-
|
64
|
+
self.idle? && @stream&.readable?
|
66
65
|
end
|
67
66
|
|
68
67
|
def reusable?
|
69
|
-
@
|
68
|
+
@persistent && @stream && !@stream.closed?
|
70
69
|
end
|
71
70
|
end
|
72
71
|
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
|
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 =
|
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(
|
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
|
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 =
|
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,8 +6,10 @@
|
|
6
6
|
# Copyright, 2023, by Thomas Morgan.
|
7
7
|
# Copyright, 2024, by Anton Zhuravsky.
|
8
8
|
|
9
|
-
require_relative
|
10
|
-
|
9
|
+
require_relative "connection"
|
10
|
+
require_relative "../../body/finishable"
|
11
|
+
|
12
|
+
require "console/event/failure"
|
11
13
|
|
12
14
|
module Async
|
13
15
|
module HTTP
|
@@ -20,7 +22,7 @@ module Async
|
|
20
22
|
write_body(@version, nil)
|
21
23
|
rescue => error
|
22
24
|
# 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
|
25
|
+
Console::Event::Failure.for(error).emit(self, "Failed to write failure response!", severity: :debug)
|
24
26
|
end
|
25
27
|
|
26
28
|
def next_request
|
@@ -35,7 +37,7 @@ module Async
|
|
35
37
|
end
|
36
38
|
|
37
39
|
return request
|
38
|
-
rescue ::Protocol::HTTP1::BadRequest
|
40
|
+
rescue ::Protocol::HTTP1::BadRequest => error
|
39
41
|
fail_request(400)
|
40
42
|
# Conceivably we could retry here, but we don't really know how bad the error is, so it's better to just fail:
|
41
43
|
raise
|
@@ -46,7 +48,13 @@ module Async
|
|
46
48
|
task.annotate("Reading #{self.version} requests for #{self.class}.")
|
47
49
|
|
48
50
|
while request = next_request
|
51
|
+
if body = request.body
|
52
|
+
finishable = Body::Finishable.new(body)
|
53
|
+
request.body = finishable
|
54
|
+
end
|
55
|
+
|
49
56
|
response = yield(request, self)
|
57
|
+
version = request.version
|
50
58
|
body = response&.body
|
51
59
|
|
52
60
|
if hijacked?
|
@@ -77,7 +85,7 @@ module Async
|
|
77
85
|
# 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
86
|
write_response(@version, response.status, response.headers)
|
79
87
|
|
80
|
-
stream = write_tunnel_body(
|
88
|
+
stream = write_tunnel_body(version)
|
81
89
|
|
82
90
|
# Same as above:
|
83
91
|
request = nil
|
@@ -89,7 +97,7 @@ module Async
|
|
89
97
|
write_response(@version, response.status, response.headers)
|
90
98
|
|
91
99
|
if request.connect? and response.success?
|
92
|
-
stream = write_tunnel_body(
|
100
|
+
stream = write_tunnel_body(version)
|
93
101
|
|
94
102
|
# Same as above:
|
95
103
|
request = nil
|
@@ -99,26 +107,26 @@ module Async
|
|
99
107
|
return body.call(stream)
|
100
108
|
else
|
101
109
|
head = request.head?
|
102
|
-
version = request.version
|
103
110
|
|
104
111
|
# Same as above:
|
105
|
-
request = nil
|
112
|
+
request = nil
|
106
113
|
response = nil
|
107
114
|
|
108
115
|
write_body(version, body, head, trailer)
|
109
116
|
end
|
110
117
|
end
|
111
118
|
|
112
|
-
# We are done with the body
|
119
|
+
# We are done with the body:
|
113
120
|
body = nil
|
114
121
|
else
|
115
122
|
# If the request failed to generate a response, it was an internal server error:
|
116
123
|
write_response(@version, 500, {})
|
117
|
-
write_body(
|
124
|
+
write_body(version, nil)
|
125
|
+
|
126
|
+
request&.finish
|
118
127
|
end
|
119
128
|
|
120
|
-
|
121
|
-
request&.each{}
|
129
|
+
finishable&.wait
|
122
130
|
|
123
131
|
# This ensures we yield at least once every iteration of the loop and allow other fibers to execute.
|
124
132
|
task.yield
|
@@ -4,10 +4,10 @@
|
|
4
4
|
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2024, by Thomas Morgan.
|
6
6
|
|
7
|
-
require_relative
|
8
|
-
require_relative
|
7
|
+
require_relative "http1/client"
|
8
|
+
require_relative "http1/server"
|
9
9
|
|
10
|
-
require
|
10
|
+
require "io/stream"
|
11
11
|
|
12
12
|
module Async
|
13
13
|
module HTTP
|
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "connection"
|
7
|
+
require_relative "response"
|
8
8
|
|
9
|
-
require
|
9
|
+
require "protocol/http2/client"
|
10
10
|
|
11
11
|
module Async
|
12
12
|
module HTTP
|
@@ -4,25 +4,25 @@
|
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2020, by Bruno Sutic.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "stream"
|
8
8
|
|
9
|
-
require
|
9
|
+
require "async/semaphore"
|
10
10
|
|
11
11
|
module Async
|
12
12
|
module HTTP
|
13
13
|
module Protocol
|
14
14
|
module HTTP2
|
15
|
-
HTTPS =
|
16
|
-
SCHEME =
|
17
|
-
METHOD =
|
18
|
-
PATH =
|
19
|
-
AUTHORITY =
|
20
|
-
STATUS =
|
21
|
-
PROTOCOL =
|
15
|
+
HTTPS = "https".freeze
|
16
|
+
SCHEME = ":scheme".freeze
|
17
|
+
METHOD = ":method".freeze
|
18
|
+
PATH = ":path".freeze
|
19
|
+
AUTHORITY = ":authority".freeze
|
20
|
+
STATUS = ":status".freeze
|
21
|
+
PROTOCOL = ":protocol".freeze
|
22
22
|
|
23
|
-
CONTENT_LENGTH =
|
24
|
-
CONNECTION =
|
25
|
-
TRAILER =
|
23
|
+
CONTENT_LENGTH = "content-length".freeze
|
24
|
+
CONNECTION = "connection".freeze
|
25
|
+
TRAILER = "trailer".freeze
|
26
26
|
|
27
27
|
module Connection
|
28
28
|
def initialize(*)
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2020-
|
4
|
+
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
6
|
+
require "protocol/http/body/writable"
|
7
7
|
|
8
8
|
module Async
|
9
9
|
module HTTP
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2020-
|
4
|
+
# Copyright, 2020-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
6
|
+
require "protocol/http/body/stream"
|
7
7
|
|
8
8
|
module Async
|
9
9
|
module HTTP
|
@@ -3,8 +3,8 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "../request"
|
7
|
+
require_relative "stream"
|
8
8
|
|
9
9
|
module Async
|
10
10
|
module HTTP
|
@@ -53,7 +53,7 @@ module Async
|
|
53
53
|
@length = Integer(value)
|
54
54
|
elsif key == CONNECTION
|
55
55
|
raise ::Protocol::HTTP2::HeaderError, "Connection header is not allowed!"
|
56
|
-
elsif key.start_with?
|
56
|
+
elsif key.start_with? ":"
|
57
57
|
raise ::Protocol::HTTP2::HeaderError, "Invalid pseudo-header #{key}!"
|
58
58
|
elsif key =~ /[A-Z]/
|
59
59
|
raise ::Protocol::HTTP2::HeaderError, "Invalid characters in header #{key}!"
|
@@ -107,7 +107,7 @@ module Async
|
|
107
107
|
end
|
108
108
|
|
109
109
|
NO_RESPONSE = [
|
110
|
-
[STATUS,
|
110
|
+
[STATUS, "500"],
|
111
111
|
]
|
112
112
|
|
113
113
|
def send_response(response)
|
@@ -3,8 +3,8 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "../response"
|
7
|
+
require_relative "stream"
|
8
8
|
|
9
9
|
module Async
|
10
10
|
module HTTP
|
@@ -41,7 +41,7 @@ module Async
|
|
41
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
42
|
status_header = headers.shift
|
43
43
|
|
44
|
-
if status_header.first !=
|
44
|
+
if status_header.first != ":status"
|
45
45
|
raise ProtocolError, "Invalid response headers: #{headers.inspect}"
|
46
46
|
end
|
47
47
|
|
@@ -137,6 +137,16 @@ module Async
|
|
137
137
|
attr :stream
|
138
138
|
attr :request
|
139
139
|
|
140
|
+
def pool=(pool)
|
141
|
+
# If we are already closed, the stream can be released now:
|
142
|
+
if @stream.closed?
|
143
|
+
pool.release(@stream.connection)
|
144
|
+
else
|
145
|
+
# Otherwise, we will release the stream when it is closed:
|
146
|
+
@stream.pool = pool
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
140
150
|
def connection
|
141
151
|
@stream.connection
|
142
152
|
end
|
@@ -175,7 +185,7 @@ module Async
|
|
175
185
|
raise ::Protocol::HTTP2::HeaderError, "Request path already specified!" if request.path
|
176
186
|
|
177
187
|
request.path = value
|
178
|
-
elsif key.start_with?
|
188
|
+
elsif key.start_with? ":"
|
179
189
|
raise ::Protocol::HTTP2::HeaderError, "Invalid pseudo-header #{key}!"
|
180
190
|
else
|
181
191
|
request.headers[key] = value
|
@@ -3,10 +3,10 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "connection"
|
7
|
+
require_relative "request"
|
8
8
|
|
9
|
-
require
|
9
|
+
require "protocol/http2/server"
|
10
10
|
|
11
11
|
module Async
|
12
12
|
module HTTP
|
@@ -5,10 +5,10 @@
|
|
5
5
|
# Copyright, 2022, by Marco Concetto Rudilosso.
|
6
6
|
# Copyright, 2023, by Thomas Morgan.
|
7
7
|
|
8
|
-
require
|
8
|
+
require "protocol/http2/stream"
|
9
9
|
|
10
|
-
require_relative
|
11
|
-
require_relative
|
10
|
+
require_relative "input"
|
11
|
+
require_relative "output"
|
12
12
|
|
13
13
|
module Async
|
14
14
|
module HTTP
|
@@ -20,6 +20,8 @@ module Async
|
|
20
20
|
|
21
21
|
@headers = nil
|
22
22
|
|
23
|
+
@pool = nil
|
24
|
+
|
23
25
|
# Input buffer, reading request body, or response body (receive_data):
|
24
26
|
@length = nil
|
25
27
|
@input = nil
|
@@ -30,12 +32,14 @@ module Async
|
|
30
32
|
|
31
33
|
attr_accessor :headers
|
32
34
|
|
35
|
+
attr_accessor :pool
|
36
|
+
|
33
37
|
attr :input
|
34
38
|
|
35
39
|
def add_header(key, value)
|
36
40
|
if key == CONNECTION
|
37
41
|
raise ::Protocol::HTTP2::HeaderError, "Connection header is not allowed!"
|
38
|
-
elsif key.start_with?
|
42
|
+
elsif key.start_with? ":"
|
39
43
|
raise ::Protocol::HTTP2::HeaderError, "Invalid pseudo-header #{key}!"
|
40
44
|
elsif key =~ /[A-Z]/
|
41
45
|
raise ::Protocol::HTTP2::HeaderError, "Invalid upper-case characters in header #{key}!"
|
@@ -158,6 +162,10 @@ module Async
|
|
158
162
|
@output = nil
|
159
163
|
end
|
160
164
|
|
165
|
+
if pool = @pool and @connection
|
166
|
+
pool.release(@connection)
|
167
|
+
end
|
168
|
+
|
161
169
|
return self
|
162
170
|
end
|
163
171
|
end
|
@@ -4,10 +4,10 @@
|
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2024, by Thomas Morgan.
|
6
6
|
|
7
|
-
require_relative
|
8
|
-
require_relative
|
7
|
+
require_relative "http2/client"
|
8
|
+
require_relative "http2/server"
|
9
9
|
|
10
|
-
require
|
10
|
+
require "io/stream"
|
11
11
|
|
12
12
|
module Async
|
13
13
|
module HTTP
|
@@ -4,10 +4,10 @@
|
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2019, by Brian Morearty.
|
6
6
|
|
7
|
-
require_relative
|
8
|
-
require_relative
|
7
|
+
require_relative "http10"
|
8
|
+
require_relative "http11"
|
9
9
|
|
10
|
-
require_relative
|
10
|
+
require_relative "http2"
|
11
11
|
|
12
12
|
module Async
|
13
13
|
module HTTP
|
@@ -3,10 +3,10 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "protocol/http/request"
|
7
|
+
require "protocol/http/headers"
|
8
8
|
|
9
|
-
require_relative
|
9
|
+
require_relative "../body/writable"
|
10
10
|
|
11
11
|
module Async
|
12
12
|
module HTTP
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2017-
|
4
|
+
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
6
|
+
require "protocol/http/response"
|
7
7
|
|
8
|
-
require_relative
|
8
|
+
require_relative "../body/writable"
|
9
9
|
|
10
10
|
module Async
|
11
11
|
module HTTP
|
data/lib/async/http/protocol.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2017-
|
4
|
+
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "protocol/http1"
|
7
|
+
require_relative "protocol/https"
|
8
8
|
|
9
9
|
module Async
|
10
10
|
module HTTP
|
data/lib/async/http/proxy.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
7
|
-
require_relative
|
6
|
+
require_relative "client"
|
7
|
+
require_relative "endpoint"
|
8
8
|
|
9
|
-
require_relative
|
9
|
+
require_relative "body/pipe"
|
10
10
|
|
11
11
|
module Async
|
12
12
|
module HTTP
|
@@ -96,6 +96,7 @@ module Async
|
|
96
96
|
end
|
97
97
|
else
|
98
98
|
# This ensures we don't leave a response dangling:
|
99
|
+
input.close
|
99
100
|
response.close
|
100
101
|
|
101
102
|
raise ConnectFailure, response
|
data/lib/async/http/reference.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
6
|
+
require "protocol/http/reference"
|
7
7
|
|
8
8
|
module Async
|
9
9
|
module HTTP
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2019-2020, by Brian Morearty.
|
6
6
|
|
7
|
-
require_relative
|
7
|
+
require_relative "middleware/location_redirector"
|
8
8
|
|
9
9
|
warn "`Async::HTTP::RelativeLocation` is deprecated and will be removed in the next release. Please use `Async::HTTP::Middleware::LocationRedirector` instead.", uplevel: 1
|
10
10
|
|
data/lib/async/http/server.rb
CHANGED
@@ -4,12 +4,12 @@
|
|
4
4
|
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
# Copyright, 2019, by Brian Morearty.
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
7
|
+
require "async"
|
8
|
+
require "io/endpoint"
|
9
|
+
require "protocol/http/middleware"
|
10
|
+
require "traces/provider"
|
11
11
|
|
12
|
-
require_relative
|
12
|
+
require_relative "protocol"
|
13
13
|
|
14
14
|
module Async
|
15
15
|
module HTTP
|
@@ -76,8 +76,8 @@ module Async
|
|
76
76
|
|
77
77
|
Traces::Provider(self) do
|
78
78
|
def call(request)
|
79
|
-
if trace_parent = request.headers[
|
80
|
-
Traces.trace_context = Traces::Context.parse(trace_parent.join, request.headers[
|
79
|
+
if trace_parent = request.headers["traceparent"]
|
80
|
+
Traces.trace_context = Traces::Context.parse(trace_parent.join, request.headers["tracestate"], remote: true)
|
81
81
|
end
|
82
82
|
|
83
83
|
attributes = {
|
@@ -86,25 +86,25 @@ module Async
|
|
86
86
|
'http.authority': request.authority,
|
87
87
|
'http.scheme': request.scheme,
|
88
88
|
'http.path': request.path,
|
89
|
-
'http.user_agent': request.headers[
|
89
|
+
'http.user_agent': request.headers["user-agent"],
|
90
90
|
}
|
91
91
|
|
92
92
|
if length = request.body&.length
|
93
|
-
attributes[
|
93
|
+
attributes["http.request.length"] = length
|
94
94
|
end
|
95
95
|
|
96
96
|
if protocol = request.protocol
|
97
|
-
attributes[
|
97
|
+
attributes["http.protocol"] = protocol
|
98
98
|
end
|
99
99
|
|
100
|
-
Traces.trace(
|
100
|
+
Traces.trace("async.http.server.call", resource: "#{request.method} #{request.path}", attributes: attributes) do |span|
|
101
101
|
super.tap do |response|
|
102
102
|
if status = response&.status
|
103
|
-
span[
|
103
|
+
span["http.status_code"] = status
|
104
104
|
end
|
105
105
|
|
106
106
|
if length = response&.body&.length
|
107
|
-
span[
|
107
|
+
span["http.response.length"] = length
|
108
108
|
end
|
109
109
|
end
|
110
110
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2018-
|
4
|
+
# Copyright, 2018-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require
|
6
|
+
require "protocol/http/body/wrapper"
|
7
7
|
|
8
|
-
require
|
8
|
+
require "async/clock"
|
9
9
|
|
10
10
|
module Async
|
11
11
|
module HTTP
|
@@ -89,7 +89,7 @@ module Async
|
|
89
89
|
parts << "took #{format_duration(duration)} until first chunk"
|
90
90
|
end
|
91
91
|
|
92
|
-
return parts.join(
|
92
|
+
return parts.join("; ")
|
93
93
|
end
|
94
94
|
|
95
95
|
def inspect
|
data/lib/async/http/version.rb
CHANGED
data/lib/async/http.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2017-2024, by Samuel Williams.
|
5
5
|
|
6
|
-
require_relative
|
6
|
+
require_relative "http/version"
|
7
7
|
|
8
|
-
require_relative
|
9
|
-
require_relative
|
8
|
+
require_relative "http/client"
|
9
|
+
require_relative "http/server"
|
10
10
|
|
11
|
-
require_relative
|
11
|
+
require_relative "http/internet"
|
12
12
|
|
13
|
-
require_relative
|
13
|
+
require_relative "http/endpoint"
|
data/readme.md
CHANGED
@@ -16,6 +16,17 @@ Please see the [project documentation](https://socketry.github.io/async-http/) f
|
|
16
16
|
|
17
17
|
Please see the [project releases](https://socketry.github.io/async-http/releases/index) for all releases.
|
18
18
|
|
19
|
+
### v0.77.0
|
20
|
+
|
21
|
+
- Improved HTTP/1 connection handling.
|
22
|
+
- The input stream is no longer closed when the output stream is closed.
|
23
|
+
|
24
|
+
### v0.76.0
|
25
|
+
|
26
|
+
- `Async::HTTP::Body::Writable` is moved to `Protocol::HTTP::Body::Writable`.
|
27
|
+
- Remove `Async::HTTP::Body::Delayed` with no replacement.
|
28
|
+
- Remove `Async::HTTP::Body::Slowloris` with no replacement.
|
29
|
+
|
19
30
|
### v0.75.0
|
20
31
|
|
21
32
|
- Better handling of HTTP/1 \<-\> HTTP/2 proxying, specifically upgrade/CONNECT requests.
|
data/releases.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Releases
|
2
2
|
|
3
|
+
## v0.77.0
|
4
|
+
|
5
|
+
- Improved HTTP/1 connection handling.
|
6
|
+
- The input stream is no longer closed when the output stream is closed.
|
7
|
+
|
8
|
+
## v0.76.0
|
9
|
+
|
10
|
+
- `Async::HTTP::Body::Writable` is moved to `Protocol::HTTP::Body::Writable`.
|
11
|
+
- Remove `Async::HTTP::Body::Delayed` with no replacement.
|
12
|
+
- Remove `Async::HTTP::Body::Slowloris` with no replacement.
|
13
|
+
|
3
14
|
## v0.75.0
|
4
15
|
|
5
16
|
- Better handling of HTTP/1 \<-\> HTTP/2 proxying, specifically upgrade/CONNECT requests.
|
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.
|
4
|
+
version: 0.77.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-
|
61
|
+
date: 2024-09-19 00:00:00.000000000 Z
|
62
62
|
dependencies:
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
64
|
name: async
|
@@ -122,28 +122,28 @@ dependencies:
|
|
122
122
|
requirements:
|
123
123
|
- - "~>"
|
124
124
|
- !ruby/object:Gem::Version
|
125
|
-
version: '0.
|
125
|
+
version: '0.37'
|
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.
|
132
|
+
version: '0.37'
|
133
133
|
- !ruby/object:Gem::Dependency
|
134
134
|
name: protocol-http1
|
135
135
|
requirement: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
137
|
- - "~>"
|
138
138
|
- !ruby/object:Gem::Version
|
139
|
-
version: '0.
|
139
|
+
version: '0.25'
|
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.
|
146
|
+
version: '0.25'
|
147
147
|
- !ruby/object:Gem::Dependency
|
148
148
|
name: protocol-http2
|
149
149
|
requirement: !ruby/object:Gem::Requirement
|
@@ -182,6 +182,7 @@ files:
|
|
182
182
|
- bake/async/http/h2spec.rb
|
183
183
|
- lib/async/http.rb
|
184
184
|
- lib/async/http/body.rb
|
185
|
+
- lib/async/http/body/finishable.rb
|
185
186
|
- lib/async/http/body/hijack.rb
|
186
187
|
- lib/async/http/body/pipe.rb
|
187
188
|
- lib/async/http/body/writable.rb
|
metadata.gz.sig
CHANGED
Binary file
|