async-grpc 0.9.0 → 0.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 031cde64ff322b5e4d247cec205cdbe17219d455240866df154fca3f370e675c
4
- data.tar.gz: d926dbe26788e37bbcb219cce9224c40f5c282bb0ed84c42fcbb6118472da69f
3
+ metadata.gz: 12169b5f04693e4d731851e19f34c4c1a7b1f4486e8f2046117bbc990170f773
4
+ data.tar.gz: ef7bc8f5a20fe39022894d1807e43ffdf32a445aab479a6fc51eb6c93005dd06
5
5
  SHA512:
6
- metadata.gz: 5a5cb6a72c70046df6b85f287d96f04b2ab12a807945025b5c38b924f6dcb5480b012444b42b4e857e63f1b535c5c6db9cd9c6fe6ad9f04c6f7976065cdcfbf5
7
- data.tar.gz: dc65cc27dfcb838ce8b77f805012333edeb0813707e9d646a805c9776f9e7fae9d2dca78cd3a5dc29ceb27b99ff435cb9f84adcbeba131362aeb40ef7dc37020
6
+ metadata.gz: 9ea87b076054c89e61f0f6cd6df5c1842e5b9d3ffac934c668f0faa8d934a1c2d5b001c3c8176d85b15c8e4d73104a4f8c8a4ada9c0584530a08ccd9c2d21b13
7
+ data.tar.gz: 1df7363341ba861b8676ca8e6fbd18b62f1cf7c59fe27c6609f28c205907c61d2f40728e312967a5a7b2e7e4f84ec063f3bbcb4386ad7ca08d107070251f8310
checksums.yaml.gz.sig CHANGED
Binary file
@@ -98,11 +98,13 @@ module Async
98
98
  # Call the underlying HTTP client with merged headers.
99
99
  # @parameter request [Protocol::HTTP::Request] The HTTP request
100
100
  # @returns [Protocol::HTTP::Response] The HTTP response
101
+ # @raises [ResponseError] If the HTTP response does not conform to gRPC.
101
102
  def call(request)
102
103
  request.headers = @headers.merge(request.headers)
103
104
 
104
105
  super.tap do |response|
105
106
  response.headers.policy = Protocol::GRPC::HEADER_POLICY
107
+ validate_response!(response)
106
108
  end
107
109
  end
108
110
 
@@ -117,16 +119,17 @@ module Async
117
119
  # @yields {|input, output| ...} Block for streaming calls
118
120
  # @returns [Object | Protocol::GRPC::Body::ReadableBody] Response message or readable body for streaming
119
121
  # @raises [ArgumentError] If method is unknown or streaming type is invalid
122
+ # @raises [ResponseError] If the HTTP response does not conform to gRPC.
120
123
  # @raises [Protocol::GRPC::Error] If the gRPC call fails
121
124
  def invoke(service, method, request = nil, metadata: {}, timeout: nil, encoding: nil, initial: nil, &block)
122
125
  rpc = service.class.lookup_rpc(method)
123
- raise ArgumentError, "Unknown method: #{method}" unless rpc
126
+ raise ArgumentError, "Unknown method: #{method}!" unless rpc
124
127
 
125
128
  path = service.path(method)
126
129
  headers = Protocol::GRPC::Metadata.build(
127
130
  metadata: metadata,
128
131
  timeout: timeout,
129
- content_type: "application/grpc+proto"
132
+ content_type: "application/grpc"
130
133
  )
131
134
  headers["grpc-encoding"] = encoding if encoding
132
135
 
@@ -144,12 +147,22 @@ module Async
144
147
  when :bidirectional
145
148
  bidirectional_call(path, headers, request_class, response_class, encoding, initial: initial, &block)
146
149
  else
147
- raise ArgumentError, "Unknown streaming type: #{streaming}"
150
+ raise ArgumentError, "Unknown streaming type: #{streaming}!"
148
151
  end
149
152
  end
150
153
 
151
154
  protected
152
155
 
156
+ # Reject non-gRPC responses before passing their bytes to a frame decoder.
157
+ # @parameter response [Protocol::HTTP::Response] The HTTP response.
158
+ # @raises [ResponseError] If the response is not a valid gRPC envelope.
159
+ def validate_response!(response)
160
+ content_type = response.headers["content-type"].to_s
161
+ return if response.status == 200 && content_type.match?(/\Aapplication\/grpc(?:\+[\w.-]+)?(?:\s*;|\z)/i)
162
+
163
+ raise ResponseError.for(response)
164
+ end
165
+
153
166
  # Make a unary gRPC call.
154
167
  # @parameter path [String] The gRPC path
155
168
  # @parameter headers [Protocol::HTTP::Headers] Request headers
@@ -14,6 +14,29 @@ module Async
14
14
  class DeadlineExceededError < Error
15
15
  end
16
16
 
