| 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 |