| Index: server/prpc/encoding.go
|
| diff --git a/server/prpc/encoding.go b/server/prpc/encoding.go
|
| index 2788e2e29d1d8b4a2a4b50380368de5e54399482..e6c010642695ac391c72a84c92cc74ebef3860fb 100644
|
| --- a/server/prpc/encoding.go
|
| +++ b/server/prpc/encoding.go
|
| @@ -11,6 +11,7 @@ import (
|
| "io"
|
| "net/http"
|
| "sort"
|
| + "strconv"
|
|
|
| "github.com/golang/protobuf/jsonpb"
|
| "github.com/golang/protobuf/proto"
|
| @@ -18,7 +19,9 @@ import (
|
| "google.golang.org/grpc"
|
| "google.golang.org/grpc/codes"
|
|
|
| + "github.com/luci/luci-go/common/errors"
|
| "github.com/luci/luci-go/common/logging"
|
| + "github.com/luci/luci-go/common/prpc"
|
| )
|
|
|
| const (
|
| @@ -114,30 +117,6 @@ func writeMessage(w http.ResponseWriter, msg proto.Message, format format) error
|
| return err
|
| }
|
|
|
| -// codeToStatus maps gRPC codes to HTTP statuses.
|
| -// This map may need to be corrected when
|
| -// https://github.com/grpc/grpc-common/issues/210
|
| -// is closed.
|
| -var codeToStatus = map[codes.Code]int{
|
| - codes.OK: http.StatusOK,
|
| - codes.Canceled: http.StatusNoContent,
|
| - codes.Unknown: http.StatusInternalServerError,
|
| - codes.InvalidArgument: http.StatusBadRequest,
|
| - codes.DeadlineExceeded: http.StatusServiceUnavailable,
|
| - codes.NotFound: http.StatusNotFound,
|
| - codes.AlreadyExists: http.StatusConflict,
|
| - codes.PermissionDenied: http.StatusForbidden,
|
| - codes.Unauthenticated: http.StatusUnauthorized,
|
| - codes.ResourceExhausted: http.StatusServiceUnavailable,
|
| - codes.FailedPrecondition: http.StatusPreconditionFailed,
|
| - codes.Aborted: http.StatusInternalServerError,
|
| - codes.OutOfRange: http.StatusBadRequest,
|
| - codes.Unimplemented: http.StatusNotImplemented,
|
| - codes.Internal: http.StatusInternalServerError,
|
| - codes.Unavailable: http.StatusServiceUnavailable,
|
| - codes.DataLoss: http.StatusInternalServerError,
|
| -}
|
| -
|
| // ErrorStatus returns HTTP status for an error.
|
| // In particular, it maps gRPC codes to HTTP statuses.
|
| // Status of nil is 200.
|
| @@ -148,7 +127,7 @@ func ErrorStatus(err error) int {
|
| return err.status
|
| }
|
|
|
| - status, ok := codeToStatus[grpc.Code(err)]
|
| + status, ok := prpc.CodeStatus(grpc.Code(err))
|
| if !ok {
|
| status = http.StatusInternalServerError
|
| }
|
| @@ -186,6 +165,7 @@ func writeError(c context.Context, w http.ResponseWriter, err error) {
|
| logging.Errorf(c, "HTTP %d: %s", status, ErrorDesc(err))
|
| }
|
|
|
| + w.Header().Set(prpc.HeaderGrpcCode, strconv.Itoa(int(grpcCode(err))))
|
| w.Header().Set(headerContentType, "text/plain")
|
| w.WriteHeader(status)
|
|
|
| @@ -200,6 +180,30 @@ func writeError(c context.Context, w http.ResponseWriter, err error) {
|
| }
|
| }
|
|
|
| +// returns the most appropriate gRPC code for an error.
|
| +func grpcCode(err error) codes.Code {
|
| + if err == nil {
|
| + return codes.OK
|
| + }
|
| +
|
| + for ; err != nil; err = errors.Unwrap(err) {
|
| + if code := grpc.Code(err); code != codes.Unknown {
|
| + return code
|
| + }
|
| +
|
| + switch err {
|
| +
|
| + case context.Canceled:
|
| + return codes.Canceled
|
| +
|
| + case context.DeadlineExceeded:
|
| + return codes.DeadlineExceeded
|
| +
|
| + }
|
| + }
|
| + return codes.Unknown
|
| +}
|
| +
|
| func assert(condition bool) {
|
| if !condition {
|
| panicf("assertion failed")
|
|
|