Example #1
0
        internal static XDoc CreateWarningFromException(DekiScriptList callstack, Location location, Exception exception)
        {
            // unwrap nested async exception
            exception = UnwrapAsyncException(null, exception);

            // determine exception
            XDoc result;

            if (exception is DreamAbortException)
            {
                DreamAbortException e = (DreamAbortException)exception;
                if (e.Response.ContentType.IsXml)
                {
                    result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), new XMessage(e.Response).ToPrettyString());
                }
                else
                {
                    result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), e.Response.AsText());
                }
            }
            else if (exception is DekiScriptException)
            {
                result = CreateWarningElement(callstack, exception.Message, exception.GetCoroutineStackTrace());
            }
            else
            {
                result = CreateWarningElement(callstack, string.Format("{0}: {1}", exception.Message, location), exception.GetCoroutineStackTrace());
            }
            return(result);
        }
        private static DekiScriptLiteral FromXmlRpcToDekiScript(XDoc xdoc)
        {
            if (xdoc.HasName("html"))
            {
                return(new DekiScriptList().Add(new DekiScriptXml(xdoc)));
            }
            if (xdoc.HasName("methodResponse"))
            {
                if (!xdoc["fault"].IsEmpty)
                {
                    string errorMessage = xdoc["fault/value/struct/member[name='faultString']/value/string"].AsText;
                    throw new DekiScriptXmlRpcException(errorMessage ?? xdoc.ToPrettyString());
                }
                if (!xdoc["params"].IsEmpty)
                {
                    DekiScriptList result = new DekiScriptList();
                    foreach (XDoc param in xdoc["params/param/value"])
                    {
                        result.Add(ToDekiScriptRecurse(param));
                    }
                    return(result);
                }
                else
                {
                    // NOTE: unexpected result, treat it as a nil result

                    DekiScriptList result = new DekiScriptList();
                    result.Add(DekiScriptNil.Value);
                    return(result);
                }
            }
            throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", xdoc.Name));
        }
Example #3
0
        public static XDoc CreateWarningElement(DekiScriptList callstack, String description, string message)
        {
            if (callstack != null)
            {
                StringBuilder stacktrace = new StringBuilder();
                foreach (var entry in from item in callstack.Value let entry = item.AsString() where entry != null select entry)
                {
                    stacktrace.AppendFormat("    at {0}\n", entry);
                }
                if (stacktrace.Length > 0)
                {
                    if (message == null)
                    {
                        message = "Callstack:\n" + stacktrace;
                    }
                    else
                    {
                        message = "Callstack:\n" + stacktrace + "\n" + message;
                    }
                }
            }

            XDoc result = new XDoc("div");

            result.Start("span").Attr("class", "warning").Value(description).End();
            if (message != null)
            {
                string id = StringUtil.CreateAlphaNumericKey(8);
                result.Value(" ");
                result.Start("span").Attr("style", "cursor: pointer;").Attr("onclick", string.Format("$('#{0}').toggle()", id)).Value("(click for details)").End();
                result.Start("pre").Attr("id", id).Attr("style", "display: none;").Value(message).End();
            }
            return(result);
        }
Example #4
0
        public static DekiScriptMap ValidateToMap(DekiScriptParameter[] parameters, DekiScriptList args) {
            DekiScriptMap result = new DekiScriptMap();

            // check passed in arguments
            int i = 0;
            var count = Math.Min(args.Value.Count, parameters.Length);
            for(; i < count; ++i) {
                var value = args[i];
                if(value.IsNil) {
                    if((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) {
                        throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i));
                    }

                    // set default value for this parameter
                    result.Add(parameters[i].Name, parameters[i].Default);
                } else {
                    result.Add(parameters[i].Name, parameters[i].Convert(value));
                }
            }

            // check that missing arguments are optional
            for(; i < parameters.Length; ++i) {
                if((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) {
                    throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i));
                }
                result.Add(parameters[i].Name, parameters[i].Default);
            }
            return result;
        }
        public DekiScriptExpression Visit(DekiScriptListConstructor expr, DekiScriptExpressionEvaluationState state)
        {
            // TODO (steveb): need to figure out how to optimize lists with generators
            if (expr.Generator != null)
            {
                return(expr);
            }

            // optimize each item in the list
            DekiScriptExpression[] list = new DekiScriptExpression[expr.Items.Length];
            bool isLiteral = true;

            for (int i = 0; i < expr.Items.Length; i++)
            {
                DekiScriptExpression item = expr.Items[i].VisitWith(this, state);
                list[i]   = item;
                isLiteral = isLiteral && (item is DekiScriptLiteral);
            }
            if (!isLiteral)
            {
                return(DekiScriptExpression.List(expr.Location, list));
            }

            // convert expression to a list
            DekiScriptList result = new DekiScriptList();

            foreach (DekiScriptLiteral literal in list)
            {
                result.Add(literal);
            }
            return(result);
        }
        //--- Methods ---
        public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList 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];
        }
Example #7
0
        //--- Class Methods ---
        public static DekiScriptMap MakeErrorObject(Exception e, DekiScriptEnv env) {
            DekiScriptMap exception = new DekiScriptMap();

            // add call stack if one is available
            DekiScriptList callstack = null;
            if(env != null) {
                DekiScriptLiteral callstackVar;
                if(env.Vars.TryGetValue(DekiScriptEnv.CALLSTACK, out callstackVar)) {
                    callstack = callstackVar as DekiScriptList;
                }
            }
            while(e is DekiScriptInvokeException) {
                var ex = (DekiScriptInvokeException)e;
                if(callstack == null) {
                    callstack = new DekiScriptList();
                }
                callstack.AddNativeValue(ex.FunctionName);
                e = ex.InnerException;
            }
            if(callstack != null) {
                exception.Add("callstack", callstack);
            }

            // add exception text
            exception.Add("message", DekiScriptExpression.Constant(e.Message));
            exception.Add("stacktrace", DekiScriptExpression.Constant(e.GetCoroutineStackTrace()));
            if(e.InnerException != null) {
                exception.Add("inner", MakeErrorObject(e.InnerException, null));
            }
            if(e is DekiScriptException) {
                exception.Add("source", DekiScriptExpression.Constant(((DekiScriptException)e).Location.Origin));
            }
            return exception;
        }
Example #8
0
        private DekiScriptLiteral InvokeHelper(DekiScriptRuntime runtime, DekiScriptList args)
        {
            // convert passed in arguments
            object[] arguments = new object[Parameters.Length];
            int      i         = 0;

            try {
                for (; i < Parameters.Length; ++i)
                {
                    var value = args[i].NativeValue;

                    // check if we need to convert the value
                    if ((value != null) && (Parameters[i].NativeType != typeof(object)))
                    {
                        // check for the special case where we cast from XML to STR
                        if ((value is XDoc) && (Parameters[i].NativeType == typeof(string)))
                        {
                            XDoc xml = (XDoc)value;
                            if (xml.HasName("html"))
                            {
                                value = xml["body[not(@target)]"].Contents;
                            }
                            else
                            {
                                value = xml.ToString();
                            }
                        }
                        else
                        {
                            // rely on the default type conversion rules
                            value = SysUtil.ChangeType(value, Parameters[i].NativeType);
                        }
                    }
                    arguments[i] = value;
                }
            } catch {
                throw new ArgumentException(string.Format("could not convert parameter '{0}' (index {1}) from {2} to {3}", Parameters[i].Name, i, args[i].ScriptTypeName, DekiScriptLiteral.AsScriptTypeName(Parameters[i].ScriptType)));
            }

            // invoke method
            var result = _invoke(runtime, arguments);

            // check if result is a URI
            if (result is XUri)
            {
                // normalize URI if possible
                DreamContext context = DreamContext.CurrentOrNull;
                if (context != null)
                {
                    result = context.AsPublicUri((XUri)result);
                }
            }
            var literal = DekiScriptLiteral.FromNativeValue(result);

            try {
                return(literal.Convert(ReturnType));
            } catch (DekiScriptInvalidCastException) {
                throw new DekiScriptInvalidReturnCastException(Location.None, literal.ScriptType, ReturnType);
            }
        }
        internal void InsertExceptionMessageBeforeNode(DekiScriptEnv env, XmlNode parent, XmlNode reference, Location location, Exception exception)
        {
            if (Fallthrough)
            {
                throw exception;
            }
            if (exception is DekiScriptDocumentTooLargeException)
            {
                DekiScriptDocumentTooLargeException e = (DekiScriptDocumentTooLargeException)exception;

                // check if an error message was already embedded
                if (e.Handled)
                {
                    throw exception;
                }
                e.Handled = true;
            }

            // check if environment has a __callstack variable
            DekiScriptList    callstack = null;
            DekiScriptLiteral callstackVar;

            if (env.Vars.TryGetValue(DekiScriptEnv.CALLSTACK, out callstackVar))
            {
                callstack = callstackVar as DekiScriptList;
            }

            XDoc warning = DekiScriptRuntime.CreateWarningFromException(callstack, location, exception);

            parent.InsertBefore(parent.OwnerDocument.ImportNode(warning.AsXmlNode, true), reference);
            if (exception is DekiScriptDocumentTooLargeException)
            {
                throw exception;
            }
        }
Example #10
0
        public static DekiScriptList ValidateToList(DekiScriptParameter[] parameters, DekiScriptMap args)
        {
            DekiScriptList result = new DekiScriptList();

            // check passed in arguments
            for (int i = 0; i < parameters.Length; ++i)
            {
                var value = args[parameters[i].Name];
                if (value.IsNil)
                {
                    if ((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional)
                    {
                        throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i));
                    }

                    // set default value for this parameter
                    result.Add(parameters[i].Default);
                }
                else
                {
                    result.Add(parameters[i].Convert(value));
                }
            }
            return(result);
        }
Example #11
0
 public void Call_func_with_arg_list() {
     string path = LoadExtension();
     DekiScriptList args = new DekiScriptList()
         .Add(DekiScriptExpression.Constant("1"))
         .Add(DekiScriptExpression.Constant("2"));
     DreamMessage result = Plug.New(_host.LocalMachineUri).At(path, "Addition").Post(args.ToXml());
     Assert.IsTrue(result.IsSuccessful);
     XDoc resultDoc = result.ToDocument();
     Assert.AreEqual("value", resultDoc.Name);
     Assert.AreEqual(3, resultDoc.Elements.First.AsInt);
 }
        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);
        }
Example #13
0
        public void Call_func_with_arg_list()
        {
            string         path = LoadExtension();
            DekiScriptList args = new DekiScriptList()
                                  .Add(DekiScriptExpression.Constant("1"))
                                  .Add(DekiScriptExpression.Constant("2"));
            DreamMessage result = Plug.New(_host.LocalMachineUri).At(path, "Addition").Post(args.ToXml());

            Assert.IsTrue(result.IsSuccessful);
            XDoc resultDoc = result.ToDocument();

            Assert.AreEqual("value", resultDoc.Name);
            Assert.AreEqual(3, resultDoc.Elements.First.AsInt);
        }
        private static DekiScriptLiteral ToDekiScriptRecurse(XDoc doc)
        {
            XDoc xdoc = doc.Elements;

            switch (xdoc.Name)
            {
            case "nil":
                return(DekiScriptNil.Value);

            case "boolean":
                if (xdoc.Contents.GetType().Equals(typeof(String)))
                {
                    return(DekiScriptExpression.Constant((xdoc.Contents.Contains("1") || xdoc.Contents.Contains("true")) ? true : false));
                }
                return(DekiScriptExpression.Constant(xdoc.AsBool ?? false));

            case "double":
                return(DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0));

            case "int":
            case "i4":
                return(DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0));

            case "string":
                return(DekiScriptExpression.Constant(xdoc.AsText ?? string.Empty));

            case "struct": {
                DekiScriptMap result = new DekiScriptMap();
                foreach (XDoc value in xdoc["member"])
                {
                    result.Add(value["name"].Contents, ToDekiScriptRecurse(value["value"]));
                }
                return(result);
            }

            case "array": {
                DekiScriptList result = new DekiScriptList();
                foreach (XDoc value in xdoc["data/value"])
                {
                    result.Add(ToDekiScriptRecurse(value));
                }
                return(result);
            }

            default:
                throw new ArgumentException("this type does not exist in the XML-RPC standard");
            }
        }
        //--- Methods ---
        public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args)
        {
            // prepare uri for invocation
            Plug plug = Plug.New(_endpoint);

            plug = runtime.PreparePlug(plug);
            DreamMessage response = plug.Post(DekiScriptToXmlRpc(_methodname, args));

            // convert response to literal
            DekiScriptLiteral list = FromXmlRpcToDekiScript(response.ToDocument());

            if (list.ScriptType != DekiScriptType.LIST)
            {
                throw new DekiScriptBadReturnTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST });
            }
            return(((DekiScriptList)list)[0]);
        }
Example #16
0
        //--- Class Methods ---
        public static DekiScriptMap MakeErrorObject(Exception e, DekiScriptEnv env)
        {
            DekiScriptMap exception = new DekiScriptMap();

            // add call stack if one is available
            DekiScriptList callstack = null;

            if (env != null)
            {
                DekiScriptLiteral callstackVar;
                if (env.Vars.TryGetValue(DekiScriptEnv.CALLSTACK, out callstackVar))
                {
                    callstack = callstackVar as DekiScriptList;
                }
            }
            while (e is DekiScriptInvokeException)
            {
                var ex = (DekiScriptInvokeException)e;
                if (callstack == null)
                {
                    callstack = new DekiScriptList();
                }
                callstack.AddNativeValue(ex.FunctionName);
                e = ex.InnerException;
            }
            if (callstack != null)
            {
                exception.Add("callstack", callstack);
            }

            // add exception text
            exception.Add("message", DekiScriptExpression.Constant(e.Message));
            exception.Add("stacktrace", DekiScriptExpression.Constant(e.GetCoroutineStackTrace()));
            if (e.InnerException != null)
            {
                exception.Add("inner", MakeErrorObject(e.InnerException, null));
            }
            if (e is DekiScriptException)
            {
                exception.Add("source", DekiScriptExpression.Constant(((DekiScriptException)e).Location.Origin));
            }
            return(exception);
        }
        public DekiScriptLiteral Visit(DekiScriptListConstructor expr, DekiScriptEnv env)
        {
            DekiScriptList result = new DekiScriptList();

            if (expr.Generator == null)
            {
                foreach (DekiScriptExpression item in expr.Items)
                {
                    result.Add(item.VisitWith(this, env));
                }
            }
            else
            {
                DekiScriptGeneratorEvaluation.Instance.Generate(expr.Generator, delegate(DekiScriptEnv subEnv) {
                    foreach (DekiScriptExpression item in expr.Items)
                    {
                        result.Add(item.VisitWith(this, subEnv));
                    }
                }, env.NewLocalScope());
            }
            return(result);
        }
Example #18
0
        public static DekiScriptMap ValidateToMap(DekiScriptParameter[] parameters, DekiScriptList args)
        {
            DekiScriptMap result = new DekiScriptMap();

            // check passed in arguments
            int i     = 0;
            var count = Math.Min(args.Value.Count, parameters.Length);

            for (; i < count; ++i)
            {
                var value = args[i];
                if (value.IsNil)
                {
                    if ((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional)
                    {
                        throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i));
                    }

                    // set default value for this parameter
                    result.Add(parameters[i].Name, parameters[i].Default);
                }
                else
                {
                    result.Add(parameters[i].Name, parameters[i].Convert(value));
                }
            }

            // check that missing arguments are optional
            for (; i < parameters.Length; ++i)
            {
                if ((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional)
                {
                    throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i));
                }
                result.Add(parameters[i].Name, parameters[i].Default);
            }
            return(result);
        }
        //--- Methods ---
        public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList 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 DekiScriptOutputBuffer.Range Visit(DekiScriptListConstructor expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptList result = new DekiScriptList();

            if (expr.Generator == null)
            {
                foreach (DekiScriptExpression item in expr.Items)
                {
                    result.Add(state.Pop(item.VisitWith(this, state)));
                }
            }
            else
            {
                DekiScriptGeneratorEvaluation.Generate(expr.Generator, delegate(DekiScriptEnv subEnv) {
                    foreach (DekiScriptExpression item in expr.Items)
                    {
                        var eval = state.Pop(item.VisitWith(this, state.With(subEnv)));
                        result.Add(eval);
                    }
                }, state);
            }
            return(state.Push(result));
        }
 //--- Abstract Methods ---
 public abstract DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args);
Example #22
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();
        }
 //--- Methods ---
 public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args)
 {
     throw new DekiScriptBadTypeException(Location.None, args.ScriptType, new[] { DekiScriptType.MAP });
 }
Example #24
0
 //--- Methods ---
 public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) {
     return InvokeHelper(runtime, DekiScriptParameter.ValidateToMap(Parameters, args));
 }
 public DekiScriptLiteral Visit(DekiScriptList expr, DekiScriptEnv env)
 {
     return(expr);
 }
        private DekiScriptLiteral InvokeHelper(DekiScriptRuntime runtime, DekiScriptList args) {

            // convert passed in arguments
            object[] arguments = new object[Parameters.Length];
            int i = 0;
            try {
                for(; i < Parameters.Length; ++i) {
                    var value = args[i].NativeValue;

                    // check if we need to convert the value
                    if((value != null) && (Parameters[i].NativeType != typeof(object))) {

                        // check for the special case where we cast from XML to STR
                        if((value is XDoc) && (Parameters[i].NativeType == typeof(string))) {
                            XDoc xml = (XDoc)value;
                            if(xml.HasName("html")) {
                                value = xml["body[not(@target)]"].Contents;
                            } else {
                                value = xml.ToString();
                            }
                        } else {

                            // rely on the default type conversion rules
                            value = SysUtil.ChangeType(value, Parameters[i].NativeType);
                        }
                    }
                    arguments[i] = value;
                }
            } catch {
                throw new ArgumentException(string.Format("could not convert parameter '{0}' (index {1}) from {2} to {3}", Parameters[i].Name, i, args[i].ScriptTypeName, DekiScriptLiteral.AsScriptTypeName(Parameters[i].ScriptType)));
            }

            // invoke method
            var result = _invoke(runtime, arguments);

            // check if result is a URI
            if(result is XUri) {

                // normalize URI if possible
                DreamContext context = DreamContext.CurrentOrNull;
                if(context != null) {
                    result = context.AsPublicUri((XUri)result);
                }
            }
            var literal = DekiScriptLiteral.FromNativeValue(result);
            try {
                return literal.Convert(ReturnType);
            } catch(DekiScriptInvalidCastException) {
                throw new DekiScriptInvalidReturnCastException(Location.None, literal.ScriptType, ReturnType);
            }
        }
        public static XDoc CreateWarningElement(DekiScriptList callstack, String description, string message) {
            if(callstack != null) {
                StringBuilder stacktrace = new StringBuilder();
                foreach(var entry in from item in callstack.Value let entry = item.AsString() where entry != null select entry) {
                    stacktrace.AppendFormat("    at {0}\n", entry);
                }
                if(stacktrace.Length > 0) {
                    if(message == null) {
                        message = "Callstack:\n" + stacktrace;
                    } else {
                        message = "Callstack:\n" + stacktrace + "\n" + message;
                    }
                }
            }

            XDoc result = new XDoc("div");
            result.Start("span").Attr("class", "warning").Value(description).End();
            if(message != null) {
                string id = StringUtil.CreateAlphaNumericKey(8);
                result.Value(" ");
                result.Start("span").Attr("style", "cursor: pointer;").Attr("onclick", string.Format("$('#{0}').toggle()", id)).Value("(click for details)").End();
                result.Start("pre").Attr("id", id).Attr("style", "display: none;").Value(message).End();
            }
            return result;
        }
 //--- Abstract Methods ---
 public abstract DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args);
        public DekiScriptOutputBuffer.Range Visit(DekiScriptCall expr, DekiScriptExpressionEvaluationState state)
        {
            state.ThrowIfTimedout();

            // evaluate prefix
            DekiScriptLiteral prefix = state.Pop(expr.Prefix.VisitWith(this, state));

            if (prefix.ScriptType != DekiScriptType.URI)
            {
                if (prefix.ScriptType == DekiScriptType.NIL)
                {
                    throw new DekiScriptUndefinedNameException(expr.Location, expr.Prefix.ToString());
                }
                else
                {
                    throw new DekiScriptBadTypeException(expr.Location, prefix.ScriptType, new[] { DekiScriptType.URI });
                }
            }

            // evaluate arguments
            DekiScriptLiteral arguments = state.Pop(expr.Arguments.VisitWith(this, state));

            if ((arguments.ScriptType != DekiScriptType.MAP) && (arguments.ScriptType != DekiScriptType.LIST))
            {
                throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST });
            }

            // check if the URI was curried
            DekiScriptUri uri = (DekiScriptUri)prefix;

            if (!uri.Arguments.IsNil)
            {
                switch (uri.Arguments.ScriptType)
                {
                case DekiScriptType.LIST:

                    // append argument to list
                    DekiScriptList list = new DekiScriptList((DekiScriptList)uri.Arguments);
                    list.Add(arguments);
                    arguments = list;
                    break;

                case DekiScriptType.MAP:
                    if (arguments.ScriptType == DekiScriptType.MAP)
                    {
                        // concatenate both maps
                        DekiScriptMap map = new DekiScriptMap();
                        map.AddRange((DekiScriptMap)uri.Arguments);
                        map.AddRange((DekiScriptMap)arguments);
                        arguments = map;
                    }
                    else if ((arguments.ScriptType != DekiScriptType.LIST) || ((DekiScriptList)arguments).Value.Count > 0)
                    {
                        // we can't append a list to a map
                        throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP });
                    }
                    break;

                default:
                    throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST });
                }
            }

            // check if this is an invocation or curry operation
            if (expr.IsCurryOperation)
            {
                return(state.Push(new DekiScriptUri(uri.Value, arguments)));
            }

            // invoke function
            try {
                return(state.Push(state.Runtime.Invoke(expr.Location, uri.Value, arguments, state.Env)));
            } catch (DekiScriptFatalException) {
                throw;
            } catch (Exception e) {
                var descriptor = state.Runtime.ResolveRegisteredFunctionUri(uri.Value);
                throw new DekiScriptInvokeException(expr.Location, uri.Value, (descriptor != null) ? descriptor.Name : uri.Value.ToString(), e);
            }
        }
