async-http 0.101.0 → 0.102.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/context/choosing-a-client.md +164 -0
- data/context/concurrent-requests.md +134 -0
- data/context/getting-started.md +106 -69
- data/context/index.yaml +14 -3
- data/context/testing.md +173 -45
- data/lib/async/http/body/hijack.rb +1 -1
- data/lib/async/http/body/pipe.rb +2 -2
- data/lib/async/http/body.rb +1 -1
- data/lib/async/http/internet.rb +1 -1
- data/lib/async/http/middleware/location_redirector.rb +1 -1
- data/lib/async/http/mock/endpoint.rb +1 -1
- data/lib/async/http/protocol/configurable.rb +1 -1
- data/lib/async/http/protocol/http.rb +1 -1
- data/lib/async/http/protocol/http1/finishable.rb +2 -1
- data/lib/async/http/protocol/http1/request.rb +1 -1
- data/lib/async/http/protocol/http1/response.rb +1 -1
- data/lib/async/http/protocol/http1.rb +1 -1
- 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 +7 -2
- data/lib/async/http/protocol/http2/connection.rb +20 -6
- data/lib/async/http/protocol/http2/input.rb +14 -3
- data/lib/async/http/protocol/http2/output.rb +23 -8
- data/lib/async/http/protocol/http2/response.rb +15 -2
- data/lib/async/http/protocol/http2/server.rb +1 -1
- data/lib/async/http/protocol/http2/stream.rb +61 -4
- data/lib/async/http/protocol/http2.rb +1 -1
- data/lib/async/http/protocol/request.rb +1 -1
- data/lib/async/http/protocol/response.rb +1 -1
- data/lib/async/http/proxy.rb +1 -1
- data/lib/async/http/statistics.rb +1 -1
- data/lib/async/http/version.rb +1 -1
- data/lib/async/http.rb +1 -1
- data/lib/traces/provider/async/http/client.rb +1 -1
- data/lib/traces/provider/async/http/protocol/http1/client.rb +1 -1
- data/lib/traces/provider/async/http/protocol/http2/client.rb +1 -1
- data/lib/traces/provider/async/http/server.rb +1 -1
- data/license.md +2 -1
- data/readme.md +18 -13
- data/releases.md +5 -0
- data.tar.gz.sig +0 -0
- metadata +11 -6
- metadata.gz.sig +0 -0
|
@@ -28,6 +28,9 @@ module Async
|
|
|
28
28
|
@length = nil
|
|
29
29
|
@input = nil
|
|
30
30
|
|
|
31
|
+
# The application can close its input before the peer finishes sending. HTTP/2 cannot close only the receiving side of a stream, so incoming data is discarded until local output also finishes. At that point, a no-error reset terminates the remaining wire stream.
|
|
32
|
+
@input_closed = false
|
|
33
|
+
|
|
31
34
|
# Output buffer, writing request body or response body (window_updated):
|
|
32
35
|
@output = nil
|
|
33
36
|
end
|
|
@@ -114,14 +117,17 @@ module Async
|
|
|
114
117
|
def process_data(frame)
|
|
115
118
|
data = frame.unpack
|
|
116
119
|
|
|
117
|
-
if @input
|
|
120
|
+
if input = @input
|
|
118
121
|
unless data.empty?
|
|
119
|
-
|
|
122
|
+
input.write(data)
|
|
120
123
|
end
|
|
121
124
|
|
|
122
125
|
if frame.end_stream?
|
|
123
|
-
|
|
126
|
+
input.close_write
|
|
124
127
|
end
|
|
128
|
+
else
|
|
129
|
+
# The application has closed the input, so discard incoming data while maintaining flow control for the stream.
|
|
130
|
+
request_window_update
|
|
125
131
|
end
|
|
126
132
|
|
|
127
133
|
return data
|
|
@@ -131,6 +137,22 @@ module Async
|
|
|
131
137
|
send_reset_stream(::Protocol::HTTP2::Error::INTERNAL_ERROR)
|
|
132
138
|
end
|
|
133
139
|
|
|
140
|
+
# Close the application-facing receiving side of the stream. While local output remains active, incoming data is discarded with flow-control updates. Once local output is also closed, the remaining wire stream is terminated without an error.
|
|
141
|
+
# @parameter input [Input] The input body being closed.
|
|
142
|
+
# @parameter error [Exception | Nil] The error which closed the input.
|
|
143
|
+
def finish_input(input, error = nil)
|
|
144
|
+
if @input.equal?(input)
|
|
145
|
+
@input = nil
|
|
146
|
+
@input_closed = true
|
|
147
|
+
|
|
148
|
+
if error
|
|
149
|
+
send_reset_stream(::Protocol::HTTP2::Error::INTERNAL_ERROR)
|
|
150
|
+
else
|
|
151
|
+
close_if_finished
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
134
156
|
# Set the body and begin sending it.
|
|
135
157
|
def send_body(body, trailer = nil)
|
|
136
158
|
@output = Output.new(self, body, trailer)
|
|
@@ -169,11 +191,32 @@ module Async
|
|
|
169
191
|
return true
|
|
170
192
|
end
|
|
171
193
|
|
|
194
|
+
# Send headers and apply any pending application-side closure.
|
|
195
|
+
def send_headers(...)
|
|
196
|
+
result = super
|
|
197
|
+
close_if_finished
|
|
198
|
+
return result
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Send data and apply any pending application-side closure.
|
|
202
|
+
def send_data(...)
|
|
203
|
+
result = super
|
|
204
|
+
close_if_finished
|
|
205
|
+
return result
|
|
206
|
+
end
|
|
207
|
+
|
|
172
208
|
# When the stream transitions to the closed state, this method is called. There are roughly two ways this can happen:
|
|
173
209
|
# - A frame is received which causes this stream to enter the closed state. This method will be invoked from the background reader task.
|
|
174
210
|
# - A frame is sent which causes this stream to enter the closed state. This method will be invoked from that task.
|
|
175
211
|
# While the input stream is relatively straight forward, the output stream can trigger the second case above
|
|
176
212
|
def closed(error)
|
|
213
|
+
orderly_reset = error.is_a?(::Protocol::HTTP2::StreamError) &&
|
|
214
|
+
error.code == ::Protocol::HTTP2::Error::NO_ERROR
|
|
215
|
+
|
|
216
|
+
if orderly_reset
|
|
217
|
+
error = nil
|
|
218
|
+
end
|
|
219
|
+
|
|
177
220
|
super
|
|
178
221
|
|
|
179
222
|
if input = @input
|
|
@@ -183,7 +226,12 @@ module Async
|
|
|
183
226
|
|
|
184
227
|
if output = @output
|
|
185
228
|
@output = nil
|
|
186
|
-
|
|
229
|
+
|
|
230
|
+
if orderly_reset
|
|
231
|
+
output.close_stream
|
|
232
|
+
else
|
|
233
|
+
output.stop(error)
|
|
234
|
+
end
|
|
187
235
|
end
|
|
188
236
|
|
|
189
237
|
if pool = @pool and @connection
|
|
@@ -192,6 +240,15 @@ module Async
|
|
|
192
240
|
|
|
193
241
|
return self
|
|
194
242
|
end
|
|
243
|
+
|
|
244
|
+
private
|
|
245
|
+
|
|
246
|
+
# If both application-facing directions are closed but the peer has not finished, terminate the remaining wire stream without an error.
|
|
247
|
+
def close_if_finished
|
|
248
|
+
if @input_closed && @state == :half_closed_local
|
|
249
|
+
send_reset_stream(::Protocol::HTTP2::Error::NO_ERROR)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
195
252
|
end
|
|
196
253
|
end
|
|
197
254
|
end
|
data/lib/async/http/proxy.rb
CHANGED
data/lib/async/http/version.rb
CHANGED
data/lib/async/http.rb
CHANGED
data/license.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Copyright, 2017-2026, by Samuel Williams.
|
|
4
4
|
Copyright, 2018, by Viacheslav Koval.
|
|
5
5
|
Copyright, 2018, by Janko Marohnić.
|
|
6
|
-
Copyright, 2019, by Denis Talakevich.
|
|
6
|
+
Copyright, 2019-2026, by Denis Talakevich.
|
|
7
7
|
Copyright, 2019-2020, by Brian Morearty.
|
|
8
8
|
Copyright, 2019, by Cyril Roelandt.
|
|
9
9
|
Copyright, 2020, by Stefan Wrobel.
|
|
@@ -25,6 +25,7 @@ Copyright, 2024, by Hal Brodigan.
|
|
|
25
25
|
Copyright, 2025, by Jean Boussier.
|
|
26
26
|
Copyright, 2025, by Yuuji Yaginuma.
|
|
27
27
|
Copyright, 2025, by William T. Nelson.
|
|
28
|
+
Copyright, 2026, by Jun Jiang.
|
|
28
29
|
|
|
29
30
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
30
31
|
of this software and associated documentation files (the "Software"), to deal
|
data/readme.md
CHANGED
|
@@ -8,14 +8,23 @@ An asynchronous client and server implementation of HTTP/1.0, HTTP/1.1 and HTTP/
|
|
|
8
8
|
|
|
9
9
|
Please see the [project documentation](https://socketry.github.io/async-http/) for more details.
|
|
10
10
|
|
|
11
|
-
- [Getting Started](https://socketry.github.io/async-http/guides/getting-started/index) - This guide explains how to
|
|
11
|
+
- [Getting Started](https://socketry.github.io/async-http/guides/getting-started/index) - This guide explains how to make HTTP requests and serve HTTP responses with `Async::HTTP`.
|
|
12
12
|
|
|
13
|
-
- [
|
|
13
|
+
- [Choosing a Client](https://socketry.github.io/async-http/guides/choosing-a-client/index) - This guide explains how to choose between ruby:`Async::HTTP::Internet`, ruby:`Async::HTTP::Client`, and higher-level interfaces for libraries.
|
|
14
|
+
|
|
15
|
+
- [Concurrent Requests and Connection Pooling](https://socketry.github.io/async-http/guides/concurrent-requests/index) - This guide explains how to run HTTP requests concurrently while keeping request fan-out, connection usage, and resource life cycles bounded.
|
|
16
|
+
|
|
17
|
+
- [Testing](https://socketry.github.io/async-http/guides/testing/index) - This guide explains how to test `Async::HTTP` clients and servers without depending on external HTTP services.
|
|
14
18
|
|
|
15
19
|
## Releases
|
|
16
20
|
|
|
17
21
|
Please see the [project releases](https://socketry.github.io/async-http/releases/index) for all releases.
|
|
18
22
|
|
|
23
|
+
### v0.102.0
|
|
24
|
+
|
|
25
|
+
- Requests assigned to an HTTP/2 connection which has already closed are refused before being written, allowing them to be retried safely.
|
|
26
|
+
- HTTP/2 connections which received a graceful `GOAWAY` are removed from availability immediately, but remain in the pool until the server has finished answering the streams it accepted. The connection is closed after its final user releases it, so those requests no longer fail with `EOFError: Connection closed with N active stream(s)!`.
|
|
27
|
+
|
|
19
28
|
### v0.101.0
|
|
20
29
|
|
|
21
30
|
- Handle remote disconnects in `Async::HTTP::Protocol::HTTP1::Server#each` without reporting them as server failures.
|
|
@@ -55,10 +64,6 @@ Please see the [project releases](https://socketry.github.io/async-http/releases
|
|
|
55
64
|
- HTTP/1: Delegate request write failure handling to `protocol-http1`.
|
|
56
65
|
- HTTP/2: Handle GOAWAY and REFUSED\_STREAM via `protocol-http2`, enabling automatic retry of unprocessed requests.
|
|
57
66
|
|
|
58
|
-
### v0.94.3
|
|
59
|
-
|
|
60
|
-
- Fix response body leak in HTTP/2 server when stream is reset before `send_response` completes (e.g. client-side gRPC cancellation). The response body's `close` was never called, leaking any resources tied to body lifecycle (such as `rack.response_finished` callbacks and utilization metrics).
|
|
61
|
-
|
|
62
67
|
## See Also
|
|
63
68
|
|
|
64
69
|
- [benchmark-http](https://github.com/socketry/benchmark-http) — A benchmarking tool to report on web server concurrency.
|
|
@@ -71,26 +76,26 @@ Please see the [project releases](https://socketry.github.io/async-http/releases
|
|
|
71
76
|
|
|
72
77
|
We welcome contributions to this project.
|
|
73
78
|
|
|
74
|
-
1. Fork
|
|
79
|
+
1. Fork the repository.
|
|
75
80
|
2. Create your feature branch (`git checkout -b my-new-feature`).
|
|
76
|
-
3. Commit your changes (`git commit -am 'Add some feature'`).
|
|
81
|
+
3. Commit your changes (`git commit -am 'Add some feature.'`).
|
|
77
82
|
4. Push to the branch (`git push origin my-new-feature`).
|
|
78
|
-
5. Create new
|
|
83
|
+
5. Create a new pull request.
|
|
79
84
|
|
|
80
85
|
### Running Tests
|
|
81
86
|
|
|
82
87
|
To run the test suite:
|
|
83
88
|
|
|
84
|
-
```
|
|
85
|
-
bundle exec sus
|
|
89
|
+
``` bash
|
|
90
|
+
$ bundle exec sus
|
|
86
91
|
```
|
|
87
92
|
|
|
88
93
|
### Making Releases
|
|
89
94
|
|
|
90
95
|
To make a new release:
|
|
91
96
|
|
|
92
|
-
```
|
|
93
|
-
bundle exec bake gem:release:patch # or minor or major
|
|
97
|
+
``` bash
|
|
98
|
+
$ bundle exec bake gem:release:patch # or minor or major
|
|
94
99
|
```
|
|
95
100
|
|
|
96
101
|
### Developer Certificate of Origin
|
data/releases.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.102.0
|
|
4
|
+
|
|
5
|
+
- Requests assigned to an HTTP/2 connection which has already closed are refused before being written, allowing them to be retried safely.
|
|
6
|
+
- HTTP/2 connections which received a graceful `GOAWAY` are removed from availability immediately, but remain in the pool until the server has finished answering the streams it accepted. The connection is closed after its final user releases it, so those requests no longer fail with `EOFError: Connection closed with N active stream(s)!`.
|
|
7
|
+
|
|
3
8
|
## v0.101.0
|
|
4
9
|
|
|
5
10
|
- Handle remote disconnects in `Async::HTTP::Protocol::HTTP1::Server#each` without reporting them as server failures.
|
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.102.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -10,15 +10,16 @@ authors:
|
|
|
10
10
|
- Janko Marohnić
|
|
11
11
|
- Thomas Morgan
|
|
12
12
|
- Adam Daniels
|
|
13
|
+
- Denis Talakevich
|
|
13
14
|
- Igor Sidorov
|
|
14
15
|
- William T. Nelson
|
|
15
16
|
- Anton Zhuravsky
|
|
16
17
|
- Cyril Roelandt
|
|
17
|
-
- Denis Talakevich
|
|
18
18
|
- Hal Brodigan
|
|
19
19
|
- Ian Ker-Seymer
|
|
20
20
|
- Jean Boussier
|
|
21
21
|
- Josh Huber
|
|
22
|
+
- Jun Jiang
|
|
22
23
|
- Marco Concetto Rudilosso
|
|
23
24
|
- Olle Jonsson
|
|
24
25
|
- Orgad Shaneh
|
|
@@ -82,14 +83,14 @@ dependencies:
|
|
|
82
83
|
requirements:
|
|
83
84
|
- - "~>"
|
|
84
85
|
- !ruby/object:Gem::Version
|
|
85
|
-
version: '0.
|
|
86
|
+
version: '0.12'
|
|
86
87
|
type: :runtime
|
|
87
88
|
prerelease: false
|
|
88
89
|
version_requirements: !ruby/object:Gem::Requirement
|
|
89
90
|
requirements:
|
|
90
91
|
- - "~>"
|
|
91
92
|
- !ruby/object:Gem::Version
|
|
92
|
-
version: '0.
|
|
93
|
+
version: '0.12'
|
|
93
94
|
- !ruby/object:Gem::Dependency
|
|
94
95
|
name: io-endpoint
|
|
95
96
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -152,14 +153,14 @@ dependencies:
|
|
|
152
153
|
requirements:
|
|
153
154
|
- - "~>"
|
|
154
155
|
- !ruby/object:Gem::Version
|
|
155
|
-
version: '0.
|
|
156
|
+
version: '0.27'
|
|
156
157
|
type: :runtime
|
|
157
158
|
prerelease: false
|
|
158
159
|
version_requirements: !ruby/object:Gem::Requirement
|
|
159
160
|
requirements:
|
|
160
161
|
- - "~>"
|
|
161
162
|
- !ruby/object:Gem::Version
|
|
162
|
-
version: '0.
|
|
163
|
+
version: '0.27'
|
|
163
164
|
- !ruby/object:Gem::Dependency
|
|
164
165
|
name: protocol-url
|
|
165
166
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -180,6 +181,8 @@ extra_rdoc_files: []
|
|
|
180
181
|
files:
|
|
181
182
|
- bake/async/http.rb
|
|
182
183
|
- bake/async/http/h2spec.rb
|
|
184
|
+
- context/choosing-a-client.md
|
|
185
|
+
- context/concurrent-requests.md
|
|
183
186
|
- context/getting-started.md
|
|
184
187
|
- context/index.yaml
|
|
185
188
|
- context/testing.md
|
|
@@ -240,6 +243,8 @@ homepage: https://github.com/socketry/async-http
|
|
|
240
243
|
licenses:
|
|
241
244
|
- MIT
|
|
242
245
|
metadata:
|
|
246
|
+
bug_tracker_uri: https://github.com/socketry/async-http/issues
|
|
247
|
+
changelog_uri: https://github.com/socketry/async-http/blob/main/releases.md
|
|
243
248
|
documentation_uri: https://socketry.github.io/async-http/
|
|
244
249
|
source_code_uri: https://github.com/socketry/async-http.git
|
|
245
250
|
rdoc_options: []
|
metadata.gz.sig
CHANGED
|
Binary file
|