public object Fetch(
            [DekiExtParam("document id")] string id
            )
        {
            // fetch response from cache
            CacheEntry result;

            lock (_cacheLookup) {
                _cacheLookup.TryGetValue(id, out result);
            }

            // check if we have a cached entry
            XDoc document = null;

            if (result != null)
            {
                _log.DebugFormat("cache hit for '{0}'", result.Id);
                result.ResetMemoryExpiration();
                if (result.Cache != null)
                {
                    _log.DebugFormat("cache data in memory '{0}'", result.Id);
                    document = XDocFactory.From(result.Cache, MimeType.XML);
                }
                else
                {
                    // we have the result on disk, so let's fetch it
                    DreamMessage msg = Storage.At(CACHE_DATA, result.Guid + ".bin").GetAsync().Wait();
                    if (msg.IsSuccessful)
                    {
                        _log.DebugFormat("cache data pulled from disk");
                        result.Cache = Encoding.UTF8.GetString(msg.AsBytes());
                        document     = XDocFactory.From(result.Cache, MimeType.XML);
                    }
                    else
                    {
                        _log.DebugFormat("unable to fetch cache data from disk: {0}", msg.Status);
                    }
                }
            }

            // check if we have a document to convert
            if (document != null)
            {
                try {
                    DekiScriptList list = (DekiScriptList)DekiScriptLiteral.FromXml(document);
                    return(list[0]);
                } catch {
                    // the cached entry is corrupted, remove it
                    Clear(id);
                }
            }
            return(null);
        }
        public override DekiScriptLiteral InvokeMap(DekiScriptRuntime runtime, DekiScriptMap args)
        {
            // prepare uri for invocation
            Plug plug = Plug.New(_endpoint);

            plug = runtime.PreparePlug(plug);

            // make web-request
            DreamMessage response = plug.Post(args.ToXml(), new Tasking.Result <DreamMessage>()).Wait();

            if (!response.IsSuccessful)
            {
                if (response.HasDocument)
                {
                    var error   = response.ToDocument();
                    var message = error["message"];
                    if (error.HasName("exception") && !message.IsEmpty)
                    {
                        throw new DekiScriptRemoteException(Location.None, message.Contents);
                    }
                }
                throw new DreamResponseException(response);
            }

            // convert response to literal
            DekiScriptLiteral list;

            try {
                list = DekiScriptLiteral.FromXml(response.ToDocument());
            } catch (ArgumentException) {
                throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", response.ToDocument().Name));
            }
            if (list.ScriptType != DekiScriptType.LIST)
            {
                throw new DekiScriptBadTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST });
            }
            return(((DekiScriptList)list)[0]);
        }
        public override DekiScriptLiteral InvokeMap(DekiScriptRuntime runtime, DekiScriptMap args)
        {
            // prepare uri for invocation
            Plug plug = Plug.New(_endpoint);

            plug = runtime.PreparePlug(plug);

            // invoke function
            DreamMessage response = plug.Get();

            // convert response to literal
            DekiScriptLiteral list;

            try {
                list = DekiScriptLiteral.FromXml(response.ToDocument());
            } catch (ArgumentException) {
                throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", response.ToDocument().Name));
            }
            if (list.ScriptType != DekiScriptType.LIST)
            {
                throw new DekiScriptBadReturnTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST });
            }
            return(((DekiScriptList)list)[0]);
        }