Example #30
0
        //--- Methods ---
        private DekiScriptEnv ProcessEnvironment() {
            var current = DreamContext.Current;
            DekiScriptEnv env = current.GetState<DekiScriptEnv>("pageenv-" + _basePage.ID);

            // check if we already have an initialized environment
            if(env == null) {

                // create environment
                env = ExtensionBL.CreateEnvironment(_basePage);

                // add request arguments
                DekiScriptMap request = new DekiScriptMap();
                DekiScriptMap queryArgs = new DekiScriptMap();
                DreamContext context = DreamContext.CurrentOrNull;
                if(context != null) {
                    if(context.Uri.Params != null) {
                        foreach(KeyValuePair<string, string> query in context.Uri.Params) {

                            // check that query parameter doesn't have 'dream.' prefix
                            if(!query.Key.StartsWithInvariantIgnoreCase("dream.")) {
                                DekiScriptLiteral value;

                                // check if a query parameter with the same name was alreayd found
                                if(queryArgs.TryGetValue(query.Key, out value)) {
                                    DekiScriptList list = value as DekiScriptList;

                                    // check if the current value is already a list
                                    if(list == null) {
                                        list = new DekiScriptList();
                                        list.Add(value);

                                        // replace current value
                                        queryArgs.Add(query.Key, list);
                                    }

                                    // append new value to list
                                    list.Add(DekiScriptExpression.Constant(query.Value));
                                } else {

                                    // add query parameter
                                    queryArgs.Add(query.Key, DekiScriptExpression.Constant(query.Value));
                                }
                            }
                        }
                    }

                    // show User-Agent, Referer and Host information in __request
                    request.Add("referer", DekiScriptExpression.Constant(context.Request.Headers.Referer));
                    request.Add("useragent", DekiScriptExpression.Constant(context.Request.Headers.UserAgent));
                    request.Add("host", DekiScriptExpression.Constant(context.Request.Headers.Host));

                    // determine the client IP address
                    var clientIPs = current.Request.Headers.DreamClientIP;
                    if(clientIPs.Length > 0) {
                        request.Add("client", DekiScriptExpression.Constant(clientIPs[clientIPs.Length - 1]));
                    } else {
                        request.Add("client", DekiScriptNil.Value);
                    }

                    // parse form fields from a request for requests with a mimetype of application/x-www-form-urlencoded
                    DekiScriptMap postParams;
                    if(context.Request.ContentType.Match(MimeType.FORM_URLENCODED)) {
                        KeyValuePair<string, string>[] formFields = XUri.ParseParamsAsPairs(context.Request.ToText());
                        if(!ArrayUtil.IsNullOrEmpty(formFields)) {
                            postParams = new DekiScriptMap();
                            foreach(KeyValuePair<string, string> kvp in formFields) {
                                postParams.Add(kvp.Key, DekiScriptExpression.Constant(kvp.Value));
                            }
                            request.Add("fields", postParams);
                        }
                    }
                }
                request.Add("args", queryArgs);
                env.Vars.Add("__request", request);

                // store computed environment for subsequent calls
                current.SetState("pageenv-" + _basePage.ID, env);
            }
            env = env.NewScope();

            // global processing variables
            env.Vars.Add("__include", DekiScriptExpression.Constant(_isInclude));
            env.Vars.Add("__mode", DekiScriptExpression.Constant(_mode.ToString().ToLowerInvariant()));
            env.Vars.Add(DekiScriptEnv.SAFEMODE, DekiScriptExpression.Constant(ExtensionRuntime.IsSafeMode(_page)));
            env.Vars.Add("__page", DekiContext.Current.Deki.PropertyAt("$page", _page.ID, true));

            // set processing settings
            DekiScriptMap settings = new DekiScriptMap();
            settings.Add("nofollow", DekiScriptExpression.Constant(DekiContext.Current.Instance.WebLinkNoFollow));
            env.Vars.Add(DekiScriptEnv.SETTINGS, settings);

            // add callstack (specific for each page invocation)
            DekiScriptList callstack = new DekiScriptList();
            ParserState parseState = GetParseState();
            if(parseState != null) {
                foreach(PageBE includingPage in parseState.ProcessingStack) {
                    callstack.Add(DekiScriptExpression.Constant(includingPage.Title.AsPrefixedDbPath()));
                }
                env.Vars.Add(DekiScriptEnv.CALLSTACK, callstack);
            }

            // add arguments environment vars
            env.Vars.Add("args", _args ?? DekiScriptNil.Value);
            env.Vars.Add("$", _args ?? DekiScriptNil.Value);
            return env.NewScope();
        }
        internal DekiScriptLiteral Evaluate(DekiScriptAccess expr, DekiScriptExpressionEvaluationState state, bool evaluateProperties)
        {
            DekiScriptLiteral prefix = state.Pop(expr.Prefix.VisitWith(this, state));
            DekiScriptLiteral index  = state.Pop(expr.Index.VisitWith(this, state));

            switch (prefix.ScriptType)
            {
            case DekiScriptType.MAP: {
                DekiScriptLiteral result = ((DekiScriptMap)prefix)[index];
                if (evaluateProperties)
                {
                    result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env);
                }
                return(result);
            }

            case DekiScriptType.LIST: {
                DekiScriptLiteral value  = DekiScriptExpression.Constant(index.AsNumber());
                DekiScriptLiteral result = ((DekiScriptList)prefix)[value];
                if (evaluateProperties)
                {
                    result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env);
                }
                return(result);
            }

            case DekiScriptType.URI: {
                DekiScriptUri uri = (DekiScriptUri)prefix;

                // coerce the index type to STR
                index = DekiScriptExpression.Constant(index.AsString());
                if (index.ScriptType != DekiScriptType.STR)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR });
                }

                // curry the argument
                DekiScriptList args;
                if (!uri.Arguments.IsNil)
                {
                    // the uri already has curried parameters, make sure they are in LIST format; otherwise fail
                    if (uri.Arguments.ScriptType != DekiScriptType.LIST)
                    {
                        throw new DekiScriptBadTypeException(expr.Location, uri.Arguments.ScriptType, new[] { DekiScriptType.NIL, DekiScriptType.LIST });
                    }
                    args = new DekiScriptList((DekiScriptList)uri.Arguments);
                }
                else
                {
                    args = new DekiScriptList();
                }
                args.Add(index);
                return(new DekiScriptUri(uri.Value, args));
            }

            case DekiScriptType.STR: {
                DekiScriptString text = (DekiScriptString)prefix;

                // coerce the index type to NUM
                double?value = index.AsNumber();
                if (value == null)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.NUM });
                }

                // retrieve character at given index position
                int position = (int)value;
                if ((position < 0) || (position >= text.Value.Length))
                {
                    // index is out of bounds, return nil
                    return(DekiScriptNil.Value);
                }
                return(DekiScriptExpression.Constant(text.Value[position].ToString()));
            }

            case DekiScriptType.XML: {
                string path = index.AsString();
                if (path == null)
                {
                    throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR });
                }
                XDoc doc = ((DekiScriptXml)prefix).Value[path];
                if (doc.HasName("html"))
                {
                    doc = DekiScriptLibrary.CleanseHtmlDocument(doc);
                }
                return(new DekiScriptXml(doc));
            }

            case DekiScriptType.NIL:
                return(DekiScriptNil.Value);
            }
            throw new DekiScriptBadTypeException(expr.Location, prefix.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST, DekiScriptType.XML, DekiScriptType.STR, DekiScriptType.URI });
        }
        public DekiScriptOutputBuffer.Range Visit(DekiScriptBinary expr, DekiScriptExpressionEvaluationState state)
        {
            DekiScriptExpression Left  = expr.Left;
            DekiScriptExpression Right = expr.Right;

            switch (expr.OpCode)
            {
            case DekiScriptBinary.Op.LeftValue:
                return(Left.VisitWith(this, state));

            case DekiScriptBinary.Op.IdentityEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.IdentityEqual(left, right)));
            }

            case DekiScriptBinary.Op.IdentityNotEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.IdentityNotEqual(left, right)));
            }

            case DekiScriptBinary.Op.IsType: {
                DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state));
                string            type = ((DekiScriptString)Right).Value;
                return(state.Push(DekiScriptExpression.Constant(type.EqualsInvariantIgnoreCase("any") || left.ScriptTypeName.EqualsInvariantIgnoreCase(type))));
            }

            case DekiScriptBinary.Op.Equal: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.Equal(left, right)));
            }

            case DekiScriptBinary.Op.NotEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                return(state.Push(DekiScriptBinary.NotEqual(left, right)));
            }

            case DekiScriptBinary.Op.GreaterOrEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() >= right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) >= 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.GreaterThan: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() > right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) > 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LessOrEqual: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() <= right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) <= 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LessThan: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right))
                {
                    switch (left.ScriptType)
                    {
                    case DekiScriptType.BOOL:
                    case DekiScriptType.NUM:
                        return(state.Push(DekiScriptExpression.Constant(left.AsNumber() < right.AsNumber())));

                    case DekiScriptType.STR:
                        return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) < 0)));

                    default:
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
                else
                {
                    return(DekiScriptOutputBuffer.Range.Empty);
                }
            }

            case DekiScriptBinary.Op.LogicalAnd: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (!result.IsNilFalseZero)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.LogicalOr: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (result.IsNilFalseZero)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.Addition:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() + state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Division:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() / state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Modulo: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if ((left is DekiScriptString) && ((right is DekiScriptMap) || (right is DekiScriptList)))
                {
                    // NOTE (steveb): string.format shorthand notation: "abc = $abc" % { abc: 123 } -OR- "0 = $0" % [ 123 ]
                    return(state.Push(DekiScriptLiteral.FromNativeValue(DekiScriptLibrary.StringFormat(((DekiScriptString)left).Value, right.NativeValue))));
                }
                else
                {
                    return(state.Push(DekiScriptExpression.Constant(left.AsNumber() % right.AsNumber())));
                }
            }

            case DekiScriptBinary.Op.Multiplication:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() * state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.Subtraction:
                return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() - state.Pop(Right.VisitWith(this, state)).AsNumber())));

            case DekiScriptBinary.Op.NullCoalesce: {
                DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state));
                if (result.IsNil)
                {
                    return(Right.VisitWith(this, state));
                }
                return(state.Push(result));
            }

            case DekiScriptBinary.Op.Concat: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (left is DekiScriptNil)
                {
                    return(state.Push(right));
                }
                else if (right is DekiScriptNil)
                {
                    return(state.Push(left));
                }
                else if ((left is DekiScriptMap) && (right is DekiScriptMap))
                {
                    // left and right expressions are maps, merge them
                    DekiScriptMap result = new DekiScriptMap();
                    result.AddRange((DekiScriptMap)left);
                    result.AddRange((DekiScriptMap)right);
                    return(state.Push(result));
                }
                else if ((left is DekiScriptList) && (right is DekiScriptList))
                {
                    // left and right expressions are lists, concatenate them
                    DekiScriptList result = new DekiScriptList();
                    result.AddRange((DekiScriptList)left);
                    result.AddRange((DekiScriptList)right);
                    return(state.Push(result));
                }
                else
                {
                    // treat left and right expressions as strings
                    string leftText  = left.AsString();
                    string rightText = right.AsString();
                    if ((leftText != null) && (rightText != null))
                    {
                        return(state.Push(DekiScriptExpression.Constant(leftText + rightText)));
                    }
                    else if (leftText != null)
                    {
                        return(state.Push(DekiScriptExpression.Constant(leftText)));
                    }
                    else if (rightText != null)
                    {
                        return(state.Push(DekiScriptExpression.Constant(rightText)));
                    }
                    else
                    {
                        return(DekiScriptOutputBuffer.Range.Empty);
                    }
                }
            }

            case DekiScriptBinary.Op.UriAppend: {
                // TODO (steveb): we should throw an exception when the LHS is not a valid string or uri

                XUri   left   = XUri.TryParse(state.Pop(Left.VisitWith(this, state)).AsString());
                string result = null;
                if (left != null)
                {
                    DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                    if (right is DekiScriptString)
                    {
                        result = DekiScriptLibrary.UriBuild(left, right.AsString(), null);
                    }
                    else if (right is DekiScriptMap)
                    {
                        result = DekiScriptLibrary.UriBuild(left, null, (Hashtable)right.NativeValue);
                    }
                    else
                    {
                        result = left.ToString();
                    }
                }
                return(state.Push(DekiScriptLiteral.FromNativeValue(result)));
            }

            case DekiScriptBinary.Op.InCollection: {
                DekiScriptLiteral left  = state.Pop(Left.VisitWith(this, state));
                DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state));
                if (right is DekiScriptList)
                {
                    foreach (DekiScriptLiteral item in ((DekiScriptList)right).Value)
                    {
                        if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero)
                        {
                            return(state.Push(DekiScriptBool.True));
                        }
                    }
                    return(state.Push(DekiScriptBool.False));
                }
                else if (right is DekiScriptMap)
                {
                    foreach (DekiScriptLiteral item in ((DekiScriptMap)right).Value.Values)
                    {
                        if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero)
                        {
                            return(state.Push(DekiScriptBool.True));
                        }
                    }
                    return(state.Push(DekiScriptBool.False));
                }
                else
                {
                    return(state.Push(DekiScriptBool.False));
                }
            }
            }
            throw new InvalidOperationException("invalid op code:" + expr.OpCode);
        }
 public DekiScriptOutputBuffer.Range Visit(DekiScriptList expr, DekiScriptExpressionEvaluationState state)
 {
     return(state.Push(expr));
 }
