-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
grpc-web interface not compatible with dart client #453
Comments
Actually, https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md says "use lower-case header/trailer names", This matches a fix made in improbable-eng/grpc-web#228 |
@bamnet, HTTP header names are not supposed to be case-sensitive. With HTTP/2, they get normalized to all lower-case to aid with HPACK header compression. I wonder if that's why the protocol spec insists on a lower-case name. Many HTTP clients, however, normalize to camel-case when using HTTP 1.1 (including the internal representation of Go's While a fix might be appropriate here in connect-go (since the web protocol document insists on all lower-case), it also seems appropriate to put fixes into both the protocol spec and the Dart gRPC runtime since the IETF specs for HTTP clearly state that header and trailer names are not case-sensitive. |
I'm opening this PR to (hopefully!) stimulate a discussion. In brief, I'd like to amend the gRPC-Web protocol docs to encourage clients to follow standard HTTP semantics. The gRPC-Web specification is a nicely-designed way for proxies to expose standard HTTP/2 gRPC servers to clients using less tightly-controlled HTTP stacks, such as web browsers. To serve that goal, it seems valuable to have the gRPC-Web specification follow [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names). Like previous RFCs, 9110 specifies that "field names are case-insensitive." However, the current gRPC-Web specification requires that servers and proxies "use lower-case header/trailer names" on the wire. In principle, mandating casing on the wire is fine (if unusual); however, it encourages clients to violate HTTP semantics and _depend_ on the wire casing. I'd like to loosen the gRPC-Web specification to permit any casing on the wire, emphasizing that gRPC-Web clients ought to follow standard HTTP semantics and treat field names case-insensitively. This amendment does not affect the correctness of Envoy (which may continue to use lower-case field names) or the `grpc-web` Javascript project (which already treats field names case-insensitively, thanks to the Web Platform's `Headers` interface). However, it does clarify that `grpc-dart` is _incorrect_ in relying on lower-case field names. Relates to improbable-eng/grpc-web#228 and https://github.com/bufbuild/connect-go/issues/453/
I'm opening this PR to (hopefully!) stimulate a discussion. In brief, I'd like to amend the gRPC-Web protocol docs to encourage implementations to follow HTTP semantics and compare HTTP field names case-insensitively. The gRPC-Web specification is a nicely-designed way for proxies to expose standard HTTP/2 gRPC servers to clients using less tightly-controlled HTTP stacks, such as web browsers. To serve that goal, it seems valuable to have the gRPC-Web specification follow [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names). Like previous RFCs, 9110 specifies that "field names are case-insensitive." However, the current gRPC-Web specification requires that servers and proxies "use lower-case header/trailer names" on the wire. In principle, mandating casing on the wire is normal for HTTP/2 and fine (if unusual) for HTTP/1.1; however, it encourages implementations to violate HTTP semantics and require lower-case names when _reading_ headers and trailers. I'd like to loosen the gRPC-Web specification to permit any casing on the wire for HTTP/1.1. I'd also like to emphasize that gRPC-Web implementations ought to follow standard HTTP semantics when _reading_ fields and compare names case-insensitively. This amendment does not affect the correctness of Envoy (which may continue to use lower-case field names) or the `grpc-web` Javascript project (which already treats field names case-insensitively, thanks to the Web Platform's `Headers` interface). However, it does clarify that `grpc-dart` is _incorrect_ in relying on lower-case field names. Relates to improbable-eng/grpc-web#228, https://github.com/bufbuild/connect-go/issues/453/, and grpc/grpc-dart#594.
I'm opening this PR to (hopefully!) stimulate a discussion. In brief, I'd like to amend the gRPC-Web protocol docs to encourage implementations to follow HTTP semantics and compare HTTP field names case-insensitively. The gRPC-Web specification is a nicely-designed way for proxies to expose standard HTTP/2 gRPC servers to clients using less tightly-controlled HTTP stacks, such as web browsers. To serve that goal, it seems valuable to have the gRPC-Web specification follow [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names). Like previous RFCs, 9110 specifies that "field names are case-insensitive." However, the current gRPC-Web specification requires that servers and proxies "use lower-case header/trailer names" on the wire. In principle, mandating casing on the wire is normal for HTTP/2 and fine (if unusual) for HTTP/1.1; however, it encourages implementations to violate HTTP semantics and require lower-case names when _reading_ headers and trailers. I'd like to loosen the gRPC-Web specification to permit any casing on the wire for HTTP/1.1. I'd also like to emphasize that gRPC-Web implementations ought to follow standard HTTP semantics when _reading_ fields and compare names case-insensitively. This amendment does not affect the correctness of Envoy (which may continue to use lower-case field names) or the `grpc-web` Javascript project (which already treats field names case-insensitively, thanks to the Web Platform's `Headers` interface). However, it does clarify that `grpc-dart` is _incorrect_ in relying on lower-case field names. Relates to improbable-eng/grpc-web#228, https://github.com/bufbuild/connect-go/issues/453/, and grpc/grpc-dart#594.
Echoing @jhump, this seems like a bug in I'd like to wait and see if we can come to some resolution on those issues before making any changes here. |
Responding here to @akshayjshah's comment
This statement is not entirely correct. While it is true that HTTP & HTTP/1.1 field names are in fact case insensitive, HTTP/2 is pretty unambiguous:
gRPC-Web is derived from the native HTTP/2 protocol so naturally it simply follows the same requirement. I would also like to highlight that gRPC-Web is a protocol on top of underlying HTTP/* protocol so it certainly can add additional requirements on top of what HTTP/1.1 requires. For example in this case it requires more normalized headers and trailers than what underlying protocol mandates. Consequently as it stands now it is most certainly a bug in connect-go code, which is in clear violation of gRPC-Web specification. If gRPC-Web specification gets relaxed as proposed in your PR then it will become a bug in grpc-dart code, but not before that. Note that canonical JavaScript implementation of gRPC-Web does also expect that field names are sent in lower case (e.g. see this code used for parsing trailers). This also means that relaxing specification right now would effectively mean a breaking change for all the clients which rely on existing specification. I don't think that makes sense. |
@mraleph I agree that the current gRPC-Web specification insists on lower-cased header and trailer names on the wire. We can defer a discussion of whether that makes sense in HTTP/1.1 to grpc/grpc#32364; regardless of how that PR turns out, the current grpc-dart behavior seems like it may be incorrect to me. HTTP/2 field names must indeed be lower-case on the wire, as the section of RFC 9113 you've quoted clearly says. However, the semantics of HTTP/2 header names are covered in RFC 9110. From section 1.2:
And later, in section 5.1:
RFC 7540, which was the authoritative HTTP/2 specification when the gRPC-Web spec was written, addressed the interplay between the wire format and the semantics more clearly:
It seems to me that the intention here is to send lower-case names on the wire, but to treat All that said, I don't intend to suggest any changes that would be backward-incompatible for Envoy or More broadly, it seems to me that there are many more gRPC-Web implementations than the current pseudo-specification anticipated. It would be helpful to the whole ecosystem to have a formal specification rather than the current casual description: grpc/grpc#30565 |
@mraleph Update on |
Currently two options are possible:
1 is essentially a breaking change with wide implications. 2 is not - server code is wrong it gets fixed, everybody is happy. No non local impact. So I think the choice between 1 and 2 is fairly straightforward. |
I'm opening this PR to (hopefully!) stimulate a discussion. In brief, I'd like to amend the gRPC-Web protocol docs to encourage implementations to follow HTTP semantics and compare HTTP field names case-insensitively. The gRPC-Web specification is a nicely-designed way for proxies to expose standard HTTP/2 gRPC servers to clients using less tightly-controlled HTTP stacks, such as web browsers. To serve that goal, it seems valuable to have the gRPC-Web specification follow [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names). Like previous RFCs, 9110 specifies that "field names are case-insensitive." However, the current gRPC-Web specification requires that servers and proxies "use lower-case header/trailer names" on the wire. In principle, mandating casing on the wire is normal for HTTP/2 and fine (if unusual) for HTTP/1.1; however, it encourages implementations to violate HTTP semantics and require lower-case names when _reading_ headers and trailers. I'd like to loosen the gRPC-Web specification to permit any casing on the wire for HTTP/1.1. I'd also like to emphasize that gRPC-Web implementations ought to follow standard HTTP semantics when _reading_ fields and compare names case-insensitively. This amendment does not affect the correctness of Envoy (which may continue to use lower-case field names) or the `grpc-web` Javascript project (which already treats field names case-insensitively, thanks to the Web Platform's `Headers` interface). However, it does clarify that `grpc-dart` is _incorrect_ in relying on lower-case field names. Relates to improbable-eng/grpc-web#228, https://github.com/bufbuild/connect-go/issues/453/, and grpc/grpc-dart#594.
Yes, the hand-written trailers parsing in Changing I also see "2 is not - server code is wrong it gets fixed, everybody is happy" as inaccurate. I'd like gRPC-Web - and protobuf-based RPC in general - to be more attractive to web developers familiar with HTTP's usual semantics. Insisting on matching HTTP/1.1 headers case-sensitively is, IMO, an entirely avoidable wart in a protocol that's already struggling to gain significant traction. If I'm off-base and the gRPC team intends user access to metadata to be case-sensitive, I don't mind changing |
#461) As a partial solution to #453, lower-case keys when appending gRPC-Web trailers to the response body. This is uncontroversial, since it only affects a portion of the wire format specific to gRPC-Web. This does _not_ address trailers-only responses or standard response headers, which the gRPC-Web specification seems to also demand in lowercase. --------- Co-authored-by: Akshay Shah <[email protected]>
@bamnet I'm waiting on grpc/grpc#32364 before also lower-casing HTTP headers. |
Thanks for the fix! My flutter app is now successfully working on Android, iOS, Web, and Desktop. |
I'm opening this PR to (hopefully!) stimulate a discussion. In brief, I'd like to amend the gRPC-Web protocol docs to encourage implementations to follow HTTP semantics and compare HTTP field names case-insensitively. The gRPC-Web specification is a nicely-designed way for proxies to expose standard HTTP/2 gRPC servers to clients using less tightly-controlled HTTP stacks, such as web browsers. To serve that goal, it seems valuable to have the gRPC-Web specification follow [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names). Like previous RFCs, 9110 specifies that "field names are case-insensitive." However, the current gRPC-Web specification requires that servers and proxies "use lower-case header/trailer names" on the wire. In principle, mandating casing on the wire is normal for HTTP/2 and fine (if unusual) for HTTP/1.1; however, it encourages implementations to violate HTTP semantics and require lower-case names when _reading_ headers and trailers. I'd like to loosen the gRPC-Web specification to permit any casing on the wire for HTTP/1.1. I'd also like to emphasize that gRPC-Web implementations ought to follow standard HTTP semantics when _reading_ fields and compare names case-insensitively. Implementations that can't treat names case-insensitively without breaking backward compatibility should instead normalize field names to lowercase. Among the Google-maintained gRPC implementations, at least `grpc-go` and `grpc-java` already compare names case-insensitively (even though they're HTTP/2-only). `grpc-dart` does the opposite and compares names case-sensitively. `grpc-web` is sometimes case-insensitive (when reading `grpc-status` and `grpc-message` from trailers-only responses) and sometimes case-sensitive (when hand-parsing a block of length-prefixed trailers). The proposed amendment does not affect the correctness of Envoy (which may continue to use lower-case field names). It partially affects `grpc-web`, which would require a small patch to always normalize names. (Both patched and unpatched versions of `grpc-web` would work with Envoy.) `grpc-dart` would need to either begin treating field names case-insensitively or normalize names, depending on what's possible in Dart without breaking backward compatibility. Relates to improbable-eng/grpc-web#228, https://github.com/bufbuild/connect-go/issues/453/, and grpc/grpc-dart#594.
As a final update here, grpc/grpc#32364 was accepted. This should clarify that |
I'm opening this PR to (hopefully!) stimulate a discussion. In brief, I'd like to amend the gRPC-Web protocol docs to encourage implementations to follow HTTP semantics and compare HTTP field names case-insensitively. The gRPC-Web specification is a nicely-designed way for proxies to expose standard HTTP/2 gRPC servers to clients using less tightly-controlled HTTP stacks, such as web browsers. To serve that goal, it seems valuable to have the gRPC-Web specification follow [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names). Like previous RFCs, 9110 specifies that "field names are case-insensitive." However, the current gRPC-Web specification requires that servers and proxies "use lower-case header/trailer names" on the wire. In principle, mandating casing on the wire is normal for HTTP/2 and fine (if unusual) for HTTP/1.1; however, it encourages implementations to violate HTTP semantics and require lower-case names when _reading_ headers and trailers. I'd like to loosen the gRPC-Web specification to permit any casing on the wire for HTTP/1.1. I'd also like to emphasize that gRPC-Web implementations ought to follow standard HTTP semantics when _reading_ fields and compare names case-insensitively. Implementations that can't treat names case-insensitively without breaking backward compatibility should instead normalize field names to lowercase. Among the Google-maintained gRPC implementations, at least `grpc-go` and `grpc-java` already compare names case-insensitively (even though they're HTTP/2-only). `grpc-dart` does the opposite and compares names case-sensitively. `grpc-web` is sometimes case-insensitive (when reading `grpc-status` and `grpc-message` from trailers-only responses) and sometimes case-sensitive (when hand-parsing a block of length-prefixed trailers). The proposed amendment does not affect the correctness of Envoy (which may continue to use lower-case field names). It partially affects `grpc-web`, which would require a small patch to always normalize names. (Both patched and unpatched versions of `grpc-web` would work with Envoy.) `grpc-dart` would need to either begin treating field names case-insensitively or normalize names, depending on what's possible in Dart without breaking backward compatibility. Relates to improbable-eng/grpc-web#228, https://github.com/bufbuild/connect-go/issues/453/, and grpc/grpc-dart#594.
I'm opening this PR to (hopefully!) stimulate a discussion. In brief, I'd like to amend the gRPC-Web protocol docs to encourage implementations to follow HTTP semantics and compare HTTP field names case-insensitively. The gRPC-Web specification is a nicely-designed way for proxies to expose standard HTTP/2 gRPC servers to clients using less tightly-controlled HTTP stacks, such as web browsers. To serve that goal, it seems valuable to have the gRPC-Web specification follow [RFC 9110 (HTTP Semantics)](https://www.rfc-editor.org/rfc/rfc9110.html#name-field-names). Like previous RFCs, 9110 specifies that "field names are case-insensitive." However, the current gRPC-Web specification requires that servers and proxies "use lower-case header/trailer names" on the wire. In principle, mandating casing on the wire is normal for HTTP/2 and fine (if unusual) for HTTP/1.1; however, it encourages implementations to violate HTTP semantics and require lower-case names when _reading_ headers and trailers. I'd like to loosen the gRPC-Web specification to permit any casing on the wire for HTTP/1.1. I'd also like to emphasize that gRPC-Web implementations ought to follow standard HTTP semantics when _reading_ fields and compare names case-insensitively. Implementations that can't treat names case-insensitively without breaking backward compatibility should instead normalize field names to lowercase. Among the Google-maintained gRPC implementations, at least `grpc-go` and `grpc-java` already compare names case-insensitively (even though they're HTTP/2-only). `grpc-dart` does the opposite and compares names case-sensitively. `grpc-web` is sometimes case-insensitive (when reading `grpc-status` and `grpc-message` from trailers-only responses) and sometimes case-sensitive (when hand-parsing a block of length-prefixed trailers). The proposed amendment does not affect the correctness of Envoy (which may continue to use lower-case field names). It partially affects `grpc-web`, which would require a small patch to always normalize names. (Both patched and unpatched versions of `grpc-web` would work with Envoy.) `grpc-dart` would need to either begin treating field names case-insensitively or normalize names, depending on what's possible in Dart without breaking backward compatibility. Relates to improbable-eng/grpc-web#228, https://github.com/bufbuild/connect-go/issues/453/, and grpc/grpc-dart#594.
#461) As a partial solution to #453, lower-case keys when appending gRPC-Web trailers to the response body. This is uncontroversial, since it only affects a portion of the wire format specific to gRPC-Web. This does _not_ address trailers-only responses or standard response headers, which the gRPC-Web specification seems to also demand in lowercase. --------- Co-authored-by: Akshay Shah <[email protected]>
Describe the bug
The grpc-web interface exposed by the connect-go server is not compatible with the grpc dart client when used in a web application. As an example, I'm working on a Flutter application which connects over Grpc on Android/iOS but Grpc-Web on Chrome. it works great on Android/iOS, but does not work on Chrome.
From what I can tell, the trailers set by connect-go are capitalized like
Grpc-Status
. The grpc dart client expects(?) these trailers to be all lowercase, likegrpc-status
. As a result of this mismatch, the Dart code can't parse the trailers and barfs returning a generic GRPC Status 2 error message even when the server has "correctly" returned a status 0 message.To Reproduce
GrpcWebClientChannel.xhr(Uri.parse('http://localhost:8080'));
Along the way, you can use a packet sniffer to observe a difference in trailer capitalization between the quasi-official envoy proxy and the connect-go implementation.
To simulate a fix in, I lowercased the values of
grpcHeaderMessage
andgrpcHeaderStatus
in protocol_grpc.go. This fixes the client (but probably isn't the right way to fix this).Environment (please complete the following information):
connect-go
version or commit:v1.5.1
go version
:go version go1.19 linux/amd64
dart --version
:Dart SDK version: 2.18.6 (stable) (Tue Dec 13 21:15:14 2022 +0000) on "linux_x64"
dart grpc
:v3.1.0
Additional context
I don't know what the Grpc-web "spec" says is correct here. I'm not sure if this is a bug in connect-go or the dart grpc client. I'm happy to chase down a bug on the dart side if this is more of a client issue than a server one but wanted to file here to start.
The text was updated successfully, but these errors were encountered: