devashishdxt / tonic-web-wasm-client

Other
104 stars 28 forks source link

`grpc-encoding` header missing on compressed data #25

Closed auterium closed 1 year ago

auterium commented 1 year ago

Hi, thanks a lot for supporting this crate, it's been really helpful for me!

While trying to use compressed transfers, I'm stumbling this error:

protocol error: received message with compressed-flag but no grpc-encoding was specified

I've dug around a bit and found out that for some reason the browser's fetch() call is filtering out all response headers except the content-type one, meaning that the grpc-encoding header is not being passed down to tonic, hence the error. If I force the header to be included within crate::call::set_response_headers():

fn set_response_headers(
    mut result: Builder,
    response: &web_sys::Response,
) -> Result<(Builder, Option<String>), Error> {
    // ...

    result = result.header("grpc-encoding", "gzip");

    Ok((result, content_type))
}

Then the calls/streams work properly. Of course this is not ideal as it would break non-compressed calls/streams. Any thoughts on how to deal with this? Thanks a lot in advance!


How to reproduce: server.rs:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt::init();

    let addr = "127.0.0.1:3000".parse().unwrap();

    let greeter = MyGreeter::default();
    let greeter = GreeterServer::new(greeter)
        .send_compressed(CompressionEncoding::Gzip);

    println!("GreeterServer listening on {}", addr);

    Server::builder()
        .accept_http1(true)
        .layer(GrpcWebLayer::new())
        .add_service(greeter)
        .serve(addr)
        .await?;

    Ok(())
}

yew_client.rs

#[function_component(App)]
pub fn app() -> Html {
    wasm_bindgen_futures::spawn_local(async move {
        let base_url = "http://127.0.0.1:3000".to_string();
        let wasm_client = tonic_web_wasm_client::Client::new(base_url);
        let mut client = GreeterClient::new(wasm_client)
            .accept_compressed(CompressionEncoding::Gzip);

        let request = tonic::Request::new(HelloRequest {
            name: "Tonic".into(),
        });

        let response = client.say_hello(request).await;
        console_log!("{:?}", response); // <--- This will be an error
    });

    // ...
}
devashishdxt commented 1 year ago

Hi @auterium. Thanks for creating this issue. Shouldn't the grpc server send this header in its response? set_response_headers just copies all the headers from web_sys::Response to http::Response.

auterium commented 1 year ago

The gRPC server is sending the headers properly, but what I found was that for some weird reason web_sys::Response is not passing all headers received. As a test, I forked and modified the repo to be printing out the copied headers in set_response_headers and only the content-type header was present. Any other header was missing out, even if visible from debug tools. I tried adding some headers on the server that would start with x- in the hopes of them not being filtered out, but no luck. Kind of stuck on where to continue looking as it's my first experience with wasm so I'm still familiarizing myself with the ecosystem

devashishdxt commented 1 year ago

@auterium Can you post some sample server code here? Thanks.

auterium commented 1 year ago

Hi @devashishdxt sorry for the late reply. Here's a sample server code:

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt::init();

    let addr = "127.0.0.1:3000".parse().unwrap();

    let greeter = MyGreeter::default();
    let greeter = GreeterServer::new(greeter)
        .send_compressed(CompressionEncoding::Gzip);

    println!("GreeterServer listening on {}", addr);

    Server::builder()
        .accept_http1(true)
        .layer(GrpcWebLayer::new())
        .add_service(greeter)
        .serve(addr)
        .await?;

    Ok(())
}
devashishdxt commented 1 year ago

I think your original error was because of some missing things in client code or misconfigured cors layer. I've added gzip tests in the repository. Here is client and server code: https://github.com/devashishdxt/tonic-web-wasm-client/tree/main/test-suite/gzip.

Ref: #27