{"action":"created","issue":{"url":"https://api.github.com/repos/grpc-ecosystem/grpc-gateway/issues/195","repository_url":"https://api.github.com/repos/grpc-ecosystem/grpc-gateway","labels_url":"https://api.github.com/repos/grpc-ecosystem/grpc-gateway/issues/195/labels{/name}","comments_url":"https://api.github.com/repos/grpc-ecosystem/grpc-gateway/issues/195/comments","events_url":"https://api.github.com/repos/grpc-ecosystem/grpc-gateway/issues/195/events","html_url":"https://github.com/grpc-ecosystem/grpc-gateway/issues/195","id":166139407,"number":195,"title":"marshaler runtime.Marshaler does not handle io.EOF when decoding","user":{"login":"gyuho","id":6799218,"avatar_url":"https://avatars.githubusercontent.com/u/6799218?v=3","gravatar_id":"","url":"https://api.github.com/users/gyuho","html_url":"https://github.com/gyuho","followers_url":"https://api.github.com/users/gyuho/followers","following_url":"https://api.github.com/users/gyuho/following{/other_user}","gists_url":"https://api.github.com/users/gyuho/gists{/gist_id}","starred_url":"https://api.github.com/users/gyuho/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gyuho/subscriptions","organizations_url":"https://api.github.com/users/gyuho/orgs","repos_url":"https://api.github.com/users/gyuho/repos","events_url":"https://api.github.com/users/gyuho/events{/privacy}","received_events_url":"https://api.github.com/users/gyuho/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2016-07-18T16:45:44Z","updated_at":"2016-07-26T03:00:20Z","closed_at":null,"body":"Hi,\r\n\r\nafter resolving `golang/protobuf/jsonpb` compatibility issue, we found another issue with json decoder\r\n\r\nDetails can be found at https://github.com/coreos/etcd/pull/5969#issuecomment-233384529.\r\n\r\nTo summarize\r\n\r\n`dec.Decode(&protoReq)` returns `io.EOF` in this code (full generated code can be found https://github.com/coreos/etcd/blob/master/etcdserver/etcdserverpb/rpc.pb.gw.go#L92-L93):\r\n\r\n```go\r\nfunc request_Watch_Watch_0(ctx context.Context, marshaler runtime.Marshaler, client WatchClient, req *http.Request, pathParams map[string]string) (Watch_WatchClient, runtime.ServerMetadata, error) {\r\n\tvar metadata runtime.ServerMetadata\r\n\tstream, err := client.Watch(ctx)\r\n\tif err != nil {\r\n\t\tgrpclog.Printf(\"Failed to start streaming: %v\", err)\r\n\t\treturn nil, metadata, err\r\n\t}\r\n\tdec := marshaler.NewDecoder(req.Body)\r\n\thandleSend := func() error {\r\n\t\tvar protoReq WatchRequest\r\n\t\terr = dec.Decode(&protoReq)\r\n\t\tif err != nil {\r\n\t\t\tgrpclog.Printf(\"Failed to decode request: %v\", err)\r\n\t\t\treturn err\r\n\t\t}\r\n\t\tif err = stream.Send(&protoReq); err != nil {\r\n\t\t\tgrpclog.Printf(\"Failed to send request: %v\", err)\r\n\t\t\treturn err\r\n\t\t}\r\n\t\treturn nil\r\n\t}\r\n```\r\n\r\nBut if we manually make it handle `io.EOF` as below:\r\n\r\n```diff\r\n        dec := marshaler.NewDecoder(req.Body)\r\n        handleSend := func() error {\r\n                var protoReq WatchRequest\r\n                err = dec.Decode(&protoReq)\r\n-               if err != nil {\r\n+               if err != nil && err != io.EOF {\r\n```\r\n\r\nwhere `req.Body` is `{\"create_request\": {\"key\": \"Zm9v\"}}`, everything works as expected.\r\n\r\nIs there any way to make this decoder handle `io.EOF`?\r\n\r\nThanks."},"comment":{"url":"https://api.github.com/repos/grpc-ecosystem/grpc-gateway/issues/comments/235149516","html_url":"https://github.com/grpc-ecosystem/grpc-gateway/issues/195#issuecomment-235149516","issue_url":"https://api.github.com/repos/grpc-ecosystem/grpc-gateway/issues/195","id":235149516,"user":{"login":"yugui","id":8161,"avatar_url":"https://avatars.githubusercontent.com/u/8161?v=3","gravatar_id":"","url":"https://api.github.com/users/yugui","html_url":"https://github.com/yugui","followers_url":"https://api.github.com/users/yugui/followers","following_url":"https://api.github.com/users/yugui/following{/other_user}","gists_url":"https://api.github.com/users/yugui/gists{/gist_id}","starred_url":"https://api.github.com/users/yugui/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/yugui/subscriptions","organizations_url":"https://api.github.com/users/yugui/orgs","repos_url":"https://api.github.com/users/yugui/repos","events_url":"https://api.github.com/users/yugui/events{/privacy}","received_events_url":"https://api.github.com/users/yugui/received_events","type":"User","site_admin":false},"created_at":"2016-07-26T03:00:20Z","updated_at":"2016-07-26T03:00:20Z","body":"> why we were sending zero-length input in the first place\r\n\r\nI don't think we are sending zero-length input. #200 just fixes an edge-case bug which can happen when the stream is empty.\r\nAlso the very first invocation of `handleSend` is different from the later ones just because let the caller know errors earlier.\r\n\r\n> The print statement returns {\"create_request\": {\"key\": \"Zm9v\"}} <nil>, so the request body was not empty, but dec.Decode(&protoReq) returns io.EOF, which doesn't make sense. Is this expected? Or some kind of grpc-specific behavior?\r\n\r\nI can't reproduce.\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"strings\"\r\n\r\n\t\"github.com/grpc-ecosystem/grpc-gateway/runtime\"\r\n)\r\n\r\nfunc main() {\r\n\tvar m runtime.JSONPb\r\n\tdec := m.NewDecoder(strings.NewReader(`{\"create_request\": {\"key\": \"Zm9v\"}}`))\r\n\r\n\tmsg := make(map[string]interface{})\r\n\tif err := dec.Decode(&msg); err != nil {\r\n\t\tfmt.Println(msg, err)\r\n\t\treturn\r\n\t}\r\n\tfmt.Println(msg)\r\n}\r\n```"}}
{"actor":{"display_login":"yugui"}}