OLD | NEW |
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 import ( | 7 import ( |
8 "fmt" | |
9 "net/http" | 8 "net/http" |
10 | 9 |
11 "github.com/golang/protobuf/proto" | 10 "github.com/golang/protobuf/proto" |
12 "github.com/julienschmidt/httprouter" | |
13 "golang.org/x/net/context" | 11 "golang.org/x/net/context" |
14 "google.golang.org/grpc" | 12 "google.golang.org/grpc" |
| 13 "google.golang.org/grpc/codes" |
15 | 14 |
16 » "github.com/luci/luci-go/server/middleware" | 15 » "github.com/luci/luci-go/common/grpcutil" |
17 ) | 16 ) |
18 | 17 |
19 type method struct { | 18 type method struct { |
20 service *service | 19 service *service |
21 desc grpc.MethodDesc | 20 desc grpc.MethodDesc |
22 } | 21 } |
23 | 22 |
24 func (m *method) Name() string { | |
25 return m.desc.MethodName | |
26 } | |
27 | |
28 // Handle decodes an input protobuf message from the HTTP request, | |
29 // delegates RPC handling to the inner implementation and | |
30 // encodes the output message back to the HTTP response. | |
31 // | |
32 // If the inner handler returns an error, HTTP status is determined using | |
33 // ErrorStatus. | |
34 // If the status is http.StatusInternalServerError, only "Internal server error" | |
35 // is printed. | |
36 // All errors with status >= 500 are logged. | |
37 func (m *method) Handle(c context.Context, w http.ResponseWriter, r *http.Reques
t, _ httprouter.Params) { | |
38 if err := m.handle(c, w, r); err != nil { | |
39 writeError(c, w, err) | |
40 } | |
41 } | |
42 | |
43 // handle decodes an input protobuf message from the HTTP request, | 23 // handle decodes an input protobuf message from the HTTP request, |
44 // delegates RPC handling to the inner implementation and | 24 // delegates RPC handling to the inner implementation and |
45 // encodes the output message back to the HTTP response. | 25 // encodes the output message back to the HTTP response. |
46 func (m *method) handle(c context.Context, w http.ResponseWriter, r *http.Reques
t) *httpError { | 26 // |
| 27 // If the inner handler returns an error, HTTP status is determined using |
| 28 // errorStatus. |
| 29 // Prints only "Internal server error" if the code is Internal. |
| 30 // Logs the error if code is Internal or Unknown. |
| 31 func (m *method) handle(c context.Context, w http.ResponseWriter, r *http.Reques
t) *response { |
47 defer r.Body.Close() | 32 defer r.Body.Close() |
48 » format, err := responseFormat(r.Header.Get(headerAccept)) | 33 |
49 » if err != nil { | 34 » format, perr := responseFormat(r.Header.Get(headerAccept)) |
50 » » return err | 35 » if perr != nil { |
| 36 » » return respondProtocolError(perr) |
51 } | 37 } |
52 | 38 |
53 » c, rawErr := parseHeader(c, r.Header) | 39 » c, err := parseHeader(c, r.Header) |
54 » if rawErr != nil { | 40 » if err != nil { |
55 » » return withStatus(rawErr, http.StatusBadRequest) | 41 » » return respondProtocolError(withStatus(err, http.StatusBadReques
t)) |
56 } | 42 } |
57 | 43 |
58 » res, rawErr := m.desc.Handler(m.service.impl, c, func(msg interface{}) e
rror { | 44 » out, err := m.desc.Handler(m.service.impl, c, func(in interface{}) error
{ |
59 » » if msg == nil { | 45 » » if in == nil { |
60 » » » panicf("cannot decode to nil") | 46 » » » return grpcutil.Errf(codes.Internal, "input message is n
il") |
61 } | 47 } |
62 // Do not collapse it to one line. There is implicit err type co
nversion. | 48 // Do not collapse it to one line. There is implicit err type co
nversion. |
63 » » if err := readMessage(r, msg.(proto.Message)); err != nil { | 49 » » if perr := readMessage(r, in.(proto.Message)); perr != nil { |
64 » » » return err | 50 » » » return perr |
65 } | 51 } |
66 return nil | 52 return nil |
67 }) | 53 }) |
68 » if rawErr != nil { | 54 » if err != nil { |
69 » » if err, ok := rawErr.(*httpError); ok { | 55 » » if perr, ok := err.(*protocolError); ok { |
70 » » » return err | 56 » » » return respondProtocolError(perr) |
71 } | 57 } |
72 » » return withStatus(rawErr, ErrorStatus(rawErr)) | 58 » » return errResponse(errorCode(err), 0, grpc.ErrorDesc(err)) |
73 } | 59 } |
74 » if res == nil { | 60 |
75 » » return m.internalServerError("service returned nil message") | 61 » if out == nil { |
| 62 » » return errResponse(codes.Internal, 0, "service returned nil mess
age") |
76 } | 63 } |
77 » if err := writeMessage(w, res.(proto.Message), format); err != nil { | 64 » return respondMessage(out.(proto.Message), format) |
78 » » return m.internalServerError("could not respond: %s", err) | |
79 » } | |
80 » return nil | |
81 } | 65 } |
82 | |
83 // InstallHandlers installs a POST HTTP handlers at /prpc/{service_name}/{method
_name}. | |
84 func (m *method) InstallHandlers(r *httprouter.Router, base middleware.Base) { | |
85 path := fmt.Sprintf("/prpc/%s/%s", m.service.Name(), m.Name()) | |
86 r.POST(path, base(m.Handle)) | |
87 } | |
88 | |
89 func (m *method) internalServerError(format string, a ...interface{}) *httpError
{ | |
90 format = fmt.Sprintf("%s.%s: ", m.service.Name(), m.Name()) + format | |
91 return errorf(http.StatusInternalServerError, format, a...) | |
92 } | |
OLD | NEW |