Fix crashes where transports returned errors unhandled by the message parser.

The http.Handler-based transport body reader was returning error types
not understood by the recvMsg parser. See #557 for some background and
examples.

Fix the http.Handler transport and add tests. I copied in a subset of
the http2 package's serverTest type, adapted slightly to work with
grpc. In the process of adding tests, I discovered that
ErrUnexpectedEOF was also not handled by the regular server
transport. Document the rules and fix that crash as well.

Unrelated stuff in this CL:

* make tests listen on localhost:0 instead of :0, to avoid Mac firewall
  pop-up dialogs.

* rename parser.s field to parser.r, to be more idiomatic that it's an
  io.Reader and not anything fancier. (it's not acting like type
  stream, even if that's the typical concrete type)

* move 5 byte temp buffer into parser, rather than allocating it for
  each new message. (drop in the bucket improvement in garbage; more
  to do later)

* rename http2RSTErrConvTab to http2ErrConvTab, per Qi's earlier
  CL. Also add the HTTP/1.1-required error mapping for completeness,
  not that it should ever arise with gRPC, also per Qi's earlier CL
  referenced in #557.
This commit is contained in:
Brad Fitzpatrick
2016-02-24 08:32:08 -08:00
parent 178b68e281
commit 110fd99e30
12 changed files with 532 additions and 31 deletions

View File

@ -446,13 +446,16 @@ func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.
}
}()
}
p := &parser{s: stream}
p := &parser{r: stream}
for {
pf, req, err := p.recvMsg()
if err == io.EOF {
// The entire stream is done (for unary RPC only).
return err
}
if err == io.ErrUnexpectedEOF {
err = transport.StreamError{Code: codes.Internal, Desc: "io.ErrUnexpectedEOF"}
}
if err != nil {
switch err := err.(type) {
case transport.ConnectionError:
@ -558,7 +561,7 @@ func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transp
ss := &serverStream{
t: t,
s: stream,
p: &parser{s: stream},
p: &parser{r: stream},
codec: s.opts.codec,
cp: s.opts.cp,
dc: s.opts.dc,