Example #34
0
        public static DekiScriptLiteral FromXml(XDoc doc) {

            // check if response is an HTML document
            if(doc.HasName("html")) {

                // TODO (steveb): this handling seems to be to specific to belong here.

                return new DekiScriptList().Add(new DekiScriptXml(doc));
            }

            // check if response is a DekiScript XML document
            if(!doc.HasName("value") || (doc["@type"].AsText == null)) {
                throw new ArgumentException("doc");
            }
            switch(doc["@type"].AsText) {
            case "nil":
                return DekiScriptNil.Value;
            case "bool":
                return Constant(doc.AsBool ?? false);
            case "num":
                return Constant(doc.AsDouble ?? 0.0);
            case "str":
                return Constant(doc.AsText ?? string.Empty);
            case "uri": {
                return Constant(doc.AsUri);
            }
            case "map": {
                DekiScriptMap result = new DekiScriptMap();
                foreach(XDoc value in doc["value"]) {
                    result.Add(value["@key"].AsText, FromXml(value));
                }
                return result;
            }
            case "list": {
                DekiScriptList result = new DekiScriptList();
                foreach(XDoc value in doc["value"]) {
                    result.Add(FromXml(value));
                }
                return result;
            }
            case "xml":
                if((doc.AsXmlNode.ChildNodes.Count == 1) && (doc.AsXmlNode.ChildNodes[0].NodeType == XmlNodeType.Element)) {
                    return new DekiScriptXml(doc[doc.AsXmlNode.ChildNodes[0]]);
                }
                return DekiScriptNil.Value;
            default:
                throw new ArgumentException("doc");
            }
        }
 private static DekiScriptLiteral ToDekiScriptRecurse(XDoc doc) {
     XDoc xdoc = doc.Elements;
     switch(xdoc.Name) {
     case "nil":
         return DekiScriptNil.Value;
     case "boolean":
         if(xdoc.Contents.GetType().Equals(typeof(String))) {
             return DekiScriptExpression.Constant((xdoc.Contents.Contains("1") || xdoc.Contents.Contains("true")) ? true : false);
         }
         return DekiScriptExpression.Constant(xdoc.AsBool ?? false);
     case "double":
         return DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0);
     case "int":
     case "i4":
         return DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0);
     case "string":
         return DekiScriptExpression.Constant(xdoc.AsText ?? string.Empty);
     case "struct": {
         DekiScriptMap result = new DekiScriptMap();
         foreach(XDoc value in xdoc["member"]) {
             result.Add(value["name"].Contents, ToDekiScriptRecurse(value["value"]));
         }
         return result;
     }
     case "array": {
         DekiScriptList result = new DekiScriptList();
         foreach(XDoc value in xdoc["data/value"]) {
             result.Add(ToDekiScriptRecurse(value));
         }
         return result;
     }
     default:
         throw new ArgumentException("this type does not exist in the XML-RPC standard");
     }
 }
        internal static XDoc CreateWarningFromException(DekiScriptList callstack, Location location, Exception exception) {

            // unwrap nested async exception
            exception = UnwrapAsyncException(null, exception);

            // determine exception
            XDoc result;
            if(exception is DreamAbortException) {
                DreamAbortException e = (DreamAbortException)exception;
                if(e.Response.ContentType.IsXml) {
                    result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), new XMessage(e.Response).ToPrettyString());
                } else {
                    result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), e.Response.AsText());
                }
            } else if(exception is DekiScriptException) {
                result = CreateWarningElement(callstack, exception.Message, exception.GetCoroutineStackTrace());
            } else {
                result = CreateWarningElement(callstack, string.Format("{0}: {1}", exception.Message, location), exception.GetCoroutineStackTrace());
            }
            return result;
        }
        //--- Methods ---
        public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) {

            // prepare uri for invocation
            Plug plug = Plug.New(_endpoint);
            plug = runtime.PreparePlug(plug);
            DreamMessage response = plug.Post(DekiScriptToXmlRpc(_methodname, args));

            // convert response to literal
            DekiScriptLiteral list = FromXmlRpcToDekiScript(response.ToDocument());
            if(list.ScriptType != DekiScriptType.LIST) {
                throw new DekiScriptBadReturnTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST });
            }
            return ((DekiScriptList)list)[0];
        }
 //--- Methods ---
 public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) {
     throw new DekiScriptBadTypeException(Location.None, args.ScriptType, new[] { DekiScriptType.MAP });
 }
        private static DekiScriptLiteral FromXmlRpcToDekiScript(XDoc xdoc) {
            if(xdoc.HasName("html")) {
                return new DekiScriptList().Add(new DekiScriptXml(xdoc));
            }
            if(xdoc.HasName("methodResponse")) {
                if(!xdoc["fault"].IsEmpty) {
                    string errorMessage = xdoc["fault/value/struct/member[name='faultString']/value/string"].AsText;
                    throw new DekiScriptXmlRpcException(errorMessage ?? xdoc.ToPrettyString());
                }
                if(!xdoc["params"].IsEmpty) {
                    DekiScriptList result = new DekiScriptList();
                    foreach(XDoc param in xdoc["params/param/value"]) {
                        result.Add(ToDekiScriptRecurse(param));
                    }
                    return result;
                } else {

                    // NOTE: unexpected result, treat it as a nil result

                    DekiScriptList result = new DekiScriptList();
                    result.Add(DekiScriptNil.Value);
                    return result;
                }
            }
            throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", xdoc.Name));
        }
 public DekiScriptExpression Visit(DekiScriptList expr, DekiScriptExpressionEvaluationState state)
 {
     return(expr);
 }
