-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Bug Report
Version
tonic = { version = "0.1.0-alpha.4", features = ["rustls", "prost"] }
tonic-build = { version = "0.1.0-alpha.4" }Platform
OS: macOS Catalina (10.15)
rustc version: 1.39.0-nightly (2019-09-10)
# output from: `uname -a`
Darwin MBP 19.0.0 Darwin Kernel Version 19.0.0: Wed Sep 25 20:18:50 PDT 2019; root:xnu-6153.11.26~2/RELEASE_X86_64 x86_64Description
Hello,
I was trying to write an abstraction library for using Google Cloud Platform APIs.
More specifically, I was writing the one for the Pub/Sub service of GCP.
So, I cloned the protobuf definitions of their services (https://github.com/googleapis/googleapis), and attempted to call one of their endpoints.
Here is the build.rs file I used:
fn main() {
tonic_build::configure()
.build_client(true)
.build_server(false)
.format(true)
.out_dir("src/api")
.compile(&["protos/google/pubsub/v1/pubsub.proto"], &["protos"])
.unwrap();
println!("cargo:rerun-if-changed=protos/google/pubsub/v1/pubsub.proto");
}
protos/is the directory containing the clone of Google's protobufs.
Then, I attempt to connect and make a call to the service, like this:
use http::HeaderValue;
use tonic::transport::{Certificate, Channel, ClientTlsConfig};
use tonic::Request;
mod api {
// Generated protobuf bindings
include!("api/google.pubsub.v1.rs");
}
const ENDPOINT: &str = "https://pubsub.googleapis.com";
const SCOPES: [&str; 2] = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/pubsub",
];
#[tokio::main]
async fn main() {
let certs = tokio::fs::read("roots.pem").await.unwrap();
let mut tls_config = ClientTlsConfig::with_rustls();
tls_config.ca_certificate(Certificate::from_pem(certs.as_slice()));
tls_config.domain_name("pubsub.googleapis.com");
let channel = Channel::from_static(ENDPOINT)
.intercept_headers(|headers| {
let token = "some-valid-google-oauth-token";
let value = format!("Bearer {0}", token);
let value = HeaderValue::from_str(value.as_str()).unwrap();
headers.insert("authorization", value);
})
.tls_config(&tls_config)
.channel();
let mut service = api::client::PublisherClient::new(channel);
let response = service.list_topics(Request::new(api::ListTopicsRequest {
project: format!("projects/{0}", "some-gcp-project-name"),
page_size: 10,
page_token: String::default(),
}));
dbg!(response.await);
}The roots.pem file I use here is the sample PEM file from Google Trust Services (https://pki.goog/roots.pem).
The dbg!(response.await) statement always yields:
[src/sample.rs:42] response.await = Err(
Status {
code: Internal,
message: "Unexpected compression flag: 60",
},
)
This happens regardless of the validity of the OAuth token.
To see if the connection flow was valid, I reproduced the experiment using Golang's google.golang.org/grpc and github.com/golang/protobuf packages:
package main
import (
"context"
"fmt"
"os"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
pubsub "google.golang.org/genproto/googleapis/pubsub/v1" // generated protobuf bindings
)
func clientInterceptor(
ctx context.Context,
method string,
req interface{},
reply interface{},
cc *grpc.ClientConn,
invoker grpc.UnaryInvoker,
opts ...grpc.CallOption,
) error {
md := metadata.New(map[string]string{
"authorization": "Bearer some-valid-google-oauth-token",
})
ctx = metadata.NewOutgoingContext(ctx, md)
return invoker(ctx, method, req, reply, cc, opts...)
}
func main() {
creds, err := credentials.NewClientTLSFromFile("roots.pem", "pubsub.googleapis.com")
if err != nil {
fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
}
conn, err := grpc.Dial("pubsub.googleapis.com:443", grpc.WithTransportCredentials(creds), grpc.WithUnaryInterceptor(clientInterceptor))
if err != nil {
fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
}
defer conn.Close()
pub := pubsub.NewPublisherClient(conn)
resp, err := pub.ListTopics(context.Background(), &pubsub.ListTopicsRequest{Project: "projects/some-gcp-project-name", PageSize: 10})
if err != nil {
fmt.Fprintf(os.Stderr, "error: %s\n", err.Error())
}
fmt.Printf("topics: %#v\n", resp)
}This Go code, provided with valid credentials, works as expected whereas the Rust code, with the same credentials, encounters the invalid compression flag error.