示例#4
0
        public Yield PostExtensionFunction(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            var  name = context.GetParam("function");
            XUri uri  = Self.At(name);

            // check if deki server is permitted to invoke this function
            if (this is IDreamServiceLicense)
            {
                string deki;
                if (context.ServiceLicense.TryGetValue("deki", out deki) && !deki.EqualsInvariant(request.Headers[DEKI_HEADER] ?? string.Empty))
                {
                    throw new DreamAbortException(DreamMessage.Forbidden("deki server is not licensed for this service"));
                }
            }

            // check if any functions were found
            DekiScriptInvocationTargetDescriptor descriptor;

            if (!_functions.TryGetValue(uri, out descriptor))
            {
                response.Return(DreamMessage.NotFound(string.Format("function {0} not found", context.GetParam("function"))));
                yield break;
            }

            // check if invoker has access to function
            if ((descriptor.Access != DreamAccess.Public) && (descriptor.Access > DetermineAccess(context, request)))
            {
                response.Return(DreamMessage.Forbidden("insufficient access privileges"));
                yield break;
            }

            // check if request has a requested culture
            context.Culture = HttpUtil.GetCultureInfoFromHeader(request.Headers.AcceptLanguage, context.Culture);

            // check for implicit arguments
            context.SetState(GetImplicitEnvironment(request, _publicDigitalSignature));

            // create custom environment
            DekiScriptEnv env = CreateEnvironment();

            // create custom target for custom environment
            var target = descriptor.Target as DekiScriptExpressionInvocationTarget;

            if (target != null)
            {
                // TODO (steveb): re-initializing the invocation target works for the first call, but not if the function calls another function in the same extension!

                target = new DekiScriptExpressionInvocationTarget(target.Access, target.Parameters, target.Expression, env);
            }

            // invoke target
            DekiScriptLiteral eval;

            if (target != null)
            {
                eval = target.Invoke(ScriptRuntime, DekiScriptLiteral.FromXml(request.ToDocument()));
            }
            else
            {
                eval = descriptor.Target.Invoke(ScriptRuntime, DekiScriptLiteral.FromXml(request.ToDocument()));
            }

            // invoke function
            response.Return(DreamMessage.Ok(new DekiScriptList().Add(eval).ToXml()));
            yield break;
        }
示例#5
0
        public Yield PostExtensionFunction(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            string name = context.GetParam("function");

            // check if we need to reload the manifest
            if (_debug)
            {
                LoadScript();
            }

            // find function
            DekiScriptInvocationTargetDescriptor descriptor;

            if (!_functions.TryGetValue(Self.At(name), out descriptor))
            {
                response.Return(DreamMessage.NotFound(string.Format("function {0} not found", name)));
                yield break;
            }

            // set optional culture from request
            context.Culture = HttpUtil.GetCultureInfoFromHeader(request.Headers.AcceptLanguage, context.Culture);

            // read input arguments for invocation
            DekiScriptLiteral args = DekiScriptLiteral.FromXml(request.ToDocument());

            // create custom environment
            var implicitEnv = DekiExtService.GetImplicitEnvironment(request, _publicDigitalSignature);

            implicitEnv.AddNativeValueAt("self", Self.Uri.AsPublicUri().ToString());
            DreamContext.Current.SetState("env.implicit", implicitEnv);

            // invoke target
            DekiScriptLiteral eval;

            try {
                eval = descriptor.Target.Invoke(ScriptRuntime, args);
            } catch (Exception e) {
                response.Return(DreamMessage.InternalError(e));
                yield break;
            }

            // check if response is embeddable XML
            if (eval is DekiScriptXml)
            {
                XDoc doc = ((DekiScriptXml)eval).Value;
                if (doc.HasName("html"))
                {
                    // replace all self: references
                    foreach (XDoc item in doc[".//*[starts-with(@src, 'self:')]/@src | .//*[starts-with(@href, 'self:')]/@href"])
                    {
                        try {
                            item.ReplaceValue(Self.AtPath(item.Contents.Substring(5)));
                        } catch { }
                    }
                }
            }

            // process response
            DekiScriptList result = new DekiScriptList().Add(eval);

            response.Return(DreamMessage.Ok(result.ToXml()));
        }
