blob: 9acd92b1405884e43ebc7692c630a120eba03cef [file] [log] [blame]
Jiri Simsa78b646f2014-10-08 10:23:05 -07001// The app package contains the struct that keeps per javascript app state and handles translating
2// javascript requests to veyron requests and vice versa.
3package app
4
5import (
6 "bytes"
7 "encoding/json"
8 "flag"
9 "fmt"
10 "io"
11 "sync"
12 "time"
13
Ankure7889242014-10-20 18:37:29 -070014 vsecurity "veyron.io/veyron/veyron/security"
Jiri Simsa78b646f2014-10-08 10:23:05 -070015 "veyron.io/veyron/veyron2"
16 "veyron.io/veyron/veyron2/context"
17 "veyron.io/veyron/veyron2/ipc"
Asim Shankarf3c61a32014-10-15 17:34:11 -070018 "veyron.io/veyron/veyron2/options"
Jiri Simsa78b646f2014-10-08 10:23:05 -070019 "veyron.io/veyron/veyron2/rt"
20 "veyron.io/veyron/veyron2/security"
Mike Burrowsb6689c22014-10-08 11:14:15 -070021 "veyron.io/veyron/veyron2/verror2"
Jiri Simsa78b646f2014-10-08 10:23:05 -070022 "veyron.io/veyron/veyron2/vlog"
23 "veyron.io/veyron/veyron2/vom"
24 vom_wiretype "veyron.io/veyron/veyron2/vom/wiretype"
25 wiretype_build "veyron.io/veyron/veyron2/wiretype/build"
Jiri Simsa78b646f2014-10-08 10:23:05 -070026 "veyron.io/wspr/veyron/services/wsprd/ipc/server"
27 "veyron.io/wspr/veyron/services/wsprd/lib"
Ali Ghassemiaa0ea242014-10-20 12:55:39 -070028 "veyron.io/wspr/veyron/services/wsprd/namespace"
Ankure7889242014-10-20 18:37:29 -070029 "veyron.io/wspr/veyron/services/wsprd/principal"
Jiri Simsa78b646f2014-10-08 10:23:05 -070030 "veyron.io/wspr/veyron/services/wsprd/signature"
31)
32
Mike Burrowsb6689c22014-10-08 11:14:15 -070033// pkgPath is the prefix os errors in this package.
34const pkgPath = "veyron.io/veyron/veyron/services/wsprd/app"
35
36// Errors
Ankure7889242014-10-20 18:37:29 -070037var (
38 marshallingError = verror2.Register(pkgPath+".marshallingError", verror2.NoRetry, "{1} {2} marshalling error {_}")
39 noResults = verror2.Register(pkgPath+".noResults", verror2.NoRetry, "{1} {2} no results from call {_}")
40 signatureError = verror2.Register(pkgPath+".signatureError", verror2.NoRetry, "{1} {2} signature error {_}")
41 badCaveatType = verror2.Register(pkgPath+".badCaveatType", verror2.NoRetry, "{1} {2} bad caveat type {_}")
Ankur5b802242014-10-29 11:32:21 -070042 unknownBlessings = verror2.Register(pkgPath+".unknownBlessings", verror2.NoRetry, "{1} {2} unknown public id {_}")
Ankure7889242014-10-20 18:37:29 -070043 invalidBlessingsHandle = verror2.Register(pkgPath+".invalidBlessingsHandle", verror2.NoRetry, "{1} {2} invalid blessings handle {_}")
Ankure7889242014-10-20 18:37:29 -070044)
Mike Burrowsb6689c22014-10-08 11:14:15 -070045
Jiri Simsa78b646f2014-10-08 10:23:05 -070046// TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
47// to pass it in from javascript. For now all RPCs have the same
48// retryTimeout, set by command line flag.
49var retryTimeout *int
50
51func init() {
52 // TODO(bjornick,nlacasse): Remove the retryTimeout flag once we able
53 // to pass it in from javascript. For now all RPCs have the same
54 // retryTimeout, set by command line flag.
55 retryTimeout = flag.Int("retry-timeout", 0, "Duration in seconds to retry starting an RPC call. 0 means never retry.")
56}
57
58// Temporary holder of RPC so that we can store the unprocessed args.
59type veyronTempRPC struct {
60 Name string
61 Method string
62 InArgs []json.RawMessage
63 NumOutArgs int32
64 IsStreaming bool
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070065 Timeout int64
Jiri Simsa78b646f2014-10-08 10:23:05 -070066}
67
68type veyronRPC struct {
69 Name string
70 Method string
71 InArgs []interface{}
72 NumOutArgs int32
73 IsStreaming bool
74}
75
Jiri Simsa78b646f2014-10-08 10:23:05 -070076type serveRequest struct {
77 Name string
78 ServerId uint64
79}
80
Ali Ghassemi1008bbe2014-11-07 16:36:08 -080081type addRemoveNameRequest struct {
82 Name string
83 ServerId uint64
84}
85
Jiri Simsa78b646f2014-10-08 10:23:05 -070086type jsonCaveatValidator struct {
87 Type string `json:"_type"`
88 Data json.RawMessage
89}
90
91type blessingRequest struct {
92 Handle int64
93 Caveats []jsonCaveatValidator
94 DurationMs int64
Ankurc56b3472014-10-29 11:16:19 -070095 Extension string
Jiri Simsa78b646f2014-10-08 10:23:05 -070096}
97
Matt Rosencrantz4aabe572014-10-22 09:25:50 -070098type outstandingRequest struct {
99 stream *outstandingStream
100 cancel context.CancelFunc
101}
102
Jiri Simsa78b646f2014-10-08 10:23:05 -0700103// Controller represents all the state of a Veyron Web App. This is the struct
104// that is in charge performing all the veyron options.
105type Controller struct {
106 // Protects everything.
107 // TODO(bjornick): We need to split this up.
108 sync.Mutex
109
110 logger vlog.Logger
111
112 // The runtime to use to create new clients.
113 rt veyron2.Runtime
114
115 // The ipc.ListenSpec to use with server.Listen
116 listenSpec *ipc.ListenSpec
117
118 // Used to generate unique ids for requests initiated by the proxy.
119 // These ids will be even so they don't collide with the ids generated
120 // by the client.
121 lastGeneratedId int64
122
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700123 // Used to keep track of data (streams and cancellation functions) for
124 // outstanding requests.
125 outstandingRequests map[int64]*outstandingRequest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700126
127 // Maps flowids to the server that owns them.
128 flowMap map[int64]*server.Server
129
130 // A manager that Handles fetching and caching signature of remote services
131 signatureManager lib.SignatureManager
132
133 // We maintain multiple Veyron server per websocket pipe for serving JavaScript
134 // services.
135 servers map[uint64]*server.Server
136
137 // Creates a client writer for a given flow. This is a member so that tests can override
138 // the default implementation.
139 writerCreator func(id int64) lib.ClientWriter
140
Ankur5b802242014-10-29 11:32:21 -0700141 // There is only one client per Controller since there is a single principal per app.
Jiri Simsa78b646f2014-10-08 10:23:05 -0700142 client ipc.Client
143
144 veyronProxyEP string
145
Ankure7889242014-10-20 18:37:29 -0700146 // Store for all the Blessings that javascript has a handle to.
147 blessingsStore *principal.JSBlessingsHandles
Jiri Simsa78b646f2014-10-08 10:23:05 -0700148}
149
150// NewController creates a new Controller. writerCreator will be used to create a new flow for rpcs to
151// javascript server. veyronProxyEP is an endpoint for the veyron proxy to serve through. It can't be empty.
Cosmos Nicolaou42f75b02014-10-30 08:22:24 -0700152// opts are any options that should be passed to the rt.New().
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800153func NewController(writerCreator func(id int64) lib.ClientWriter, listenSpec *ipc.ListenSpec, namespaceRoots []string, opts ...veyron2.ROpt) (*Controller, error) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700154 r, err := rt.New(opts...)
155 if err != nil {
156 return nil, err
157 }
Benjamin Prosnitz3c738502014-11-04 14:51:38 -0800158 if namespaceRoots != nil {
159 r.Namespace().SetRoots(namespaceRoots...)
160 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700161 client, err := r.NewClient()
162 if err != nil {
163 return nil, err
164 }
165
166 controller := &Controller{
Ankure7889242014-10-20 18:37:29 -0700167 rt: r,
168 logger: r.Logger(),
169 client: client,
170 writerCreator: writerCreator,
171 listenSpec: listenSpec,
Ankure7889242014-10-20 18:37:29 -0700172 blessingsStore: principal.NewJSBlessingsHandles(),
Ankure7889242014-10-20 18:37:29 -0700173 }
174
Jiri Simsa78b646f2014-10-08 10:23:05 -0700175 controller.setup()
176 return controller, nil
177}
178
179// finishCall waits for the call to finish and write out the response to w.
Mike Burrowsb6689c22014-10-08 11:14:15 -0700180func (c *Controller) finishCall(ctx context.T, w lib.ClientWriter, clientCall ipc.Call, msg *veyronRPC) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700181 if msg.IsStreaming {
182 for {
183 var item interface{}
184 if err := clientCall.Recv(&item); err != nil {
185 if err == io.EOF {
186 break
187 }
188 w.Error(err) // Send streaming error as is
189 return
190 }
191 if err := w.Send(lib.ResponseStream, item); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700192 w.Error(verror2.Make(marshallingError, ctx, item))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700193 }
194 }
195
196 if err := w.Send(lib.ResponseStreamClose, nil); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700197 w.Error(verror2.Make(marshallingError, ctx, "ResponseStreamClose"))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700198 }
199 }
200
201 results := make([]interface{}, msg.NumOutArgs)
202 // This array will have pointers to the values in result.
203 resultptrs := make([]interface{}, msg.NumOutArgs)
204 for ax := range results {
205 resultptrs[ax] = &results[ax]
206 }
207 if err := clientCall.Finish(resultptrs...); err != nil {
208 // return the call system error as is
209 w.Error(err)
210 return
211 }
212 // for now we assume last out argument is always error
213 if len(results) < 1 {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700214 w.Error(verror2.Make(noResults, ctx))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700215 return
216 }
217
218 if err, ok := results[len(results)-1].(error); ok {
219 // return the call Application error as is
220 w.Error(err)
221 return
222 }
223
224 if err := w.Send(lib.ResponseFinal, results[0:len(results)-1]); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700225 w.Error(verror2.Convert(marshallingError, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700226 }
227}
228
229func (c *Controller) startCall(ctx context.T, w lib.ClientWriter, msg *veyronRPC) (ipc.Call, error) {
230 if c.client == nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700231 return nil, verror2.Make(verror2.BadArg, ctx, "app.Controller.client")
Jiri Simsa78b646f2014-10-08 10:23:05 -0700232 }
233 methodName := lib.UppercaseFirstCharacter(msg.Method)
Asim Shankarf3c61a32014-10-15 17:34:11 -0700234 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700235 clientCall, err := c.client.StartCall(ctx, msg.Name, methodName, msg.InArgs, retryTimeoutOpt)
236 if err != nil {
237 return nil, fmt.Errorf("error starting call (name: %v, method: %v, args: %v): %v", msg.Name, methodName, msg.InArgs, err)
238 }
239
240 return clientCall, nil
241}
242
243// Implements the serverHelper interface
244
245// CreateNewFlow creats a new server flow that will be used to write out
246// streaming messages to Javascript.
247func (c *Controller) CreateNewFlow(s *server.Server, stream ipc.Stream) *server.Flow {
248 c.Lock()
249 defer c.Unlock()
250 id := c.lastGeneratedId
251 c.lastGeneratedId += 2
252 c.flowMap[id] = s
253 os := newStream()
254 os.init(stream, vom_wiretype.Type{ID: 1})
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700255 c.outstandingRequests[id] = &outstandingRequest{
256 stream: os,
257 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700258 return &server.Flow{ID: id, Writer: c.writerCreator(id)}
259}
260
261// CleanupFlow removes the bookkeping for a previously created flow.
262func (c *Controller) CleanupFlow(id int64) {
263 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700264 request := c.outstandingRequests[id]
265 delete(c.outstandingRequests, id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700266 delete(c.flowMap, id)
267 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700268 if request != nil && request.stream != nil {
269 request.stream.end()
270 request.stream.waitUntilDone()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700271 }
272}
273
274// GetLogger returns a Veyron logger to use.
275func (c *Controller) GetLogger() vlog.Logger {
276 return c.logger
277}
278
279// RT returns the runtime of the app.
280func (c *Controller) RT() veyron2.Runtime {
281 return c.rt
282}
283
Ankure7889242014-10-20 18:37:29 -0700284// AddBlessings adds the Blessings to the local blessings store and returns
Jiri Simsa78b646f2014-10-08 10:23:05 -0700285// the handle to it. This function exists because JS only has
Ankure7889242014-10-20 18:37:29 -0700286// a handle to the blessings to avoid shipping the certificate forest
Jiri Simsa78b646f2014-10-08 10:23:05 -0700287// to JS and back.
Ankure7889242014-10-20 18:37:29 -0700288func (c *Controller) AddBlessings(blessings security.Blessings) int64 {
289 return c.blessingsStore.Add(blessings)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700290}
291
292// Cleanup cleans up any outstanding rpcs.
293func (c *Controller) Cleanup() {
294 c.logger.VI(0).Info("Cleaning up websocket")
295 c.Lock()
296 defer c.Unlock()
297
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700298 for _, request := range c.outstandingRequests {
299 if request.cancel != nil {
300 request.cancel()
301 }
302 if request.stream != nil {
303 request.stream.end()
304 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700305 }
306
307 for _, server := range c.servers {
308 server.Stop()
309 }
Benjamin Prosnitz8a51fe82014-10-16 13:05:14 -0700310
311 c.RT().Cleanup()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700312}
313
314func (c *Controller) setup() {
315 c.signatureManager = lib.NewSignatureManager()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700316 c.outstandingRequests = make(map[int64]*outstandingRequest)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700317 c.flowMap = make(map[int64]*server.Server)
318 c.servers = make(map[uint64]*server.Server)
319}
320
321// SendOnStream writes data on id's stream. The actual network write will be
322// done asynchronously. If there is an error, it will be sent to w.
323func (c *Controller) SendOnStream(id int64, data string, w lib.ClientWriter) {
324 c.Lock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700325 request := c.outstandingRequests[id]
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700326 if request == nil || request.stream == nil {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700327 vlog.Errorf("unknown stream: %d", id)
328 return
329 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700330 stream := request.stream
331 c.Unlock()
332 stream.send(data, w)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700333}
334
335// SendVeyronRequest makes a veyron request for the given flowId. If signal is non-nil, it will receive
336// the call object after it has been constructed.
337func (c *Controller) sendVeyronRequest(ctx context.T, id int64, tempMsg *veyronTempRPC, w lib.ClientWriter, stream *outstandingStream) {
338 // Fetch and adapt signature from the SignatureManager
Asim Shankarf3c61a32014-10-15 17:34:11 -0700339 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700340 sig, err := c.signatureManager.Signature(ctx, tempMsg.Name, c.client, retryTimeoutOpt)
341 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700342 w.Error(verror2.Make(signatureError, ctx, tempMsg.Name, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700343 return
344 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700345 methName := lib.UppercaseFirstCharacter(tempMsg.Method)
346 methSig, ok := sig.Methods[methName]
347 if !ok {
348 w.Error(fmt.Errorf("method not found in signature: %v (full sig: %v)", methName, sig))
349 return
350 }
351
352 var msg veyronRPC
353 if len(methSig.InArgs) != len(tempMsg.InArgs) {
354 w.Error(fmt.Errorf("invalid number of arguments, expected: %v, got:%v", methSig, tempMsg))
355 return
356 }
357 msg.InArgs = make([]interface{}, len(tempMsg.InArgs))
358 td := wiretype_build.TypeDefs(sig.TypeDefs)
359
360 for i := 0; i < len(tempMsg.InArgs); i++ {
361 argTypeId := methSig.InArgs[i].Type
362 argType := vom_wiretype.Type{
363 ID: argTypeId,
364 Defs: &td,
365 }
366
367 val, err := vom.JSONToObject(string(tempMsg.InArgs[i]), argType)
368 if err != nil {
369 w.Error(fmt.Errorf("error while converting json to object for arg %d (%s): %v", i, methSig.InArgs[i].Name, err))
370 return
371 }
372 msg.InArgs[i] = val
373 }
374
375 msg.Name = tempMsg.Name
376 msg.Method = tempMsg.Method
377 msg.NumOutArgs = tempMsg.NumOutArgs
378 msg.IsStreaming = tempMsg.IsStreaming
379
380 inStreamType := vom_wiretype.Type{
381 ID: methSig.InStream,
382 Defs: &td,
383 }
384
385 // We have to make the start call synchronous so we can make sure that we populate
386 // the call map before we can Handle a recieve call.
387 call, err := c.startCall(ctx, w, &msg)
388 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700389 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700390 return
391 }
392
393 if stream != nil {
394 stream.init(call, inStreamType)
395 }
396
Mike Burrowsb6689c22014-10-08 11:14:15 -0700397 c.finishCall(ctx, w, call, &msg)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700398 c.Lock()
399 if request, ok := c.outstandingRequests[id]; ok {
400 delete(c.outstandingRequests, id)
401 if request.cancel != nil {
402 request.cancel()
403 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700404 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700405 c.Unlock()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700406}
407
408// HandleVeyronRequest starts a veyron rpc and returns before the rpc has been completed.
409func (c *Controller) HandleVeyronRequest(ctx context.T, id int64, data string, w lib.ClientWriter) {
410 veyronTempMsg, err := c.parseVeyronRequest(ctx, bytes.NewBufferString(data))
411 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700412 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700413 return
414 }
415
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700416 var cctx context.T
417 var cancel context.CancelFunc
418
419 // TODO(mattr): To be consistent with go, we should not ignore 0 timeouts.
420 // However as a rollout strategy we must, otherwise there is a circular
421 // dependency between the WSPR change and the JS change that will follow.
422 if veyronTempMsg.Timeout == lib.JSIPCNoTimeout || veyronTempMsg.Timeout == 0 {
423 cctx, cancel = ctx.WithCancel()
424 } else {
425 cctx, cancel = ctx.WithTimeout(lib.JSToGoDuration(veyronTempMsg.Timeout))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700426 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700427
428 request := &outstandingRequest{
429 cancel: cancel,
430 }
431 if veyronTempMsg.IsStreaming {
432 // If this rpc is streaming, we would expect that the client would try to send
433 // on this stream. Since the initial handshake is done asynchronously, we have
434 // to put the outstanding stream in the map before we make the async call so that
435 // the future send know which queue to write to, even if the client call isn't
436 // actually ready yet.
437 request.stream = newStream()
438 }
439 c.Lock()
440 c.outstandingRequests[id] = request
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700441 go c.sendVeyronRequest(cctx, id, veyronTempMsg, w, request.stream)
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700442 c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700443}
444
445// HandleVeyronCancellation cancels the request corresponding to the
446// given id if it is still outstanding.
447func (c *Controller) HandleVeyronCancellation(id int64) {
448 c.Lock()
449 defer c.Unlock()
450 if request, ok := c.outstandingRequests[id]; ok && request.cancel != nil {
451 request.cancel()
452 }
Jiri Simsa78b646f2014-10-08 10:23:05 -0700453}
454
455// CloseStream closes the stream for a given id.
456func (c *Controller) CloseStream(id int64) {
457 c.Lock()
458 defer c.Unlock()
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700459 if request, ok := c.outstandingRequests[id]; ok && request.stream != nil {
460 request.stream.end()
Jiri Simsa78b646f2014-10-08 10:23:05 -0700461 return
462 }
Matt Rosencrantz4aabe572014-10-22 09:25:50 -0700463 c.logger.Errorf("close called on non-existent call: %v", id)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700464}
465
466func (c *Controller) maybeCreateServer(serverId uint64) (*server.Server, error) {
467 c.Lock()
468 defer c.Unlock()
469 if server, ok := c.servers[serverId]; ok {
470 return server, nil
471 }
472 server, err := server.NewServer(serverId, c.listenSpec, c)
473 if err != nil {
474 return nil, err
475 }
476 c.servers[serverId] = server
477 return server, nil
478}
479
480func (c *Controller) removeServer(serverId uint64) {
481 c.Lock()
482 server := c.servers[serverId]
483 if server == nil {
484 c.Unlock()
485 return
486 }
487 delete(c.servers, serverId)
488 c.Unlock()
489
490 server.Stop()
491}
492
493func (c *Controller) serve(serveRequest serveRequest, w lib.ClientWriter) {
494 // Create a server for the websocket pipe, if it does not exist already
495 server, err := c.maybeCreateServer(serveRequest.ServerId)
496 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700497 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700498 }
499
500 c.logger.VI(2).Infof("serving under name: %q", serveRequest.Name)
501
502 endpoint, err := server.Serve(serveRequest.Name)
503 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700504 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700505 return
506 }
507 // Send the endpoint back
508 if err := w.Send(lib.ResponseFinal, endpoint); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700509 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700510 return
511 }
512}
513
514// HandleServeRequest takes a request to serve a server, creates
515// a server, registers the provided services and sends the endpoint back.
516func (c *Controller) HandleServeRequest(data string, w lib.ClientWriter) {
517 // Decode the serve request which includes IDL, registered services and name
518 var serveRequest serveRequest
519 if err := json.Unmarshal([]byte(data), &serveRequest); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700520 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700521 return
522 }
523 c.serve(serveRequest, w)
524}
525
526// HandleLookupResponse handles the result of a Dispatcher.Lookup call that was
527// run by the Javascript server.
528func (c *Controller) HandleLookupResponse(id int64, data string) {
529 c.Lock()
530 server := c.flowMap[id]
531 c.Unlock()
532 if server == nil {
533 c.logger.Errorf("unexpected result from JavaScript. No channel "+
534 "for MessageId: %d exists. Ignoring the results.", id)
535 //Ignore unknown responses that don't belong to any channel
536 return
537 }
538 server.HandleLookupResponse(id, data)
539}
540
541// HandleAuthResponse handles the result of a Authorizer.Authorize call that was
542// run by the Javascript server.
543func (c *Controller) HandleAuthResponse(id int64, data string) {
544 c.Lock()
545 server := c.flowMap[id]
546 c.Unlock()
547 if server == nil {
548 c.logger.Errorf("unexpected result from JavaScript. No channel "+
549 "for MessageId: %d exists. Ignoring the results.", id)
550 //Ignore unknown responses that don't belong to any channel
551 return
552 }
553 server.HandleAuthResponse(id, data)
554}
555
556// HandleStopRequest takes a request to stop a server.
557func (c *Controller) HandleStopRequest(data string, w lib.ClientWriter) {
558 var serverId uint64
559 if err := json.Unmarshal([]byte(data), &serverId); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700560 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700561 return
562 }
563
564 c.removeServer(serverId)
565
566 // Send true to indicate stop has finished
567 if err := w.Send(lib.ResponseFinal, true); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700568 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700569 return
570 }
571}
572
Ali Ghassemi1008bbe2014-11-07 16:36:08 -0800573// HandleAddNameRequest takes a request to add a new name to a server
574func (c *Controller) HandleAddNameRequest(data string, w lib.ClientWriter) {
575 var request addRemoveNameRequest
576 if err := json.Unmarshal([]byte(data), &request); err != nil {
577 w.Error(verror2.Convert(verror2.Internal, nil, err))
578 return
579 }
580
581 // Create a server for the websocket pipe, if it does not exist already
582 server, err := c.maybeCreateServer(request.ServerId)
583 if err != nil {
584 w.Error(verror2.Convert(verror2.Internal, nil, err))
585 return
586 }
587
588 // Add name
589 if err := server.AddName(request.Name); err != nil {
590 w.Error(verror2.Convert(verror2.Internal, nil, err))
591 return
592 }
593
594 // Send true to indicate request has finished without error
595 if err := w.Send(lib.ResponseFinal, true); err != nil {
596 w.Error(verror2.Convert(verror2.Internal, nil, err))
597 return
598 }
599}
600
601// HandleRemoveNameRequest takes a request to remove a name from a server
602func (c *Controller) HandleRemoveNameRequest(data string, w lib.ClientWriter) {
603 var request addRemoveNameRequest
604 if err := json.Unmarshal([]byte(data), &request); err != nil {
605 w.Error(verror2.Convert(verror2.Internal, nil, err))
606 return
607 }
608
609 // Create a server for the websocket pipe, if it does not exist already
610 server, err := c.maybeCreateServer(request.ServerId)
611 if err != nil {
612 w.Error(verror2.Convert(verror2.Internal, nil, err))
613 return
614 }
615
616 // Remove name
617 if err := server.RemoveName(request.Name); err != nil {
618 w.Error(verror2.Convert(verror2.Internal, nil, err))
619 return
620 }
621
622 // Remove name from signature cache as well
623 c.signatureManager.FlushCacheEntry(request.Name)
624
625 // Send true to indicate request has finished without error
626 if err := w.Send(lib.ResponseFinal, true); err != nil {
627 w.Error(verror2.Convert(verror2.Internal, nil, err))
628 return
629 }
630}
631
Jiri Simsa78b646f2014-10-08 10:23:05 -0700632// HandleServerResponse handles the completion of outstanding calls to JavaScript services
633// by filling the corresponding channel with the result from JavaScript.
634func (c *Controller) HandleServerResponse(id int64, data string) {
635 c.Lock()
636 server := c.flowMap[id]
637 c.Unlock()
638 if server == nil {
639 c.logger.Errorf("unexpected result from JavaScript. No channel "+
640 "for MessageId: %d exists. Ignoring the results.", id)
641 //Ignore unknown responses that don't belong to any channel
642 return
643 }
644 server.HandleServerResponse(id, data)
645}
646
647// parseVeyronRequest parses a json rpc request into a veyronRPC object.
648func (c *Controller) parseVeyronRequest(ctx context.T, r io.Reader) (*veyronTempRPC, error) {
649 var tempMsg veyronTempRPC
650 decoder := json.NewDecoder(r)
651 if err := decoder.Decode(&tempMsg); err != nil {
652 return nil, fmt.Errorf("can't unmarshall JSONMessage: %v", err)
653 }
Matt Rosencrantzd608b372014-10-22 13:06:52 -0700654 c.logger.VI(2).Infof("VeyronRPC: %s.%s(..., streaming=%v)", tempMsg.Name, tempMsg.Method, tempMsg.IsStreaming)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700655 return &tempMsg, nil
656}
657
658type signatureRequest struct {
659 Name string
660}
661
662func (c *Controller) getSignature(ctx context.T, name string) (signature.JSONServiceSignature, error) {
663 // Fetch and adapt signature from the SignatureManager
Asim Shankarf3c61a32014-10-15 17:34:11 -0700664 retryTimeoutOpt := options.RetryTimeout(time.Duration(*retryTimeout) * time.Second)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700665 sig, err := c.signatureManager.Signature(ctx, name, c.client, retryTimeoutOpt)
666 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700667 return nil, verror2.Convert(verror2.Internal, ctx, err)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700668 }
669
670 return signature.NewJSONServiceSignature(*sig), nil
671}
672
673// HandleSignatureRequest uses signature manager to get and cache signature of a remote server
674func (c *Controller) HandleSignatureRequest(ctx context.T, data string, w lib.ClientWriter) {
675 // Decode the request
676 var request signatureRequest
677 if err := json.Unmarshal([]byte(data), &request); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700678 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700679 return
680 }
681
682 c.logger.VI(2).Infof("requesting Signature for %q", request.Name)
683 jsSig, err := c.getSignature(ctx, request.Name)
684 if err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700685 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700686 return
687 }
688
689 // Send the signature back
690 if err := w.Send(lib.ResponseFinal, jsSig); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700691 w.Error(verror2.Convert(verror2.Internal, ctx, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700692 return
693 }
694}
695
Ankure7889242014-10-20 18:37:29 -0700696// HandleUnlinkJSBlessings removes the specified blessings from the JS blessings
697// store. 'data' should be a JSON encoded number (representing the blessings handle).
698func (c *Controller) HandleUnlinkJSBlessings(data string, w lib.ClientWriter) {
Jiri Simsa78b646f2014-10-08 10:23:05 -0700699 var handle int64
700 if err := json.Unmarshal([]byte(data), &handle); err != nil {
Mike Burrowsb6689c22014-10-08 11:14:15 -0700701 w.Error(verror2.Convert(verror2.Internal, nil, err))
Jiri Simsa78b646f2014-10-08 10:23:05 -0700702 return
703 }
Ankure7889242014-10-20 18:37:29 -0700704 c.blessingsStore.Remove(handle)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700705}
706
707// Convert the json wire format of a caveat into the right go object
708func decodeCaveat(c jsonCaveatValidator) (security.Caveat, error) {
709 var failed security.Caveat
710 switch c.Type {
711 case "MethodCaveat":
712 var methods []string
713 if err := json.Unmarshal(c.Data, &methods); err != nil {
714 return failed, err
715 }
716 if len(methods) == 0 {
717 return failed, fmt.Errorf("must provide at least one method")
718 }
719 return security.MethodCaveat(methods[0], methods[1:]...)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700720 default:
Mike Burrowsb6689c22014-10-08 11:14:15 -0700721 return failed, verror2.Make(badCaveatType, nil, c.Type)
Jiri Simsa78b646f2014-10-08 10:23:05 -0700722 }
723}
724
Ankure7889242014-10-20 18:37:29 -0700725func (c *Controller) getBlessingsHandle(handle int64) (*principal.BlessingsHandle, error) {
726 id := c.blessingsStore.Get(handle)
727 if id == nil {
728 return nil, verror2.Make(unknownBlessings, nil)
729 }
730 return principal.ConvertBlessingsToHandle(id, handle), nil
731}
732
733func (c *Controller) blessPublicKey(request blessingRequest) (*principal.BlessingsHandle, error) {
734 var blessee security.Blessings
Ankur697132e2014-10-22 12:12:39 -0700735 if blessee = c.blessingsStore.Get(request.Handle); blessee == nil {
Ankur5b802242014-10-29 11:32:21 -0700736 return nil, verror2.Make(invalidBlessingsHandle, nil)
Ankure7889242014-10-20 18:37:29 -0700737 }
738
739 expiryCav, err := security.ExpiryCaveat(time.Now().Add(time.Duration(request.DurationMs) * time.Millisecond))
740 if err != nil {
741 return nil, err
742 }
743 caveats := []security.Caveat{expiryCav}
744 for _, c := range request.Caveats {
745 cav, err := decodeCaveat(c)
746 if err != nil {
747 return nil, verror2.Convert(verror2.BadArg, nil, err)
748 }
749 caveats = append(caveats, cav)
750 }
751
752 // TODO(ataly, ashankar, bjornick): Currently the Bless operation is carried
753 // out using the Default blessing in this principal's blessings store. We
754 // should change this so that the JS blessing request can also specify the
755 // blessing to be used for the Bless operation.
Ankurc56b3472014-10-29 11:16:19 -0700756 blessings, err := c.rt.Principal().Bless(blessee.PublicKey(), c.rt.Principal().BlessingStore().Default(), request.Extension, caveats[0], caveats[1:]...)
Ankure7889242014-10-20 18:37:29 -0700757 if err != nil {
758 return nil, err
759 }
760
761 return principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings)), nil
762}
763
764// HandleBlessPublicKey handles a blessing request from JS.
765func (c *Controller) HandleBlessPublicKey(data string, w lib.ClientWriter) {
766 var request blessingRequest
767 if err := json.Unmarshal([]byte(data), &request); err != nil {
768 w.Error(verror2.Convert(verror2.Internal, nil, err))
769 return
770 }
771
772 handle, err := c.blessPublicKey(request)
773 if err != nil {
774 w.Error(verror2.Convert(verror2.Internal, nil, err))
775 return
776 }
777
778 // Send the id back.
779 if err := w.Send(lib.ResponseFinal, handle); err != nil {
780 w.Error(verror2.Convert(verror2.Internal, nil, err))
781 return
782 }
783}
784
785func (c *Controller) HandleCreateBlessings(data string, w lib.ClientWriter) {
786 var extension string
787 if err := json.Unmarshal([]byte(data), &extension); err != nil {
788 w.Error(verror2.Convert(verror2.Internal, nil, err))
789 return
790 }
791 p, err := vsecurity.NewPrincipal()
792 if err != nil {
793 w.Error(verror2.Convert(verror2.Internal, nil, err))
794 return
795 }
796
797 blessings, err := p.BlessSelf(extension)
798 if err != nil {
799 w.Error(verror2.Convert(verror2.Internal, nil, err))
800 return
801 }
802 handle := principal.ConvertBlessingsToHandle(blessings, c.blessingsStore.Add(blessings))
803 if err := w.Send(lib.ResponseFinal, handle); err != nil {
804 w.Error(verror2.Convert(verror2.Internal, nil, err))
805 return
806 }
807}
808
Ali Ghassemiaa0ea242014-10-20 12:55:39 -0700809// HandleNamespaceRequest uses the namespace client to respond to namespace specific requests such as glob
810func (c *Controller) HandleNamespaceRequest(ctx context.T, data string, w lib.ClientWriter) {
811 namespace.HandleRequest(ctx, c.rt, data, w)
812}