Example #41
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();
        }
Example #42
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()));
        }
        public object Store(
            [DekiExtParam("document id")] string id,
            [DekiExtParam("document to cache", true)] object document,
            [DekiExtParam("caching duration in seconds (range: 300+; default: 300)", true)] double?ttl
            )
        {
            if (document == null)
            {
                return(Clear(id));
            }

            // fetch entry from cache
            CacheEntry result;
            bool       isNew = true;

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

            // check if we have a cached entry
            if (result != null)
            {
                _log.DebugFormat("cache hit for '{0}'", result.Id);
                isNew = false;
                result.ResetMemoryExpiration();
            }
            else
            {
                _log.DebugFormat("new cache item for '{0}'", id);
                result = new CacheEntry(id, ttl);
            }

            // update cache with document
            DekiScriptLiteral literal = DekiScriptLiteral.FromNativeValue(document);
            XDoc xml = new DekiScriptList().Add(literal).ToXml();

            result.Cache = xml.ToString();

            // start timer to clean-up cached result
            if (result.Cache != null)
            {
                XDoc infoDoc = new XDoc("cache-entry")
                               .Elem("guid", result.Guid)
                               .Elem("id", result.Id)
                               .Elem("expires", result.Expires);
                lock (result) {
                    Storage.At(CACHE_DATA, result.Guid + ".bin").PutAsync(new DreamMessage(DreamStatus.Ok, null, MimeType.BINARY, Encoding.UTF8.GetBytes(result.Cache))).Wait();
                    Storage.At(CACHE_INFO, result.Guid + ".xml").PutAsync(infoDoc).Wait();
                }
                if (isNew)
                {
                    lock (_cacheLookup) {
                        _cacheLookup[id] = result;
                    }

                    // this timer removes the cache entry from disk
                    SetupCacheTimer(result);
                }
            }
            return(document);
        }
        public DekiScriptLiteral Visit(DekiScriptCall expr, DekiScriptEnv env)
        {
            // evaluate prefix
            DekiScriptLiteral prefix = expr.Prefix.VisitWith(this, env);

            if (prefix.ScriptType != DekiScriptType.URI)
            {
                if (prefix.ScriptType == DekiScriptType.NIL)
                {
                    throw new DekiScriptUndefinedNameException(expr.Line, expr.Column, expr.Prefix.ToString());
                }
                else
                {
                    throw new DekiScriptBadTypeException(expr.Line, expr.Column, prefix.ScriptType, new DekiScriptType[] { DekiScriptType.URI });
                }
            }

            // evaluate arguments
            DekiScriptLiteral arguments = expr.Arguments.VisitWith(this, env);

            if ((arguments.ScriptType != DekiScriptType.MAP) && (arguments.ScriptType != DekiScriptType.LIST))
            {
                throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP, DekiScriptType.LIST });
            }

            // check if the URI was curried
            DekiScriptUri uri = (DekiScriptUri)prefix;

            if (!uri.Arguments.IsNil)
            {
                switch (uri.Arguments.ScriptType)
                {
                case DekiScriptType.LIST:

                    // append argument to list
                    DekiScriptList list = new DekiScriptList((DekiScriptList)uri.Arguments);
                    list.Add(arguments);
                    arguments = list;
                    break;

                case DekiScriptType.MAP:
                    if (arguments.ScriptType == DekiScriptType.MAP)
                    {
                        // concatenate both maps
                        DekiScriptMap map = new DekiScriptMap();
                        map.AddRange((DekiScriptMap)uri.Arguments);
                        map.AddRange((DekiScriptMap)arguments);
                        arguments = map;
                    }
                    else if ((arguments.ScriptType != DekiScriptType.LIST) || ((DekiScriptList)arguments).Value.Count > 0)
                    {
                        // we can't append a list to a map
                        throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP });
                    }
                    break;

                default:
                    throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP, DekiScriptType.LIST });
                }
            }

            // check if this is an invocation or curry operation
            if (expr.IsCurryOperation)
            {
                return(new DekiScriptUri(uri.Value, arguments));
            }
            else
            {
                // invoke function
                return(Coroutine.Invoke(DekiScriptRuntime.Invoke, uri.Value, arguments, env, new Result <DekiScriptLiteral>()).Wait());
            }
        }