示例#6
0
        public void Create_entries_in_cache()
        {
            DekiScriptLiteral result;

            // create web-cahce extension service
            var webcache = DreamTestHelper.CreateService(
                _hostInfo,
                new XDoc("config")
                .Elem("class", typeof(WebCacheService).FullName)
                .Elem("path", "webcache")
                );

            // extract entry points for web-cache functions
            var manifest = webcache.AtLocalHost.Get().AsDocument();
            var fetch    = Plug.New(manifest["function[name/text()='fetch']/uri"].AsUri);
            var store    = Plug.New(manifest["function[name/text()='store']/uri"].AsUri);
            var clear    = Plug.New(manifest["function[name/text()='clear']/uri"].AsUri);

            // create MAX_ITERATIONS entries in web-cache
            var sw = Stopwatch.StartNew();

            for (int i = 1; i <= MAX_ITERATIONS; ++i)
            {
                var key  = "key" + i;
                var list = new DekiScriptList()
                           .Add(DekiScriptExpression.Constant(key))
                           .Add(DekiScriptExpression.Constant(CONTENT));
                var response = store.Post(list.ToXml());
                var doc      = response.ToDocument();
                result = DekiScriptLiteral.FromXml(doc);
                _log.DebugFormat("webcache.store('{0}') -> {1}", key, result);
            }
            sw.Stop();
            _log.DebugFormat("webcache.store() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds);

            // shutdown web-cache service
            webcache.WithPrivateKey().AtLocalHost.Delete();

            // re-create web-cache extension service
            webcache = DreamTestHelper.CreateService(
                _hostInfo,
                new XDoc("config")
                .Elem("class", typeof(WebCacheService).FullName)
                .Elem("path", "webcache")
                );

            // re-extract entry points for web-cache functions
            manifest = webcache.AtLocalHost.Get().AsDocument();
            fetch    = Plug.New(manifest["function[name/text()='fetch']/uri"].AsUri);
            store    = Plug.New(manifest["function[name/text()='store']/uri"].AsUri);
            clear    = Plug.New(manifest["function[name/text()='clear']/uri"].AsUri);

            // loop over all entries in web-cache and fetch them
            sw = Stopwatch.StartNew();
            for (int i = 1; i <= MAX_ITERATIONS; ++i)
            {
                int count = 0;
                var key   = "key" + i;
                do
                {
                    result = DekiScriptLiteral.FromXml(fetch.Post(new DekiScriptList().Add(DekiScriptExpression.Constant(key)).ToXml()).ToDocument());
                    var text = ((DekiScriptList)result)[0].AsString();
                    if (text == CONTENT)
                    {
                        break;
                    }
                    Thread.Sleep(50);
                } while(++count < 100);
                if (count >= 100)
                {
                    Assert.Fail("too many attempts to load " + key);
                    return;
                }
            }
            sw.Stop();
            _log.DebugFormat("webcache.fetch() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds);

            // loop over all entries in web-cache and clear them out
            sw = Stopwatch.StartNew();
            for (int i = 1; i <= MAX_ITERATIONS; ++i)
            {
                var key  = "key" + i;
                var list = new DekiScriptList()
                           .Add(DekiScriptExpression.Constant(key));
                var response = clear.Post(list.ToXml());
                var doc      = response.ToDocument();
                result = DekiScriptLiteral.FromXml(doc);
                _log.DebugFormat("webcache.clear('{0}') -> {1}", key, result);
            }
            sw.Stop();
            _log.DebugFormat("webcache.clear() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds);

            // loop over all entries in web-cache and fetch them
            sw = Stopwatch.StartNew();
            for (int i = 1; i <= MAX_ITERATIONS; ++i)
            {
                var key = "key" + i;
                result = DekiScriptLiteral.FromXml(fetch.Post(new DekiScriptList().Add(DekiScriptExpression.Constant(key)).ToXml()).ToDocument());
                var text = ((DekiScriptList)result)[0].AsString();
                Assert.AreEqual(null, text, "entry " + key + " was not deleted");
            }
            sw.Stop();
            _log.DebugFormat("webcache.fetch() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds);

            // shutdown web-cache service again
            webcache.WithPrivateKey().AtLocalHost.Delete();
        }