// Route is used to route a given request func (r *Router) Route(req *logical.Request) (*logical.Response, error) { // Find the mount point r.l.RLock() mount, raw, ok := r.root.LongestPrefix(req.Path) if !ok { // Re-check for a backend by appending a slash. This lets "foo" mean // "foo/" at the root level which is almost always what we want. req.Path += "/" mount, raw, ok = r.root.LongestPrefix(req.Path) } r.l.RUnlock() if !ok { return nil, fmt.Errorf("no handler for route '%s'", req.Path) } defer metrics.MeasureSince([]string{"route", string(req.Operation), strings.Replace(mount, "/", "-", -1)}, time.Now()) me := raw.(*mountEntry) // If the path is tainted, we reject any operation except for // Rollback and Revoke if me.tainted { switch req.Operation { case logical.RevokeOperation, logical.RollbackOperation: default: return nil, fmt.Errorf("no handler for route '%s'", req.Path) } } // Determine if this path is an unauthenticated path before we modify it loginPath := r.LoginPath(req.Path) // Adjust the path to exclude the routing prefix original := req.Path req.Path = strings.TrimPrefix(req.Path, mount) if req.Path == "/" { req.Path = "" } // Attach the storage view for the request req.Storage = me.view // Hash the request token unless this is the token backend clientToken := req.ClientToken if !strings.HasPrefix(original, "auth/token/") { req.ClientToken = me.SaltID(req.ClientToken) } // If the request is not a login path, then clear the connection originalConn := req.Connection if !loginPath { req.Connection = nil } // Reset the request before returning defer func() { req.Path = original req.Connection = originalConn req.Storage = nil req.ClientToken = clientToken }() // Invoke the backend return me.backend.HandleRequest(req) }
func (r *Router) routeCommon(req *logical.Request, existenceCheck bool) (*logical.Response, bool, bool, error) { // Find the mount point r.l.RLock() mount, raw, ok := r.root.LongestPrefix(req.Path) if !ok { // Re-check for a backend by appending a slash. This lets "foo" mean // "foo/" at the root level which is almost always what we want. req.Path += "/" mount, raw, ok = r.root.LongestPrefix(req.Path) } r.l.RUnlock() if !ok { return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath } defer metrics.MeasureSince([]string{"route", string(req.Operation), strings.Replace(mount, "/", "-", -1)}, time.Now()) re := raw.(*routeEntry) // If the path is tainted, we reject any operation except for // Rollback and Revoke if re.tainted { switch req.Operation { case logical.RevokeOperation, logical.RollbackOperation: default: return logical.ErrorResponse(fmt.Sprintf("no handler for route '%s'", req.Path)), false, false, logical.ErrUnsupportedPath } } // Adjust the path to exclude the routing prefix originalPath := req.Path req.Path = strings.TrimPrefix(req.Path, mount) req.MountPoint = mount if req.Path == "/" { req.Path = "" } // Attach the storage view for the request req.Storage = re.storageView // Hash the request token unless this is the token backend clientToken := req.ClientToken switch { case strings.HasPrefix(originalPath, "auth/token/"): case strings.HasPrefix(originalPath, "sys/"): case strings.HasPrefix(originalPath, "cubbyhole/"): // In order for the token store to revoke later, we need to have the same // salted ID, so we double-salt what's going to the cubbyhole backend req.ClientToken = re.SaltID(r.tokenStoreSalt.SaltID(req.ClientToken)) default: req.ClientToken = re.SaltID(req.ClientToken) } // Cache the pointer to the original connection object originalConn := req.Connection // Cache the identifier of the request originalReqID := req.ID // Cache the wrap TTL of the request originalWrapTTL := req.WrapTTL // Reset the request before returning defer func() { req.Path = originalPath req.MountPoint = "" req.Connection = originalConn req.ID = originalReqID req.Storage = nil req.ClientToken = clientToken // Only the rewrap endpoint is allowed to declare a wrap TTL on a // request that did not come from the client if req.Path != "sys/wrapping/rewrap" { req.WrapTTL = originalWrapTTL } }() // Invoke the backend if existenceCheck { ok, exists, err := re.backend.HandleExistenceCheck(req) return nil, ok, exists, err } else { resp, err := re.backend.HandleRequest(req) return resp, false, false, err } }