Example #45
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()));
        }
Example #46
0
 //--- Methods ---
 public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args)
 {
     return(InvokeHelper(runtime, DekiScriptParameter.ValidateToList(Parameters, args)));
 }
Example #47
0
        public static DekiScriptList ValidateToList(DekiScriptParameter[] parameters, DekiScriptMap args) {
            DekiScriptList result = new DekiScriptList();

            // check passed in arguments
            for(int i = 0; i < parameters.Length; ++i) {
                var value = args[parameters[i].Name];
                if(value.IsNil) {
                    if((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) {
                        throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i));
                    }

                    // set default value for this parameter
                    result.Add(parameters[i].Default);
                } else {
                    result.Add(parameters[i].Convert(value));
                }
            }
            return result;
        }
        public object Store(
           [DekiExtParam("document id")] string id,
           [DekiExtParam("document to cache", true)] object document,
           [DekiExtParam("caching duration in seconds (range: 300+; default: 300)", true)] double? ttl
        ) {
            if(document == null) {
                return Clear(id);
            }

            // fetch entry from cache
            CacheEntry result;
            bool isNew = true;
            lock(_cacheLookup) {
                _cacheLookup.TryGetValue(id, out result);
            }

            // check if we have a cached entry
            if(result != null) {
                _log.DebugFormat("cache hit for '{0}'", result.Id);
                isNew = false;
                result.ResetMemoryExpiration();
            } else {
                _log.DebugFormat("new cache item for '{0}'", id);
                result = new CacheEntry(id, ttl);
            }

            // update cache with document
            DekiScriptLiteral literal = DekiScriptLiteral.FromNativeValue(document);
            XDoc xml = new DekiScriptList().Add(literal).ToXml();
            result.Cache = xml.ToString();

            // start timer to clean-up cached result
            if(result.Cache != null) {
                XDoc infoDoc = new XDoc("cache-entry")
                    .Elem("guid", result.Guid)
                    .Elem("id", result.Id)
                    .Elem("expires", result.Expires);
                lock(result) {
                    Storage.At(CACHE_DATA, result.Guid + ".bin").PutAsync(new DreamMessage(DreamStatus.Ok, null, MimeType.BINARY, Encoding.UTF8.GetBytes(result.Cache))).Wait();
                    Storage.At(CACHE_INFO, result.Guid + ".xml").PutAsync(infoDoc).Wait();
                }
                if(isNew) {
                    lock(_cacheLookup) {
                        _cacheLookup[id] = result;
                    }

                    // this timer removes the cache entry from disk 
                    SetupCacheTimer(result);
                }
            }
            return document;
        }
 public DekiScriptExpression Visit(DekiScriptList expr, DekiScriptOptimizerState state)
 {
     return(expr);
 }