0

I am trying to get a working instance of grpc-web. I've got a backend service that looks like this.

var grpc      = require('grpc');
var messages  = require('./example_pb');
var service   = require('./example_grpc_pb');


function exampleOne(call) {
    var response = new messages.ExampleOneRequest();
    call.write(response);
    call.end();
}

function main() {
   var server = new grpc.Server();
   server.addService(
       services.MyExampleService,
       {
           example : exampleOne
       }
    );
    server.bind('0.0.0.0:8050', grpc.ServerCredentials.createInsecure());
    server.start();
}
main();

I've tested this with a server side 'client', so now I am attempting to hook up the actual web browser based client. First I set up the proxy, which apparently is necesary? I decided to go with the GoLang based grpcwebproxy, which seems like an acceptable choice according to the grpc-web documentation.

>> grpcwebproxy --backend_addr=localhost:8050 \                                                                                                                                                                       
--server_tls_cert_file=/usr2/certs/server/localhost.localdomain.crt \                                                                                                                                          
--server_tls_key_file=/usr2/certs/server/localhost.localdomain.key  

Output looks like this

INFO[0000] dialing to target with scheme: ""             system=system
INFO[0000] ccResolverWrapper: sending new addresses to cc: [{localhost:8050 0  <nil>}]  system=system
INFO[0000] listening for http on: [::]:8080             
INFO[0000] listening for http_tls on: [::]:8443         
INFO[0000] pickfirstBalancer: HandleSubConnStateChange: 0xc4201638a0, CONNECTING  system=system
INFO[0000] pickfirstBalancer: HandleSubConnStateChange: 0xc4201638a0, READY  system=system

I am unable to get the web-browser implentation working, just getting some generic/CORS related 500 errors.

I went back to my server side and decided to curl the proxy. It seems that http2 is not supported with my current version of curl, so I instead use a tool called h2c.

Long story short, I try pinging the tls port 8443 and get the following (most promising).

>> ./h2c_linux_amd64 get https://localhost:8443/service.path/ExampleOne

invalid gRPC request method

I try this

>> ./h2c_linux_amd64 get http://localhost:8443/service.path/ExampleOne

http connections not supported.

I try this

>> ./h2c_linux_amd64 get http://localhost:8080/service.path/ExampleOne

http connections not supported.

I try this

>> ./h2c_linux_amd64 get https://localhost:8080/service.path/ExampleOne

Failed to connect to localhost:8080: tls: oversized record received with length 20527

I don't expect an instant "this is your solution" type answer, since there's a lot I left out, but does anyone have any suggestions on where to run with this?

The error I got

"invalid gRPC request method"

seems the most promising, if generic.

EDIT :

Seem to have gotten a bit closer, at least debugging the server side. Went back to using curl. This was my command

curl 'https://localhost:8443/service.path/ExampleOne' \
-H 'content-type: application/grpc-web+proto' \
-H 'x-grpc-web: 1' \
-H 'authority: localhost:8443' \
--data-binary $'\x00\x00\x00\x00\x04\n\x02yo' \
--insecure

With this command, I was able to make it through the grpcwebproxy, to my service, and back to the other side. Something about supplying curl with a binary string seems to do the trick. I say this because

curl 'https://localhost:8443/service.path/ExampleOne' \
-H 'content-type: application/grpc-web+proto' \
-H 'x-grpc-web: 1' \
-H 'authority: localhost:8443' \
--insecure

results in an error message of

gRPC requires HTTP/2

Now I need to map the above curl command into a valid grpc-web request.

EDIT 2 :

I am now at the point where I think I require a cert. The code from the browser is hitting my grpcwebproxy, but I am seeing the error message

2018/10/17 12:21:56 http2: server: error reading preface from client 127.0.0.1:45056: remote error: tls: unknown certificate authority
2018/10/17 12:21:56 http2: server: error reading preface from client 127.0.0.1:45058: remote error: tls: unknown certificate authority
2018/10/17 12:21:56 http2: server: error reading preface from client 127.0.0.1:45060: remote error: tls: unknown certificate authority

This occurs in the output of grpcwebproxy, so I know the request is at least making it there.

I'm thinking I got around this previously with curl by including the --insecure tag... not sure how to replicate this in the browser.

Zack
  • 13,454
  • 24
  • 75
  • 113

1 Answers1

2

One option you have is to start with our Echo example and tweak from there. I just tried our example (the one using grpcwebproxy) and that works.

$ git clone https://github.com/grpc/grpc-web
$ cd grpc-web
$ docker-compose build prereqs common node-server grpcwebproxy binary-client
$ docker-compose up -d node-server grpcwebproxy binary-client

Browser: localhost:8081/echotest.html

From the browser, if I "copy as cURL", I got

curl 'http://localhost:8080/grpc.gateway.testing.EchoService/Echo' -H 'Pragma: no-cache' -H 'X-User-Agent: grpc-web-javascript/0.1' -H 'Origin: http://localhost:8081' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US,en;q=0.9' -H 'custom-header-1: value1' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36' -H 'Content-Type: application/grpc-web+proto' -H 'Accept: */*' -H 'X-Grpc-Web: 1' -H 'Cache-Control: no-cache' -H 'Referer: http://localhost:8081/echotest.html' -H 'Connection: keep-alive' --data-binary $'\x00\x00\x00\x00\x05\n\x03abc' --compressed
Stanley Cheung
  • 347
  • 1
  • 3