Open DazWilkin opened 1 week ago
As an aside, I believe, while gRPC-Web is supported by FauxRPC, CORS is not. Is that correct?
The consequence is that gRPC-Web clients except browsers are supported.
I don't have time to dig deeply into this right this moment, but I can throw a couple suggestions:
grpc-accept-encoding
header being different may be a big hint at compression being differentI can easily add CORS support in to make this easier. You could theoretically use a load balancer to serve up a UI and FauxRPC with the same host. In which case, CORS doesn't really matter or you could have the load balancer serve up the CORS headers... but I can see how that can be extra work, so this is a good feature to add directly to FauxRPC. Can you make a different github issue for that to track it separately?
Thanks for the feedback and suggestions; I'll give them a whirl.
I'm running the Web server and FauxRPC on localhost; CORS rears its head because of the different ports, I'd thought?
I'll open an issue for CORS support.
From looking at wireshark output, there's a hint of what is happening.
Here is what it looks like when using the rust server:
Here is FauxRPC:
Notice that there's one more packet with FauxRPC. That's because FauxRPC is sending the trailers after it sends the data. For whatever reason the implementation is splitting the response message and the trailers into multiple packets. It appears like tonic doesn't handle this very well. I think both scenarios are valid, so I'm leaning on this being an issue with the client side of tonic_web.
I'm out of my depth with rust, but I believe we might learn more about this issue from debugging this poll_frame
function: https://github.com/hyperium/tonic/blob/master/tonic-web/src/call.rs#L258. This reads to me like it is supposed to be reading frames until it reads the trailers... but it appears like something is off either with the logic or the data.
I've found the issue. tonic-web appears to be parsing the trailers wrong in some cases... it's seeing an extra space with FauxRPC. This is basically what the trailers look like from FauxRPC:
grpc-message:
grpc-status: 0
The tonic_web server does this:
grpc-status:0
You don't see it in your output because it's not actually printing the raw trailers.
Note the spaces after the separating colon :
. These spaces are dictated by the grpc-web protocol spec so the tonic-web gRPC-Web client should handle the space after the colon. I think many client implementations deal with the space being absent or present, which why this flaw may have gone unnoticed. The tonic-web client is also likely mostly tested exclusively with tonic-web server, and those both don't use a space there. Again, I'm not a rust dev, so I'm not sure how effective I can be at making a patch to tonic-web 😅 I may try to attempt the fix if I find the time 😅
Thanks for this issue though, this has been a fun learning experience! 🦀
I filed a PR for tonic. From my testing it fixes your issue 😀
Wow!
Thank you very much. I saw the PR. I'll try it out.
It makes sense that they're only testing against Rust (tonic) servers.
Does this explain why the Rust client worked with Connect's public Eliza service?
Because this is only an issue with HTTP/1.1 and I think the Rust client would connect using HTTP/2 with demo.connectrpc.com. HTTP/2 has binary framing which is much more strict so this isn't an issue there. The usual behavior for HTTP clients is to never use HTTP/2 on non-TLS connections.
This, however, can be forced by using a feature called "h2c" (sometimes referred to as http2 prior knowledge
). It does look like tonic supports it... but I'm not going to lie, it looks oddly complicated to use... To test this fully you'd want to take the h2c example and adapt it to use grpc-web instead of just gRPC (because this trailer parsing logic is exclusive to gRPC-Web).
Oh wait, I'm actually wrong about HTTP/2 here. Even with HTTP/2, gRPC-Web trailers are passed in the body... so your question still stands at why the behavior is different.
I will note that FauxRPC actually uses Vanguard to enable gRPC/gRPC-Web/Connect/REST protocols... So the implementation is actually different. gRPC-Web trailers may be different between ConnectRPC and Vanguard.
Using
tonic-web
with any (but e.g.ElizaService
)client.rs
(as-is URL changes aside) against FauxRPC:Even though
fauxrpc run --addr=localhost:6660 --schema=eliza.binpb
:Reconfiguring the rust client to use
https://demo.connectrpc.com
:In the latter case, I'm having to rewire the client to use TLS too but, using
tailscale serve --https=443 6660
, I can put a TLS proxy in front of FauxRPC too and continue to receive:All the while FauxRPC reports success (200) on the
POST /.../ElizaService/Say
.This suggests there's something inconsistent in FauxRPC's behavior that's not present in ConnectRPC.
I've been flummoxed by this.
I used Kreya because it supports gRPC-Web and it works correctly with both the ConnectRPC and FauxRPC endpoints.
Yesterday, I used
socat
to try and capture the traffic using thetonic-web
'shelloworld.proto
against FauxRPC.With minor differences, there's no obvious (to me breaking) difference:
client.rs
generates theError
:Kreya responds with
Ok
: