Chromium Code Reviews| Index: server/prpc/encoding.go |
| diff --git a/server/prpc/encoding.go b/server/prpc/encoding.go |
| index 2788e2e29d1d8b4a2a4b50380368de5e54399482..f02423850fb467447713a5bc75275074a6c63360 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,11 +19,14 @@ 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 ( |
| - headerAccept = "Accept" |
| + headerAccept = "Accept" |
| + headerGRPCCode = "X-Prpc-Grpc-Code" |
|
dnj
2016/01/21 07:44:28
Make this exported and reuse it in client? No poin
nodir
2016/01/22 00:47:24
Done, but vice-versa: common cannot import server
|
| ) |
| // responseFormat returns the format to be used in a response. |
| @@ -114,30 +118,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 +128,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 +166,7 @@ func writeError(c context.Context, w http.ResponseWriter, err error) { |
| logging.Errorf(c, "HTTP %d: %s", status, ErrorDesc(err)) |
| } |
| + w.Header().Set(headerGRPCCode, strconv.Itoa(int(grpcCode(err)))) |
| w.Header().Set(headerContentType, "text/plain") |
| w.WriteHeader(status) |
| @@ -200,6 +181,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") |