async-http 0.94.2 → 0.94.3

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 (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/async/http/body/hijack.rb +17 -0
  4. data/lib/async/http/body/pipe.rb +3 -0
  5. data/lib/async/http/body.rb +3 -0
  6. data/lib/async/http/client.rb +16 -4
  7. data/lib/async/http/endpoint.rb +33 -0
  8. data/lib/async/http/internet.rb +7 -0
  9. data/lib/async/http/middleware/location_redirector.rb +9 -0
  10. data/lib/async/http/mock/endpoint.rb +10 -0
  11. data/lib/async/http/protocol/configurable.rb +15 -0
  12. data/lib/async/http/protocol/http1/client.rb +3 -0
  13. data/lib/async/http/protocol/http1/connection.rb +13 -0
  14. data/lib/async/http/protocol/http1/finishable.rb +9 -0
  15. data/lib/async/http/protocol/http1/request.rb +22 -0
  16. data/lib/async/http/protocol/http1/response.rb +10 -0
  17. data/lib/async/http/protocol/http1/server.rb +7 -0
  18. data/lib/async/http/protocol/http1.rb +1 -0
  19. data/lib/async/http/protocol/http10.rb +1 -0
  20. data/lib/async/http/protocol/http11.rb +1 -0
  21. data/lib/async/http/protocol/http2/client.rb +10 -0
  22. data/lib/async/http/protocol/http2/connection.rb +16 -0
  23. data/lib/async/http/protocol/http2/input.rb +5 -0
  24. data/lib/async/http/protocol/http2/output.rb +13 -0
  25. data/lib/async/http/protocol/http2/request.rb +17 -0
  26. data/lib/async/http/protocol/http2/response.rb +23 -0
  27. data/lib/async/http/protocol/http2/server.rb +16 -0
  28. data/lib/async/http/protocol/http2/stream.rb +19 -0
  29. data/lib/async/http/protocol/http2.rb +1 -0
  30. data/lib/async/http/protocol/https.rb +7 -0
  31. data/lib/async/http/protocol/request.rb +9 -1
  32. data/lib/async/http/protocol/response.rb +6 -1
  33. data/lib/async/http/proxy.rb +12 -0
  34. data/lib/async/http/server.rb +14 -0
  35. data/lib/async/http/statistics.rb +19 -0
  36. data/lib/async/http/version.rb +3 -1
  37. data/lib/async/http.rb +0 -3
  38. data/readme.md +20 -4
  39. data/releases.md +4 -0
  40. data.tar.gz.sig +0 -0
  41. metadata +3 -3
  42. metadata.gz.sig +0 -0
@@ -13,7 +13,10 @@ module Async
13
13
  # Wraps a client, address and headers required to initiate a connectio to a remote host using the CONNECT verb.
14
14
  # Behaves like a TCP endpoint for the purposes of connecting to a remote host.
15
15
  class Proxy
16
+ # Raised when a CONNECT tunnel through a proxy cannot be established.
16
17
  class ConnectFailure < StandardError
18
+ # Initialize the failure with the unsuccessful response.
19
+ # @parameter response [Protocol::HTTP::Response] The failed response from the proxy.
17
20
  def initialize(response)
18
21
  super "Failed to connect: #{response.status}"
19
22
  @response = response
@@ -22,7 +25,12 @@ module Async
22
25
  attr :response
23
26
  end
24
27
 
28
+ # Extends {Async::HTTP::Client} with proxy capabilities.
25
29
  module Client
30
+ # Create a proxy instance for the given endpoint.
31
+ # @parameter endpoint [Endpoint] The target endpoint to tunnel to.
32
+ # @parameter headers [Hash | Nil] Optional headers to send with the CONNECT request.
33
+ # @returns [Proxy] A proxy instance for establishing tunnels.
26
34
  def proxy(endpoint, headers = nil)
27
35
  Proxy.new(self, endpoint.authority(false), headers)
28
36
  end
@@ -34,6 +42,10 @@ module Async
34
42
  return self.class.new(proxy.wrap_endpoint(endpoint))
35
43
  end
36
44
 
45
+ # Create an endpoint that connects via this proxy.
46
+ # @parameter endpoint [Endpoint] The target endpoint.
47
+ # @parameter headers [Hash | Nil] Optional headers for the CONNECT request.
48
+ # @returns [Endpoint] An endpoint that tunnels through the proxy.
37
49
  def proxied_endpoint(endpoint, headers = nil)
38
50
  proxy = self.proxy(endpoint, headers)
39
51
 
@@ -12,11 +12,20 @@ require_relative "protocol"
12
12
 
13
13
  module Async
14
14
  module HTTP
15
+ # An HTTP server that accepts connections on a specific endpoint and dispatches requests to an application handler.
15
16
  class Server < ::Protocol::HTTP::Middleware
17
+ # Create a server using a block as the application handler.
18
+ # @parameter arguments [Array] Arguments to pass to {initialize}.
19
+ # @parameter options [Hash] Options to pass to {initialize}.
16
20
  def self.for(*arguments, **options, &block)
17
21
  self.new(block, *arguments, **options)
18
22
  end
19
23
 
24
+ # Initialize the server with an application handler and endpoint.
25
+ # @parameter app [Protocol::HTTP::Middleware] The Rack-compatible application to serve.
26
+ # @parameter endpoint [Endpoint] The endpoint to bind to.
27
+ # @parameter protocol [Protocol] The protocol to use for incoming connections.
28
+ # @parameter scheme [String] The default scheme to set on requests.
20
29
  def initialize(app, endpoint, protocol: endpoint.protocol, scheme: endpoint.scheme)
21
30
  super(app)
22
31
 
@@ -25,6 +34,7 @@ module Async
25
34
  @scheme = scheme
26
35
  end
27
36
 
37
+ # @returns [Hash] A JSON-compatible representation of this server.
28
38
  def as_json(...)
29
39
  {
30
40
  endpoint: @endpoint.to_s,
@@ -33,6 +43,7 @@ module Async
33
43
  }
34
44
  end
35
45
 
46
+ # @returns [String] A JSON string representation of this server.
36
47
  def to_json(...)
37
48
  as_json.to_json(...)
38
49
  end
@@ -41,6 +52,9 @@ module Async
41
52
  attr :protocol
42
53
  attr :scheme
43
54
 
55
+ # Accept an incoming connection and process requests.
56
+ # @parameter peer [IO] The connected peer.
57
+ # @parameter address [Addrinfo] The remote address of the peer.
44
58
  def accept(peer, address, task: Task.current)
45
59
  connection = @protocol.server(peer)
46
60
 
@@ -9,15 +9,23 @@ require "async/clock"
9
9
 
10
10
  module Async
11
11
  module HTTP
12
+ # Tracks response timing statistics including time to first byte and total duration.
12
13
  class Statistics
14
+ # Start tracking statistics from the current time.
15
+ # @returns [Statistics] A new statistics instance.
13
16
  def self.start
14
17
  self.new(Clock.now)
15
18
  end
16
19
 
20
+ # Initialize the statistics tracker.
21
+ # @parameter start_time [Float] The start time for measuring durations.
17
22
  def initialize(start_time)
18
23
  @start_time = start_time
19
24
  end
20
25
 
26
+ # Wrap a response body with a statistics-collecting wrapper.
27
+ # @parameter response [Protocol::HTTP::Response] The response to wrap.
28
+ # @returns [Protocol::HTTP::Response] The wrapped response.
21
29
  def wrap(response, &block)
22
30
  if response and response.body
23
31
  response.body = Body::Statistics.new(@start_time, response.body, block)
@@ -30,6 +38,10 @@ module Async
30
38
  module Body
31
39
  # Invokes a callback once the body has finished reading.
32
40
  class Statistics < ::Protocol::HTTP::Body::Wrapper
41
+ # Initialize the statistics body wrapper.
42
+ # @parameter start_time [Float] The start time for measuring durations.
43
+ # @parameter body [Protocol::HTTP::Body::Readable] The body to wrap.
44
+ # @parameter callback [Proc] A callback to invoke when the body is closed.
33
45
  def initialize(start_time, body, callback)
34
46
  super(body)
35
47
 
@@ -48,24 +60,29 @@ module Async
48
60
 
49
61
  attr :sent
50
62
 
63
+ # @returns [Float | Nil] The total duration from start to close, in seconds.
51
64
  def total_duration
52
65
  if @end_time
53
66
  @end_time - @start_time
54
67
  end
55
68
  end
56
69
 
70
+ # @returns [Float | Nil] The duration from start until the first chunk was read, in seconds.
57
71
  def first_chunk_duration
58
72
  if @first_chunk_time
59
73
  @first_chunk_time - @start_time
60
74
  end
61
75
  end
62
76
 
77
+ # Close the body and record the end time.
63
78
  def close(error = nil)
64
79
  complete_statistics(error)
65
80
 
66
81
  super
67
82
  end
68
83
 
84
+ # Read the next chunk from the body, tracking timing and bytes sent.
85
+ # @returns [String | Nil] The next chunk of data.
69
86
  def read
70
87
  chunk = super
71
88
 
@@ -78,6 +95,7 @@ module Async
78
95
  return chunk
79
96
  end
80
97
 
98
+ # @returns [String] A human-readable summary of the statistics.
81
99
  def to_s
82
100
  parts = ["sent #{@sent} bytes"]
83
101
 
@@ -92,6 +110,7 @@ module Async
92
110
  return parts.join("; ")
93
111
  end
94
112
 
113
+ # @returns [String] A detailed representation including the wrapped body.
95
114
  def inspect
96
115
  "#{super} | \#<#{self.class} #{self.to_s}>"
97
116
  end
@@ -3,8 +3,10 @@
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2017-2026, by Samuel Williams.
5
5
 
6
+ # @namespace
6
7
  module Async
8
+ # @namespace
7
9
  module HTTP
8
- VERSION = "0.94.2"
10
+ VERSION = "0.94.3"
9
11
  end
10
12
  end
data/lib/async/http.rb CHANGED
@@ -4,10 +4,7 @@
4
4
  # Copyright, 2017-2024, by Samuel Williams.
5
5
 
6
6
  require_relative "http/version"
7
-
8
7
  require_relative "http/client"
9
8
  require_relative "http/server"
10
-
11
9
  require_relative "http/internet"
12
-
13
10
  require_relative "http/endpoint"
data/readme.md CHANGED
@@ -16,6 +16,10 @@ 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.94.3
20
+
21
+ - 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).
22
+
19
23
  ### v0.94.1
