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

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

Issue 2043423004: Make HTTP middleware easier to use (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: Update tests Created 4 years, 6 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 LUCI Authors. All rights reserved. 1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package prpc 5 package prpc
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "net/http" 9 "net/http"
10 "sort" 10 "sort"
11 "strings" 11 "strings"
12 "sync" 12 "sync"
13 13
14 "github.com/julienschmidt/httprouter"
15 "golang.org/x/net/context" 14 "golang.org/x/net/context"
16 "google.golang.org/grpc" 15 "google.golang.org/grpc"
17 "google.golang.org/grpc/codes" 16 "google.golang.org/grpc/codes"
18 17
19 "github.com/luci/luci-go/common/errors" 18 "github.com/luci/luci-go/common/errors"
20 "github.com/luci/luci-go/common/logging" 19 "github.com/luci/luci-go/common/logging"
21 "github.com/luci/luci-go/server/auth" 20 "github.com/luci/luci-go/server/auth"
22 » "github.com/luci/luci-go/server/middleware" 21 » "github.com/luci/luci-go/server/router"
23 22
24 prpccommon "github.com/luci/luci-go/common/prpc" 23 prpccommon "github.com/luci/luci-go/common/prpc"
25 ) 24 )
26 25
27 var ( 26 var (
28 // Describe the permitted Access Control requests. 27 // Describe the permitted Access Control requests.
29 allowHeaders = strings.Join([]string{"Origin", "Content-Type", "Accept"} , ", ") 28 allowHeaders = strings.Join([]string{"Origin", "Content-Type", "Accept"} , ", ")
30 allowMethods = strings.Join([]string{"OPTIONS", "POST"}, ", ") 29 allowMethods = strings.Join([]string{"OPTIONS", "POST"}, ", ")
31 30
32 // allowPreflightCacheAgeSecs is the amount of time to enable the browse r to 31 // allowPreflightCacheAgeSecs is the amount of time to enable the browse r to
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 if s.services == nil { 99 if s.services == nil {
101 s.services = map[string]*service{} 100 s.services = map[string]*service{}
102 } else if _, ok := s.services[desc.ServiceName]; ok { 101 } else if _, ok := s.services[desc.ServiceName]; ok {
103 panic(fmt.Errorf("service %q is already registered", desc.Servic eName)) 102 panic(fmt.Errorf("service %q is already registered", desc.Servic eName))
104 } 103 }
105 104
106 s.services[desc.ServiceName] = serv 105 s.services[desc.ServiceName] = serv
107 } 106 }
108 107
109 // authenticate forces authentication set by RegisterDefaultAuth. 108 // authenticate forces authentication set by RegisterDefaultAuth.
110 func (s *Server) authenticate(base middleware.Base) middleware.Base { 109 func (s *Server) authenticate() router.Handler {
111 a := s.Authenticator 110 a := s.Authenticator
112 if a == nil { 111 if a == nil {
113 a = GetDefaultAuth() 112 a = GetDefaultAuth()
114 if a == nil { 113 if a == nil {
115 panic("prpc: no custom Authenticator was provided and de fault authenticator was not registered. " + 114 panic("prpc: no custom Authenticator was provided and de fault authenticator was not registered. " +
116 "Forgot to import appengine/gaeauth/server packa ge?") 115 "Forgot to import appengine/gaeauth/server packa ge?")
117 } 116 }
118 } 117 }
119 118
120 if len(a) == 0 { 119 if len(a) == 0 {
121 » » return base 120 » » return router.VoidHandler
122 } 121 }
123 122
124 » return func(h middleware.Handler) httprouter.Handle { 123 » return func(c *router.Context) {
125 » » return base(func(c context.Context, w http.ResponseWriter, r *ht tp.Request, p httprouter.Params) { 124 » » c.Context = auth.SetAuthenticator(c.Context, a)
126 » » » c = auth.SetAuthenticator(c, a) 125 » » var err error
127 » » » switch c, err := a.Authenticate(c, r); { 126 » » switch c.Context, err = a.Authenticate(c.Context, c.Request); {
128 » » » case errors.IsTransient(err): 127 » » case errors.IsTransient(err):
129 » » » » res := errResponse(codes.Internal, http.StatusIn ternalServerError, escapeFmt(err.Error())) 128 » » » res := errResponse(codes.Internal, http.StatusInternalSe rverError, escapeFmt(err.Error()))
130 » » » » res.write(c, w) 129 » » » res.write(c.Context, c.Writer)
131 » » » case err != nil: 130 » » » c.Abort()
132 » » » » res := errResponse(codes.Unauthenticated, http.S tatusUnauthorized, escapeFmt(err.Error())) 131 » » case err != nil:
133 » » » » res.write(c, w) 132 » » » res := errResponse(codes.Unauthenticated, http.StatusUna uthorized, escapeFmt(err.Error()))
134 » » » default: 133 » » » res.write(c.Context, c.Writer)
135 » » » » h(c, w, r, p) 134 » » » c.Abort()
136 » » » } 135 » » }
137 » » })
138 } 136 }
139 } 137 }
140 138
141 // InstallHandlers installs HTTP handlers at /prpc/:service/:method. 139 // InstallHandlers installs HTTP handlers at /prpc/:service/:method.
142 // 140 //
143 // See https://godoc.org/github.com/luci/luci-go/common/prpc#hdr-Protocol 141 // See https://godoc.org/github.com/luci/luci-go/common/prpc#hdr-Protocol
144 // for pRPC protocol. 142 // for pRPC protocol.
145 // 143 //
146 // The authenticator in 'base' is always replaced by pRPC specific one. For more 144 // The authenticator in 'base' is always replaced by pRPC specific one. For more
147 // details about the authentication see Server.Authenticator doc. 145 // details about the authentication see Server.Authenticator doc.
148 func (s *Server) InstallHandlers(r *httprouter.Router, base middleware.Base) { 146 func (s *Server) InstallHandlers(r *router.Router, handlers []router.Handler) {
149 s.mu.Lock() 147 s.mu.Lock()
150 defer s.mu.Unlock() 148 defer s.mu.Unlock()
151 149
152 » base = s.authenticate(base) 150 » r.POST("/prpc/:service/:method", append(handlers, s.authenticate(), s.ha ndlePOST)...)
153 151 » r.OPTIONS("/prpc/:service/:method", append(handlers, s.authenticate(), s .handleOPTIONS)...)
154 » r.POST("/prpc/:service/:method", base(s.handlePOST))
155 » r.OPTIONS("/prpc/:service/:method", base(s.handleOPTIONS))
156 } 152 }
157 153
158 // handle handles RPCs. 154 // handle handles RPCs.
159 // See https://godoc.org/github.com/luci/luci-go/common/prpc#hdr-Protocol 155 // See https://godoc.org/github.com/luci/luci-go/common/prpc#hdr-Protocol
160 // for pRPC protocol. 156 // for pRPC protocol.
161 func (s *Server) handlePOST(c context.Context, w http.ResponseWriter, r *http.Re quest, p httprouter.Params) { 157 func (s *Server) handlePOST(c *router.Context) {
162 » serviceName := p.ByName("service") 158 » serviceName := c.Params.ByName("service")
163 » methodName := p.ByName("method") 159 » methodName := c.Params.ByName("method")
164 » res := s.respond(c, w, r, serviceName, methodName) 160 » res := s.respond(c.Context, c.Writer, c.Request, serviceName, methodName )
165 161
166 » c = logging.SetFields(c, logging.Fields{ 162 » c.Context = logging.SetFields(c.Context, logging.Fields{
167 "service": serviceName, 163 "service": serviceName,
168 "method": methodName, 164 "method": methodName,
169 }) 165 })
170 » s.setAccessControlHeaders(c, r, w, false) 166 » s.setAccessControlHeaders(c.Context, c.Request, c.Writer, false)
171 » res.write(c, w) 167 » res.write(c.Context, c.Writer)
172 } 168 }
173 169
174 func (s *Server) handleOPTIONS(c context.Context, w http.ResponseWriter, r *http .Request, p httprouter.Params) { 170 func (s *Server) handleOPTIONS(c *router.Context) {
175 » s.setAccessControlHeaders(c, r, w, true) 171 » s.setAccessControlHeaders(c.Context, c.Request, c.Writer, true)
176 » w.WriteHeader(http.StatusOK) 172 » c.Writer.WriteHeader(http.StatusOK)
177 } 173 }
178 174
179 func (s *Server) respond(c context.Context, w http.ResponseWriter, r *http.Reque st, serviceName, methodName string) *response { 175 func (s *Server) respond(c context.Context, w http.ResponseWriter, r *http.Reque st, serviceName, methodName string) *response {
180 service := s.services[serviceName] 176 service := s.services[serviceName]
181 if service == nil { 177 if service == nil {
182 return errResponse( 178 return errResponse(
183 codes.Unimplemented, 179 codes.Unimplemented,
184 http.StatusNotImplemented, 180 http.StatusNotImplemented,
185 "service %q is not implemented", 181 "service %q is not implemented",
186 serviceName) 182 serviceName)
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 s.mu.Lock() 221 s.mu.Lock()
226 defer s.mu.Unlock() 222 defer s.mu.Unlock()
227 223
228 names := make([]string, 0, len(s.services)) 224 names := make([]string, 0, len(s.services))
229 for name := range s.services { 225 for name := range s.services {
230 names = append(names, name) 226 names = append(names, name)
231 } 227 }
232 sort.Strings(names) 228 sort.Strings(names)
233 return names 229 return names
234 } 230 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698