17
+ # Raised when an HTTP response does not conform to gRPC.
18
+ # Preserves the buffered response for inspection.
19
+ class ResponseError < Error
20
+ # Create an error from an invalid response, buffering its body for inspection.
21
+ # @parameter response [Protocol::HTTP::Response] The invalid response.
22
+ # @returns [ResponseError] The error with the buffered response attached.
23
+ def self.for(response)
24
+ self.new("Invalid gRPC response: HTTP #{response.status}, content-type #{response.headers["content-type"].to_s.inspect}!", response.buffered!)
25
+ end
26
+
27
+ # Initialize an error with a message and response.
28
+ # @parameter message [String] The reason the response is invalid.
29
+ # @parameter response [Protocol::HTTP::Response] The buffered response.
30
+ def initialize(message, response)
31
+ super(message)
32
+
33
+ @response = response
34
+ end
35
+
36
+ # @attribute [Protocol::HTTP::Response] The buffered response, with its body available to read.
37
+ attr :response
38
+ end
39
+
17
40
  # Represents an error that originated from a remote gRPC server.
18
41
  # Used as the `cause` of {Protocol::GRPC::Error} when the client receives a non-OK status.
19
42
  # The message and optional backtrace are extracted from response metadata.
@@ -7,7 +7,7 @@
7
7
  module Async
8
8
  # @namespace
9
9
  module GRPC
10
- VERSION = "0.9.0"
10
+ VERSION = "0.10.0"
11
11
  end
12
12
  end
13
13
 
data/lib/async/grpc.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2025, by Samuel Williams.
4
+ # Copyright, 2025-2026, by Samuel Williams.
5
5
  # Copyright, 2026, by Alex Watt.
6
6
 
7
7
  require_relative "grpc/version"
data/readme.md CHANGED
@@ -24,6 +24,11 @@ Please see the [project documentation](https://socketry.github.io/async-grpc/) f
24
24
 
25
25
  Please see the [project releases](https://socketry.github.io/async-grpc/releases/index) for all releases.
26
26
 
27
+ ### v0.10.0
28
+
29
+ - Send `application/grpc` request headers for compatibility with Google API frontends.
30
+ - Reject invalid HTTP responses before decoding gRPC frames with `Async::GRPC::ResponseError`, describing the invalid status and content type in the message and buffering the response for inspecting status, headers, and body.
31
+
27
32
  ### v0.9.0
28
33
 
29
34
  - Added `Async::GRPC::Dispatcher#emit_completion` for once-per-request completion instrumentation, including routing failures, cancellations, and the final gRPC status.
data/releases.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Releases
2
2
 
3
+ ## v0.10.0
4
+
5
+ - Send `application/grpc` request headers for compatibility with Google API frontends.
6
+ - Reject invalid HTTP responses before decoding gRPC frames with `Async::GRPC::ResponseError`, describing the invalid status and content type in the message and buffering the response for inspecting status, headers, and body.
7
+
3
8
  ## v0.9.0
4
9
 
5
10
  - Added `Async::GRPC::Dispatcher#emit_completion` for once-per-request completion instrumentation, including routing failures, cancellations, and the final gRPC status.
data.tar.gz.sig CHANGED
@@ -1,3 +1,2 @@
1
- I�:���*$���� �+�
2
- �<�����[,��/�Ѻ��ezž�l�<4��"���av��v�|ܪ�D��0����/U���V���K4H}vm�,f���݅bܕ��
3
- bj���������ˡ�R�9���{�IsJ�[w� UVU��%z��n5Hy�(gy�y�s����*���|����.��b��� $��<L��ę������a�ՠ��O���
1
+ sd�y��Y��7�S)��B��Jp��S;���#��o�t�|+��L���,v�N̔�}�c�mcs���X����ʁ ��� �6��]��X��1��$�-cK2���K�7�)����J�����9A!����h�����M��%����+��Rp �'0�aǭ#*����C>b)Ky5ٻ����rZ�Ϡ�����P����L�Uh������#93�!b�_W�7���m��2ٮ�W�N��h���H��È�.~dhG Ηa��U �"�o-Y6��q4�c8�U�c�0����?���^N��S��@��ꌨ+�{�q�&
2
+ <��r�b�:Ϻ%~�u��;�
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-grpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -73,14 +73,14 @@ dependencies:
73
73
  requirements:
74
74
  - - "~>"
75
75
  - !ruby/object:Gem::Version
76
- version: 0.14.0
76
+ version: '0.16'
77
77
  type: :runtime
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
- version: 0.14.0
83
+ version: '0.16'
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: protocol-http
86
86
  requirement: !ruby/object:Gem::Requirement
@@ -135,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
135
  - !ruby/object:Gem::Version
136
136
  version: '0'
137
137
  requirements: []
138
- rubygems_version: 4.0.10
138
+ rubygems_version: 4.0.16
139
139
  specification_version: 4
140
140
  summary: Client and server implementation for gRPC using Async.
141
141
  test_files: []
metadata.gz.sig CHANGED
Binary file