Chromium Code Reviews| 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" | |
| 8 "net/http" | 9 "net/http" | 
| 9 "sort" | 10 "sort" | 
| 10 "sync" | 11 "sync" | 
| 11 | 12 | 
| 12 "github.com/julienschmidt/httprouter" | 13 "github.com/julienschmidt/httprouter" | 
| 13 "golang.org/x/net/context" | 14 "golang.org/x/net/context" | 
| 14 "google.golang.org/grpc" | 15 "google.golang.org/grpc" | 
| 16 "google.golang.org/grpc/codes" | |
| 15 | 17 | 
| 18 "github.com/luci/luci-go/common/logging" | |
| 16 "github.com/luci/luci-go/server/auth" | 19 "github.com/luci/luci-go/server/auth" | 
| 17 "github.com/luci/luci-go/server/middleware" | 20 "github.com/luci/luci-go/server/middleware" | 
| 18 ) | 21 ) | 
| 19 | 22 | 
| 20 // Server is a pRPC server to serve RPC requests. | 23 // Server is a pRPC server to serve RPC requests. | 
| 21 // Zero value is valid. | 24 // Zero value is valid. | 
| 22 type Server struct { | 25 type Server struct { | 
| 23 // CustomAuthenticator, if true, disables the forced authentication set by | 26 // CustomAuthenticator, if true, disables the forced authentication set by | 
| 24 // RegisterDefaultAuth. | 27 // RegisterDefaultAuth. | 
| 25 CustomAuthenticator bool | 28 CustomAuthenticator bool | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 67 if a == nil { | 70 if a == nil { | 
| 68 panicf("prpc: CustomAuthenticator is false, but default authenti cator was not registered. " + | 71 panicf("prpc: CustomAuthenticator is false, but default authenti cator was not registered. " + | 
| 69 "Forgot to import appengine/gaeauth/server package?") | 72 "Forgot to import appengine/gaeauth/server package?") | 
| 70 } | 73 } | 
| 71 | 74 | 
| 72 return func(h middleware.Handler) httprouter.Handle { | 75 return func(h middleware.Handler) httprouter.Handle { | 
| 73 return base(func(c context.Context, w http.ResponseWriter, r *ht tp.Request, p httprouter.Params) { | 76 return base(func(c context.Context, w http.ResponseWriter, r *ht tp.Request, p httprouter.Params) { | 
| 74 c = auth.SetAuthenticator(c, a) | 77 c = auth.SetAuthenticator(c, a) | 
| 75 c, err := a.Authenticate(c, r) | 78 c, err := a.Authenticate(c, r) | 
| 76 if err != nil { | 79 if err != nil { | 
| 77 » » » » writeError(c, w, withStatus(err, http.StatusUnau thorized)) | 80 » » » » res := errResponse(codes.Unauthenticated, http.S tatusUnauthorized, err.Error()) | 
| 81 » » » » res.write(c, w) | |
| 78 return | 82 return | 
| 79 } | 83 } | 
| 80 h(c, w, r, p) | 84 h(c, w, r, p) | 
| 81 }) | 85 }) | 
| 82 } | 86 } | 
| 83 } | 87 } | 
| 84 | 88 | 
| 85 // InstallHandlers installs HTTP POST handlers at | 89 // InstallHandlers installs HTTP handlers at /prpc/:service/:method. | 
| 86 // /prpc/{service_name}/{method_name} for all registered services. | 90 // See https://godoc.org/github.com/luci/luci-go/common/prpc#hdr-Protocol | 
| 91 // for pRPC protocol. | |
| 87 func (s *Server) InstallHandlers(r *httprouter.Router, base middleware.Base) { | 92 func (s *Server) InstallHandlers(r *httprouter.Router, base middleware.Base) { | 
| 88 s.mu.Lock() | 93 s.mu.Lock() | 
| 89 defer s.mu.Unlock() | 94 defer s.mu.Unlock() | 
| 90 | 95 | 
| 91 if !s.CustomAuthenticator { | 96 if !s.CustomAuthenticator { | 
| 92 base = s.authenticate(base) | 97 base = s.authenticate(base) | 
| 93 } | 98 } | 
| 94 | 99 | 
| 95 » for _, service := range s.services { | 100 » const path = "/prpc/:service/:method" | 
| 96 » » for _, m := range service.methods { | 101 » handle := base(s.handle) | 
| 97 » » » m.InstallHandlers(r, base) | 102 » r.POST(path, handle) | 
| 
 
dnj (Google)
2016/01/26 16:13:57
Do we need to support all of these methods? I thou
 
nodir
2016/01/26 18:01:07
We had this discussion and decided to handle all m
 
dnj
2016/01/26 18:50:27
Seems pointless, but OK. IMO either a client knows
 
nodir
2016/01/26 19:06:09
ah, Server.handle was exported at some point, that
 
 | |
| 98 » » } | 103 » r.GET(path, handle) | 
| 104 » r.PUT(path, handle) | |
| 105 » r.DELETE(path, handle) | |
| 106 » r.PATCH(path, handle) | |
| 107 } | |
| 108 | |
| 109 // handle handles RPCs. | |
| 110 // See https://godoc.org/github.com/luci/luci-go/common/prpc#hdr-Protocol | |
| 111 // for pRPC protocol. | |
| 112 func (s *Server) handle(c context.Context, w http.ResponseWriter, r *http.Reques t, p httprouter.Params) { | |
| 113 » res := s.respond(c, w, r, p) | |
| 
 
dnj (Google)
2016/01/26 16:13:57
nit: pull service/method out of params up front, t
 
nodir
2016/01/26 18:01:07
Done.
 
 | |
| 114 | |
| 115 » c = logging.SetFields(c, logging.Fields{ | |
| 116 » » "Service": p.ByName("service"), | |
| 117 » » "Method": p.ByName("method"), | |
| 118 » }) | |
| 119 » res.write(c, w) | |
| 120 } | |
| 121 | |
| 122 func (s *Server) respond(c context.Context, w http.ResponseWriter, r *http.Reque st, p httprouter.Params) *response { | |
| 123 » if r.Method != "POST" { | |
| 124 » » return errResponse(codes.Unimplemented, http.StatusMethodNotAllo wed, "HTTP method must be POST") | |
| 99 } | 125 } | 
| 126 | |
| 127 serviceName := p.ByName("service") | |
| 128 service := s.services[serviceName] | |
| 129 if service == nil { | |
| 130 return errResponse( | |
| 131 codes.Unimplemented, | |
| 132 http.StatusNotImplemented, | |
| 133 fmt.Sprintf("service %q is not implemented", serviceName )) | |
| 134 } | |
| 135 | |
| 136 methodName := p.ByName("method") | |
| 137 method := service.methods[methodName] | |
| 138 if method == nil { | |
| 139 return errResponse( | |
| 140 codes.Unimplemented, | |
| 141 http.StatusNotImplemented, | |
| 142 fmt.Sprintf("method %q in service %q is not implemented" , methodName, serviceName)) | |
| 143 } | |
| 144 | |
| 145 return method.handle(c, w, r) | |
| 100 } | 146 } | 
| 101 | 147 | 
| 102 // ServiceNames returns a sorted list of full names of all registered services. | 148 // ServiceNames returns a sorted list of full names of all registered services. | 
| 103 func (s *Server) ServiceNames() []string { | 149 func (s *Server) ServiceNames() []string { | 
| 104 s.mu.Lock() | 150 s.mu.Lock() | 
| 105 defer s.mu.Unlock() | 151 defer s.mu.Unlock() | 
| 106 | 152 | 
| 107 names := make([]string, 0, len(s.services)) | 153 names := make([]string, 0, len(s.services)) | 
| 108 for name := range s.services { | 154 for name := range s.services { | 
| 109 names = append(names, name) | 155 names = append(names, name) | 
| 110 } | 156 } | 
| 111 sort.Strings(names) | 157 sort.Strings(names) | 
| 112 return names | 158 return names | 
| 113 } | 159 } | 
| OLD | NEW |