Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(493)

Side by Side Diff: server/prpc/encoding.go

Issue 1605363002: common/prpc, tools/cmd/cproto: prpc client (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@master
Patch Set: addressed comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package prpc 5 package prpc
6 6
7 // This file implements encoding of RPC results to HTTP responses. 7 // This file implements encoding of RPC results to HTTP responses.
8 8
9 import ( 9 import (
10 "bytes" 10 "bytes"
11 "io" 11 "io"
12 "net/http" 12 "net/http"
13 "sort" 13 "sort"
14 "strconv"
14 15
15 "github.com/golang/protobuf/jsonpb" 16 "github.com/golang/protobuf/jsonpb"
16 "github.com/golang/protobuf/proto" 17 "github.com/golang/protobuf/proto"
17 "golang.org/x/net/context" 18 "golang.org/x/net/context"
18 "google.golang.org/grpc" 19 "google.golang.org/grpc"
19 "google.golang.org/grpc/codes" 20 "google.golang.org/grpc/codes"
20 21
22 "github.com/luci/luci-go/common/errors"
21 "github.com/luci/luci-go/common/logging" 23 "github.com/luci/luci-go/common/logging"
24 "github.com/luci/luci-go/common/prpc"
22 ) 25 )
23 26
24 const ( 27 const (
25 headerAccept = "Accept" 28 headerAccept = "Accept"
26 ) 29 )
27 30
28 // responseFormat returns the format to be used in a response. 31 // responseFormat returns the format to be used in a response.
29 // Can return only formatBinary (preferred), formatJSONPB or formatText. 32 // Can return only formatBinary (preferred), formatJSONPB or formatText.
30 // In case of an error, format is undefined and the error has an HTTP status. 33 // In case of an error, format is undefined and the error has an HTTP status.
31 func responseFormat(acceptHeader string) (format, *httpError) { 34 func responseFormat(acceptHeader string) (format, *httpError) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 res = buf.Bytes() 110 res = buf.Bytes()
108 } 111 }
109 if err != nil { 112 if err != nil {
110 return err 113 return err
111 } 114 }
112 w.Header().Set(headerContentType, contentType) 115 w.Header().Set(headerContentType, contentType)
113 _, err = w.Write(res) 116 _, err = w.Write(res)
114 return err 117 return err
115 } 118 }
116 119
117 // codeToStatus maps gRPC codes to HTTP statuses.
118 // This map may need to be corrected when
119 // https://github.com/grpc/grpc-common/issues/210
120 // is closed.
121 var codeToStatus = map[codes.Code]int{
122 codes.OK: http.StatusOK,
123 codes.Canceled: http.StatusNoContent,
124 codes.Unknown: http.StatusInternalServerError,
125 codes.InvalidArgument: http.StatusBadRequest,
126 codes.DeadlineExceeded: http.StatusServiceUnavailable,
127 codes.NotFound: http.StatusNotFound,
128 codes.AlreadyExists: http.StatusConflict,
129 codes.PermissionDenied: http.StatusForbidden,
130 codes.Unauthenticated: http.StatusUnauthorized,
131 codes.ResourceExhausted: http.StatusServiceUnavailable,
132 codes.FailedPrecondition: http.StatusPreconditionFailed,
133 codes.Aborted: http.StatusInternalServerError,
134 codes.OutOfRange: http.StatusBadRequest,
135 codes.Unimplemented: http.StatusNotImplemented,
136 codes.Internal: http.StatusInternalServerError,
137 codes.Unavailable: http.StatusServiceUnavailable,
138 codes.DataLoss: http.StatusInternalServerError,
139 }
140
141 // ErrorStatus returns HTTP status for an error. 120 // ErrorStatus returns HTTP status for an error.
142 // In particular, it maps gRPC codes to HTTP statuses. 121 // In particular, it maps gRPC codes to HTTP statuses.
143 // Status of nil is 200. 122 // Status of nil is 200.
144 // 123 //
145 // See also grpc.Code. 124 // See also grpc.Code.
146 func ErrorStatus(err error) int { 125 func ErrorStatus(err error) int {
147 if err, ok := err.(*httpError); ok { 126 if err, ok := err.(*httpError); ok {
148 return err.status 127 return err.status
149 } 128 }
150 129
151 » status, ok := codeToStatus[grpc.Code(err)] 130 » status, ok := prpc.CodeStatus(grpc.Code(err))
152 if !ok { 131 if !ok {
153 status = http.StatusInternalServerError 132 status = http.StatusInternalServerError
154 } 133 }
155 return status 134 return status
156 } 135 }
157 136
158 // ErrorDesc returns the error description of err if it was produced by pRPC or gRPC. 137 // ErrorDesc returns the error description of err if it was produced by pRPC or gRPC.
159 // Otherwise, it returns err.Error() or empty string when err is nil. 138 // Otherwise, it returns err.Error() or empty string when err is nil.
160 // 139 //
161 // See also grpc.ErrorDesc. 140 // See also grpc.ErrorDesc.
(...skipping 17 matching lines...) Expand all
179 func writeError(c context.Context, w http.ResponseWriter, err error) { 158 func writeError(c context.Context, w http.ResponseWriter, err error) {
180 if err == nil { 159 if err == nil {
181 panic("err is nil") 160 panic("err is nil")
182 } 161 }
183 162
184 status := ErrorStatus(err) 163 status := ErrorStatus(err)
185 if status >= 500 { 164 if status >= 500 {
186 logging.Errorf(c, "HTTP %d: %s", status, ErrorDesc(err)) 165 logging.Errorf(c, "HTTP %d: %s", status, ErrorDesc(err))
187 } 166 }
188 167
168 w.Header().Set(prpc.HeaderGrpcCode, strconv.Itoa(int(grpcCode(err))))
189 w.Header().Set(headerContentType, "text/plain") 169 w.Header().Set(headerContentType, "text/plain")
190 w.WriteHeader(status) 170 w.WriteHeader(status)
191 171
192 var body string 172 var body string
193 if status == http.StatusInternalServerError { 173 if status == http.StatusInternalServerError {
194 body = "Internal server error" 174 body = "Internal server error"
195 } else { 175 } else {
196 body = ErrorDesc(err) 176 body = ErrorDesc(err)
197 } 177 }
198 if _, err := io.WriteString(w, body+"\n"); err != nil { 178 if _, err := io.WriteString(w, body+"\n"); err != nil {
199 logging.Errorf(c, "could not write error: %s", err) 179 logging.Errorf(c, "could not write error: %s", err)
200 } 180 }
201 } 181 }
202 182
183 // returns the most appropriate gRPC code for an error.
184 func grpcCode(err error) codes.Code {
185 if err == nil {
186 return codes.OK
187 }
188
189 for ; err != nil; err = errors.Unwrap(err) {
190 if code := grpc.Code(err); code != codes.Unknown {
191 return code
192 }
193
194 switch err {
195
196 case context.Canceled:
197 return codes.Canceled
198
199 case context.DeadlineExceeded:
200 return codes.DeadlineExceeded
201
202 }
203 }
204 return codes.Unknown
205 }
206
203 func assert(condition bool) { 207 func assert(condition bool) {
204 if !condition { 208 if !condition {
205 panicf("assertion failed") 209 panicf("assertion failed")
206 } 210 }
207 } 211 }
OLDNEW
« common/prpc/options.go ('K') | « common/retry/limited.go ('k') | server/prpc/error.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698