async-http 0.77.0 → 0.79.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/lib/async/http/client.rb +0 -1
- data/lib/async/http/protocol/http1/client.rb +12 -9
- data/lib/async/http/protocol/http1/connection.rb +2 -0
- data/lib/async/http/protocol/http1/finishable.rb +62 -0
- data/lib/async/http/protocol/http1/server.rb +40 -20
- data/lib/async/http/protocol/http2/stream.rb +8 -6
- data/lib/async/http/protocol/request.rb +4 -0
- data/lib/async/http/protocol/response.rb +4 -0
- data/lib/async/http/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +7 -7
- metadata.gz.sig +0 -0
- data/lib/async/http/body/finishable.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93d3d9d22a84537ba522b417586a7bc02d243d56defe26fb9a3937470675b244
|
4
|
+
data.tar.gz: 8c16add5b2c301948235c739d076f92c400cdd745cc36881fac49125a41c5bc4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf362c7394967d2746e6d37984f25f5fc02e8e1fa89b7d5f6afcf31d87e665d75877cd5a9cd920f1ae87b6ecbc73e7d9b7cedc72467a69d95b5d24a04b897a8e
|
7
|
+
data.tar.gz: e922cf9cfd745423d9350f633d1a152dd8f6e06ae23abd3c8b1e403f49abb7089181aa68a1ded1a329cf2017b7bf98feb6a60fed45e1f8582eb3b01ca401ce4d
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/async/http/client.rb
CHANGED
@@ -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
|
-
|
71
|
-
|
72
|
-
|
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
|
@@ -0,0 +1,62 @@
|
|
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
|
+
super
|
36
|
+
|
37
|
+
unless @closed.resolved?
|
38
|
+
@error = error
|
39
|
+
@closed.value = true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def wait(persistent = true)
|
44
|
+
if @reading
|
45
|
+
@closed.wait
|
46
|
+
elsif persistent
|
47
|
+
# If the connection can be reused, let's gracefully discard the body:
|
48
|
+
self.discard
|
49
|
+
else
|
50
|
+
# Else, we don't care about the body, so we can close it immediately:
|
51
|
+
self.close
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def inspect
|
56
|
+
"#<#{self.class} closed=#{@closed} error=#{@error}> | #{super}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -7,7 +7,7 @@
|
|
7
7
|
# Copyright, 2024, by Anton Zhuravsky.
|
8
8
|
|
9
9
|
require_relative "connection"
|
10
|
-
require_relative "
|
10
|
+
require_relative "finishable"
|
11
11
|
|
12
12
|
require "console/event/failure"
|
13
13
|
|
@@ -16,6 +16,18 @@ module Async
|
|
16
16
|
module Protocol
|
17
17
|
module HTTP1
|
18
18
|
class Server < Connection
|
19
|
+
def initialize(...)
|
20
|
+
super
|
21
|
+
|
22
|
+
@ready = Async::Notification.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def closed(error = nil)
|
26
|
+
super
|
27
|
+
|
28
|
+
@ready.signal
|
29
|
+
end
|
30
|
+
|
19
31
|
def fail_request(status)
|
20
32
|
@persistent = false
|
21
33
|
write_response(@version, status, {})
|
@@ -26,8 +38,11 @@ module Async
|
|
26
38
|
end
|
27
39
|
|
28
40
|
def next_request
|
29
|
-
|
30
|
-
|
41
|
+
if closed?
|
42
|
+
return nil
|
43
|
+
elsif !idle?
|
44
|
+
@ready.wait
|
45
|
+
end
|
31
46
|
|
32
47
|
# Read an incoming request:
|
33
48
|
return unless request = Request.read(self)
|
@@ -49,7 +64,7 @@ module Async
|
|
49
64
|
|
50
65
|
while request = next_request
|
51
66
|
if body = request.body
|
52
|
-
finishable =
|
67
|
+
finishable = Finishable.new(body)
|
53
68
|
request.body = finishable
|
54
69
|
end
|
55
70
|
|
@@ -73,38 +88,41 @@ module Async
|
|
73
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:
|
74
89
|
write_response(@version, 101, response.headers)
|
75
90
|
|
76
|
-
stream = write_upgrade_body(protocol)
|
77
|
-
|
78
91
|
# At this point, the request body is hijacked, so we don't want to call #finish below.
|
79
92
|
request = nil
|
80
93
|
response = nil
|
81
94
|
|
82
|
-
|
83
|
-
|
95
|
+
if body.stream?
|
96
|
+
return body.call(write_upgrade_body(protocol))
|
97
|
+
else
|
98
|
+
write_upgrade_body(protocol, body)
|
99
|
+
end
|
84
100
|
elsif response.status == 101
|
85
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.
|
86
102
|
write_response(@version, response.status, response.headers)
|
87
103
|
|
88
|
-
stream = write_tunnel_body(version)
|
89
|
-
|
90
104
|
# Same as above:
|
91
105
|
request = nil
|
92
106
|
response = nil
|
93
107
|
|
94
|
-
|
95
|
-
|
108
|
+
if body.stream?
|
109
|
+
return body.call(write_tunnel_body(version))
|
110
|
+
else
|
111
|
+
write_tunnel_body(version, body)
|
112
|
+
end
|
96
113
|
else
|
97
114
|
write_response(@version, response.status, response.headers)
|
98
115
|
|
99
116
|
if request.connect? and response.success?
|
100
|
-
stream = write_tunnel_body(version)
|
101
|
-
|
102
117
|
# Same as above:
|
103
118
|
request = nil
|
104
119
|
response = nil
|
105
120
|
|
106
|
-
|
107
|
-
|
121
|
+
if body.stream?
|
122
|
+
return body.call(write_tunnel_body(version))
|
123
|
+
else
|
124
|
+
write_tunnel_body(version, body)
|
125
|
+
end
|
108
126
|
else
|
109
127
|
head = request.head?
|
110
128
|
|
@@ -126,10 +144,12 @@ module Async
|
|
126
144
|
request&.finish
|
127
145
|
end
|
128
146
|
|
129
|
-
finishable
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
133
153
|
rescue => error
|
134
154
|
raise
|
135
155
|
ensure
|
@@ -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
|
data/lib/async/http/version.rb
CHANGED
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.79.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-24 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.
|
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.
|
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.
|
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.
|
160
|
+
version: '0.19'
|
161
161
|
- !ruby/object:Gem::Dependency
|
162
162
|
name: traces
|
163
163
|
requirement: !ruby/object:Gem::Requirement
|
@@ -182,7 +182,6 @@ 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
|
186
185
|
- lib/async/http/body/hijack.rb
|
187
186
|
- lib/async/http/body/pipe.rb
|
188
187
|
- lib/async/http/body/writable.rb
|
@@ -198,6 +197,7 @@ files:
|
|
198
197
|
- lib/async/http/protocol/http1.rb
|
199
198
|
- lib/async/http/protocol/http1/client.rb
|
200
199
|
- lib/async/http/protocol/http1/connection.rb
|
200
|
+
- lib/async/http/protocol/http1/finishable.rb
|
201
201
|
- lib/async/http/protocol/http1/request.rb
|
202
202
|
- lib/async/http/protocol/http1/response.rb
|
203
203
|
- lib/async/http/protocol/http1/server.rb
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,56 +0,0 @@
|
|
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
|