20
24
 
21
25
  - Fix `defer_stop` usage in `HTTP1::Server`, improving server graceful shutdown behavior.
@@ -52,10 +56,6 @@ Please see the [project releases](https://socketry.github.io/async-http/releases
52
56
 
53
57
  - Add support for HTTP/2 `NO_RFC7540_PRIORITIES`. See <https://www.rfc-editor.org/rfc/rfc9218.html> for more details.
54
58
 
55
- ### v0.84.0
56
-
57
- - Minor consistency fixes to `Async::HTTP::Internet` singleton methods.
58
-
59
59
  ## See Also
60
60
 
61
61
  - [benchmark-http](https://github.com/socketry/benchmark-http) — A benchmarking tool to report on web server concurrency.
@@ -74,6 +74,22 @@ We welcome contributions to this project.
74
74
  4. Push to the branch (`git push origin my-new-feature`).
75
75
  5. Create new Pull Request.
76
76
 
77
+ ### Running Tests
78
+
79
+ To run the test suite:
80
+
81
+ ``` shell
82
+ bundle exec sus
83
+ ```
84
+
85
+ ### Making Releases
86
+
87
+ To make a new release:
88
+
89
+ ``` shell
90
+ bundle exec bake gem:release:patch # or minor or major
91
+ ```
92
+
77
93
  ### Developer Certificate of Origin
78
94
 
79
95
  In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.94.3
4
+
5
+ - 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).
6
+
3
7
  ## v0.94.1
4
8
 
5
9
  - Fix `defer_stop` usage in `HTTP1::Server`, improving server graceful shutdown behavior.
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.94.2
4
+ version: 0.94.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -277,14 +277,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
277
277
  requirements:
278
278
  - - ">="
279
279
  - !ruby/object:Gem::Version
280
- version: '3.2'
280
+ version: '3.3'
281
281
  required_rubygems_version: !ruby/object:Gem::Requirement
282
282
  requirements:
283
283
  - - ">="
284
284
  - !ruby/object:Gem::Version
285
285
  version: '0'
286
286
  requirements: []
287
- rubygems_version: 4.0.3
287
+ rubygems_version: 4.0.6
288
288
  specification_version: 4
289
289
  summary: A HTTP client and server library.
290
290
  test_files: []
metadata.gz.sig CHANGED
Binary file