grpc / grpc-web

gRPC for Web Clients
https://grpc.io
Apache License 2.0
8.45k stars 760 forks source link

Chrome's "Copy as cURL" does not work with gRPC-web #1394

Closed dimo414 closed 1 week ago

dimo414 commented 6 months ago

This isn't strictly a gRPC-web bug, but it's an incompatibility between the gRPC-web binary protocol and the developer tooling Google Chrome provides, so hopefully y'all can communicate internally :slightly_smiling_face: I don't have a lot of faith that my in-browser feedback will go anywhere.

Chrome's dev tools includes a very useful "Copy as cURL" tool to generate a curl command to reproduce a given request. However I've observed that the generated command is malformed for (some?) gRPC-web requests due to \0 bytes in the request body which bash and other shells, as well as Unix command lines, are incompatible with.

Here's a sanitized example command generated by Chrome:

curl 'https://my.server/my.CoolService/Query' \
  -H 'sec-ch-ua: "Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"' \
  -H 'DNT: 1' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' \
  -H 'authorization: Bearer ...' \
  -H 'content-type: application/grpc-web+proto' \
  -H 'x-grpc-web: 1' \
  -H 'Referer: https://my.server/' \
  -H 'grpc-timeout: 120000m' \
  -H 'sec-ch-ua-platform: "Linux"' \
  --data-raw $'\u0000\u0000\u0000\u0001F\n\u0085\u0002\n    query ....' \
  --compressed

The payload is supposed to be passed via the --data-raw flag, however bash doesn't support \0 bytes in strings and so this ends up as an empty string. Demo:

$ printf '%q\n' --data-raw $'\u0000\u0000\u0000\u0001F\n\u0085\u0002\n    query ....'
--data-raw
''

This causes the request to fail - including -v in the curl command shows the following response headers:

< HTTP/2 200 
< date: Wed, 03 Jan 2024 19:41:15 GMT
< content-type: application/grpc-web+proto
< content-length: 0
< grpc-status: 12
< grpc-message: "b'/my.CoolService/Query'" requires exactly one request message.

I believe the only way to send \0 bytes via curl is reading from a file / stdin, something like:

printf '\u0000....' | curl ... --data-binary '@-'
sampajano commented 5 months ago

@dimo414 Wow! Thanks for reporting this "subtle" issue.. 😄

I've filed a chrome bug and hope they might have an idea 😃

Thanks!

dimo414 commented 5 months ago

Thanks for passing it along @sampajano!