예제 #1
0
        /// <summary>
        /// Handles the process of rendering an asset.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="response">The HTTP response.</param>
        private void HandleAssetRenderRequest(HttpListenerRequest request, HttpListenerResponse response)
        {
            // Try to demand policy

            // Navigate asset
            AppletAsset navigateAsset        = null;
            var         appletManagerService = ApplicationContext.Current.GetService <IAppletManagerService>();

            String appletPath = request.Url.AbsolutePath.ToLower();

            if (!this.m_cacheApplets.TryGetValue(appletPath, out navigateAsset))
            {
                navigateAsset = appletManagerService.Applets.ResolveAsset(appletPath);

                if (navigateAsset == null)
                {
                    throw new FileNotFoundException(request.RawUrl);
                }

                lock (m_lockObject)
                {
                    if (!this.m_cacheApplets.ContainsKey(appletPath))
                    {
                        this.m_cacheApplets.Add(appletPath, navigateAsset);
                    }
                }
            }

#if DEBUG
            response.AddHeader("Cache-Control", "no-cache");
#else
            if (request.Url.ToString().EndsWith(".js") || request.Url.ToString().EndsWith(".css") ||
                request.Url.ToString().EndsWith(".png") || request.Url.ToString().EndsWith(".woff2"))
            {
                response.AddHeader("Cache-Control", "public");
                response.AddHeader("Expires", DateTime.UtcNow.AddHours(1).ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'"));
            }
            else
            {
                response.AddHeader("Cache-Control", "no-cache");
            }
#endif

            // Navigate policy?
            if (navigateAsset.Policies != null)
            {
                foreach (var policy in navigateAsset.Policies)
                {
                    new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, policy).Demand();
                }
            }

            response.ContentType = navigateAsset.MimeType;

            // Write asset
            var content = appletManagerService.Applets.RenderAssetContent(navigateAsset, CultureInfo.CurrentUICulture.TwoLetterISOLanguageName);
            response.AddHeader("Content-Encoding", "deflate");
            using (var gzs = new DeflateStream(response.OutputStream, CompressionMode.Compress))
                gzs.Write(content, 0, content.Length);
        }
        /// <summary>
        /// Resolve asset
        /// </summary>
        public object ResolveAppletAsset(AppletAsset navigateAsset)
        {
            String itmPath = System.IO.Path.Combine(
                ApplicationContext.Current.Configuration.GetSection <AppletConfigurationSection>().AppletDirectory,
                "assets",
                navigateAsset.Manifest.Info.Id,
                navigateAsset.Name);

            return(File.ReadAllBytes(itmPath));
        }
예제 #3
0
        /// <summary>
        /// Injection for HTML headers
        /// </summary>
        public List <AssetScriptReference> GetLazyScripts(AppletAsset asset)
        {
            var htmlAsset = asset.Content as AppletAssetHtml;

            if (htmlAsset == null && this.Resolver != null)
            {
                htmlAsset = this.Resolver(asset) as AppletAssetHtml;
            }

            // Insert scripts & Styles
            List <AssetScriptReference> scriptRefs = new List <AssetScriptReference>();

            if (htmlAsset == null)
            {
                return(scriptRefs);
            }

            scriptRefs.AddRange(htmlAsset.Script.Where(o => o.IsStatic == false));

            // Content - SSI
            var includes = htmlAsset.Html.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList();

            foreach (var inc in includes)
            {
                String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX
                if (assetName.EndsWith("\""))
                {
                    assetName = assetName.Substring(0, assetName.Length - 1);
                }
                if (assetName == "content")
                {
                    continue;
                }
                var includeAsset = this.ResolveAsset(assetName, asset);
                if (includeAsset != null)
                {
                    scriptRefs.AddRange(this.GetLazyScripts(includeAsset));
                }
            }

            // Re-write
            foreach (var itm in scriptRefs.Where(o => o.Reference.StartsWith("~")))
            {
                itm.Reference = String.Format("/{0}/{1}", asset.Manifest.Info.Id, itm.Reference.Substring(2));
                //itm.Value = itm.Value.Replace(APPLET_SCHEME, this.AppletBase).Replace(ASSET_SCHEME, this.AssetBase).Replace(DRAWABLE_SCHEME, this.DrawableBase);
            }
            return(scriptRefs.Distinct(new AssetScriptReferenceEqualityComparer()).ToList());
        }
        /// <summary>
        /// Resolve asset
        /// </summary>
        public object ResolveAppletAsset(AppletAsset navigateAsset)
        {
            String itmPath = System.IO.Path.Combine(
                ApplicationContext.Current.Configuration.GetSection <AppletConfigurationSection>().AppletDirectory,
                "assets",
                navigateAsset.Manifest.Info.Id,
                navigateAsset.Name);

            if (navigateAsset.MimeType == "text/javascript" ||
                navigateAsset.MimeType == "text/css" ||
                navigateAsset.MimeType == "application/json" ||
                navigateAsset.MimeType == "text/json" ||

                navigateAsset.MimeType == "text/xml")
            {
                var script = File.ReadAllText(itmPath);
                if (itmPath.Contains("santedb.js") || itmPath.Contains("santedb.min.js"))
                {
                    script += this.GetShimMethods();
                }
                return(script);
            }
            else
            {
                using (MemoryStream response = new MemoryStream())
                    using (var fs = File.OpenRead(itmPath))
                    {
                        int    br     = 8096;
                        byte[] buffer = new byte[8096];
                        while (br == 8096)
                        {
                            br = fs.Read(buffer, 0, 8096);
                            response.Write(buffer, 0, br);
                        }

                        return(response.ToArray());
                    }
            }
        }
예제 #5
0
        /// <summary>
        /// Injection for HTML headers
        /// </summary>
        private List <XElement> GetInjectionHeaders(AppletAsset asset, bool isUiContainer)
        {
            var htmlAsset = asset.Content as AppletAssetHtml;

            if (htmlAsset == null && this.Resolver != null)
            {
                htmlAsset = this.Resolver(asset) as AppletAssetHtml;
            }

            // Insert scripts & Styles
            List <XElement> headerInjection = new List <XElement>();

            if (htmlAsset == null)
            {
                return(headerInjection);
            }

            // Inject special headers
            foreach (var itm in htmlAsset.Bundle)
            {
                var bundle = this.m_referenceBundles.Find(o => o.Name == itm);
                if (bundle == null)
                {
                    throw new FileNotFoundException(String.Format("Bundle {0} not found", itm));
                }
                headerInjection.AddRange(bundle.Content.SelectMany(o => o.HeaderElement));
            }

            // All scripts
            if (isUiContainer) // IS A UI CONTAINER = ANGULAR UI REQUIRES ALL CONTROLLERS BE LOADED
            {
                return(this.ViewStateAssets.SelectMany(o => this.GetInjectionHeaders(o, false)).Distinct(new XElementEquityComparer()).ToList());
            }
            else
            {
                foreach (var itm in htmlAsset.Script)
                {
                    var incAsset = this.ResolveAsset(itm, asset);
                    if (incAsset != null)
                    {
                        headerInjection.AddRange(new ScriptBundleContent(itm).HeaderElement);
                    }
                    else
                    {
                        throw new FileNotFoundException(String.Format("Asset {0} not found", itm));
                    }
                }
            }
            foreach (var itm in htmlAsset.Style)
            {
                var incAsset = this.ResolveAsset(itm, asset);
                if (incAsset != null)
                {
                    headerInjection.AddRange(new StyleBundleContent(itm).HeaderElement);
                }
                else
                {
                    throw new FileNotFoundException(String.Format("Asset {0} not found", itm));
                }
            }

            // Content - SSI
            var includes = htmlAsset.Html.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList();

            foreach (var inc in includes)
            {
                String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX
                if (assetName.EndsWith("\""))
                {
                    assetName = assetName.Substring(0, assetName.Length - 1);
                }
                if (assetName == "content")
                {
                    continue;
                }
                var includeAsset = this.ResolveAsset(assetName, asset);
                if (includeAsset != null)
                {
                    headerInjection.AddRange(this.GetInjectionHeaders(includeAsset, isUiContainer));
                }
            }

            // Re-write
            foreach (var itm in headerInjection.OfType <XElement>().SelectMany(o => o.Attributes()).Where(o => o.Value.StartsWith("~")))
            {
                itm.Value = String.Format("/{0}/{1}", asset.Manifest.Info.Id, itm.Value.Substring(2));
                //itm.Value = itm.Value.Replace(APPLET_SCHEME, this.AppletBase).Replace(ASSET_SCHEME, this.AssetBase).Replace(DRAWABLE_SCHEME, this.DrawableBase);
            }
            return(headerInjection.Distinct(new XElementEquityComparer()).ToList());
        }
예제 #6
0
        /// <summary>
        /// Render asset content
        /// </summary>
        public byte[] RenderAssetContent(AppletAsset asset, string preProcessLocalization = null)
        {
            // First, is there an object already
            byte[] cacheObject = null;
            string assetPath   = String.Format("{0}?lang={1}", asset.ToString(), preProcessLocalization);

            if (this.CachePages && s_cache.TryGetValue(assetPath, out cacheObject))
            {
                return(cacheObject);
            }

            // Resolve content
            var content = asset.Content;

            if (content == null && this.Resolver != null)
            {
                content = this.Resolver(asset);
            }

            if (content is String) // Content is a string
            {
                return(Encoding.UTF8.GetBytes(content as String));
            }
            else if (content is byte[]) // Content is a binary asset
            {
                return(content as byte[]);
            }
            else if (content is XElement) // Content is XML
            {
                using (MemoryStream ms = new MemoryStream())
                    using (XmlWriter xw = XmlWriter.Create(ms))
                    {
                        (content as XElement).WriteTo(xw);
                        xw.Flush();
                        ms.Flush();
                        return(ms.ToArray());
                    }
            }
            else if (content is AppletAssetHtml) // Content is HTML
            {
                // Is the content HTML?
                var sourceAsset = content as AppletAssetHtml;
                var htmlAsset   = new AppletAssetHtml()
                {
                    Html   = new XElement(sourceAsset.Html),
                    Layout = sourceAsset.Layout,
                    Script = new List <String>(sourceAsset.Script),
                    Titles = new List <LocaleString>(sourceAsset.Titles),
                    Style  = new List <string>(sourceAsset.Style)
                };
                XElement htmlContent = null;

                if (htmlAsset.Static)
                {
                    htmlContent = htmlAsset.Html as XElement;
                }
                else
                {
                    // Type of tag to render basic content
                    switch (htmlAsset.Html.Name.LocalName)
                    {
                    case "html":     // The content is a complete HTML page
                    {
                        htmlContent = htmlAsset.Html as XElement;
                        var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view"));

                        // STRIP - OPENIZJS references
                        var xel  = htmlContent.Descendants().OfType <XElement>().Where(o => o.Name == xs_xhtml + "script" && o.Attribute("src")?.Value.Contains("openiz") == true).ToArray();
                        var head = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head");
                        if (head == null)
                        {
                            head = new XElement(xs_xhtml + "head");
                            htmlContent.Add(head);
                        }

                        head.Add(headerInjection.Where(o => !head.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href"))))));

                        //                            head.Add(headerInjection);
                        break;
                    }

                    case "body":     // The content is an HTML Body element, we must inject the HTML header
                    {
                        htmlContent = htmlAsset.Html as XElement;

                        // Inject special headers
                        var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view"));

                        // Render the bundles
                        var bodyElement = htmlAsset.Html as XElement;

                        htmlContent = new XElement(xs_xhtml + "html", new XAttribute("ng-app", asset.Name), new XElement(xs_xhtml + "head", headerInjection), bodyElement);
                    }
                    break;

                    default:
                    {
                        if (String.IsNullOrEmpty(htmlAsset.Layout))
                        {
                            htmlContent = htmlAsset.Html as XElement;
                        }
                        else
                        {
                            // Get the layout
                            var layoutAsset = this.ResolveAsset(htmlAsset.Layout, asset);
                            if (layoutAsset == null)
                            {
                                throw new FileNotFoundException(String.Format("Layout asset {0} not found", htmlAsset.Layout));
                            }

                            using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(layoutAsset, preProcessLocalization)))
                                htmlContent = XDocument.Load(ms).FirstNode as XElement;


                            // Find the <!--#include virtual="content" --> tag
                            var contentNode = htmlContent.DescendantNodes().OfType <XComment>().SingleOrDefault(o => o.Value.Trim() == "#include virtual=\"content\"");
                            if (contentNode != null)
                            {
                                contentNode.AddAfterSelf(htmlAsset.Html as XElement);
                                contentNode.Remove();
                            }

                            // Injection headers
                            var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view"));
                            var headElement     = (htmlContent.Element(xs_xhtml + "head") as XElement);
                            headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href"))))));
                        }
                    }
                    break;
                    } // switch

                    // Process data bindings
                    var dataBindings = htmlContent.DescendantNodes().OfType <XElement>().Where(o => o.Name.LocalName == "select" && o.Attributes().Any(a => a.Name.Namespace == xs_binding));
                    foreach (var db in dataBindings)
                    {
                        // Get the databinding data
                        XAttribute source          = db.Attributes(xs_binding + "source").FirstOrDefault(),
                                 filter            = db.Attributes(xs_binding + "filter").FirstOrDefault(),
                                 key               = db.Attributes(xs_binding + "key").FirstOrDefault(),
                                 value             = db.Attributes(xs_binding + "value").FirstOrDefault(),
                                 orderByDescending = db.Attributes(xs_binding + "orderByDescending").FirstOrDefault(),
                                 orderBy           = db.Attributes(xs_binding + "orderBy").FirstOrDefault();

                        var locale        = preProcessLocalization;
                        int i             = 0;
                        var valueSelector = value?.Value;
                        while (i++ < 2)
                        {
                            try
                            {
                                // Fall back to english?
                                if (value != null)
                                {
                                    valueSelector = value.Value.Replace("{{ locale }}", locale);
                                }

                                if (source == null || filter == null)
                                {
                                    continue;
                                }

                                // First we want to build the filter
                                Type imsiType = typeof(Patient).GetTypeInfo().Assembly.ExportedTypes.FirstOrDefault(o => o.GetTypeInfo().GetCustomAttribute <XmlRootAttribute>()?.ElementName == source.Value);
                                if (imsiType == null)
                                {
                                    continue;
                                }

                                var expressionBuilderMethod = typeof(QueryExpressionParser).GetGenericMethod(nameof(QueryExpressionParser.BuildLinqExpression), new Type[] { imsiType }, new Type[] { typeof(NameValueCollection) });
                                var filterList   = NameValueCollection.ParseQueryString(filter.Value);
                                var expr         = expressionBuilderMethod.Invoke(null, new object[] { filterList });
                                var filterMethod = typeof(IEntitySourceProvider).GetGenericMethod("Query", new Type[] { imsiType }, new Type[] { expr.GetType() });
                                var dataSource   = (filterMethod.Invoke(EntitySource.Current.Provider, new object[] { expr }));

                                // Sort expression
                                if (orderBy != null || orderByDescending != null)
                                {
                                    var orderProperty             = imsiType.GetRuntimeProperties().FirstOrDefault(o => o.GetCustomAttribute <JsonPropertyAttribute>()?.PropertyName == (orderBy ?? orderByDescending).Value);
                                    ParameterExpression orderExpr = Expression.Parameter(dataSource.GetType());
                                    var orderBody = orderExpr.Sort(orderProperty.Name, orderBy == null ? SortOrderType.OrderByDescending : SortOrderType.OrderBy);
                                    dataSource = Expression.Lambda(orderBody, orderExpr).Compile().DynamicInvoke(dataSource);
                                }

                                // Render expression
                                Delegate            keyExpression = null, valueExpression = null, dataExpression = null;
                                ParameterExpression parameter = Expression.Parameter(imsiType);
                                if (key == null)
                                {
                                    keyExpression = Expression.Lambda(Expression.MakeMemberAccess(parameter, imsiType.GetRuntimeProperty(nameof(IIdentifiedEntity.Key))), parameter).Compile();
                                }
                                else
                                {
                                    var rawExpr = new BindingExpressionVisitor().RewriteLambda(expressionBuilderMethod.Invoke(null, new object[] { NameValueCollection.ParseQueryString(key.Value + "=RemoveMe") }) as LambdaExpression);
                                    keyExpression = Expression.Lambda(new BindingExpressionVisitor().Visit(rawExpr.Body), rawExpr.Parameters).Compile();
                                }
                                if (value == null)
                                {
                                    valueExpression = Expression.Lambda(Expression.Call(parameter, imsiType.GetRuntimeMethod("ToString", new Type[] { })), parameter).Compile();
                                }
                                else
                                {
                                    var rawExpr = new BindingExpressionVisitor().RewriteLambda(expressionBuilderMethod.Invoke(null, new object[] { NameValueCollection.ParseQueryString(valueSelector + "=RemoveMe") }) as LambdaExpression);
                                    valueExpression = Expression.Lambda(rawExpr.Body, rawExpr.Parameters).Compile();
                                }

                                // Creation of the options
                                foreach (var itm in dataSource as IEnumerable)
                                {
                                    var optAtt     = new XElement(xs_xhtml + "option");
                                    var keyValue   = keyExpression.DynamicInvoke(itm);
                                    var valueValue = valueExpression.DynamicInvoke(itm)?.ToString();
                                    if (String.IsNullOrEmpty(valueValue))
                                    {
                                        continue;
                                    }
                                    optAtt.Add(new XAttribute("value", keyValue), new XText(valueValue));

                                    foreach (var dataBinding in db.Attributes().Where(c => c.Name.ToString().StartsWith((xs_binding + "data-").ToString())))
                                    {
                                        if (dataBinding != null)
                                        {
                                            dataExpression = Expression.Lambda(Expression.MakeMemberAccess(parameter, imsiType.GetRuntimeProperty(dataBinding.Value)), parameter).Compile();
                                            var dataValue = dataExpression?.DynamicInvoke(itm)?.ToString();

                                            if (string.IsNullOrEmpty(dataValue))
                                            {
                                                continue;
                                            }

                                            optAtt.Add(new XAttribute(dataBinding.Name.LocalName, dataValue));
                                        }
                                    }

                                    db.Add(optAtt);
                                }
                                break;
                            }
                            catch
                            {
                                if (locale == "en")
                                {
                                    throw;     // We can't fallback
                                }
                                locale = "en"; // fallback to english
                            }
                        }
                    }


                    // Now process SSI directives - <!--#include virtual="XXXXXXX" -->
                    var includes = htmlContent.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList();
                    foreach (var inc in includes)
                    {
                        String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX
                        if (assetName.EndsWith("\""))
                        {
                            assetName = assetName.Substring(0, assetName.Length - 1);
                        }
                        if (assetName == "content")
                        {
                            continue;
                        }
                        var includeAsset = this.ResolveAsset(assetName, asset);
                        if (includeAsset == null)
                        {
                            inc.AddAfterSelf(new XElement(xs_xhtml + "strong", new XText(String.Format("{0} NOT FOUND", assetName))));
                            inc.Remove();
                        }
                        else
                        {
                            using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(includeAsset, preProcessLocalization)))
                            {
                                try
                                {
                                    var xel = XDocument.Load(ms).Elements().First() as XElement;
                                    if (xel.Name == xs_xhtml + "html")
                                    {
                                        inc.AddAfterSelf(xel.Element(xs_xhtml + "body").Elements());
                                    }
                                    else
                                    {
                                        //var headerInjection = this.GetInjectionHeaders(includeAsset);

                                        //var headElement = htmlContent.Element(xs_xhtml + "head");
                                        //headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href"))))));

                                        inc.AddAfterSelf(xel);
                                    }
                                    inc.Remove();
                                }
                                catch (Exception e)
                                {
                                    throw new XmlException($"Error in Asset: {includeAsset}", e);
                                }
                            }
                        }
                    }

                    // Re-write
                    foreach (var itm in htmlContent.DescendantNodes().OfType <XElement>().SelectMany(o => o.Attributes()).Where(o => o.Value.StartsWith("~")))
                    {
                        itm.Value = String.Format("/{0}/{1}", asset.Manifest.Info.Id, itm.Value.Substring(2));
                        //itm.Value = itm.Value.Replace(APPLET_SCHEME, this.AppletBase).Replace(ASSET_SCHEME, this.AssetBase).Replace(DRAWABLE_SCHEME, this.DrawableBase);
                    }

                    // Render Title
                    var headTitle = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head");
                    var title     = htmlAsset.GetTitle(preProcessLocalization);
                    if (headTitle != null && !String.IsNullOrEmpty(title))
                    {
                        headTitle.Add(new XElement(xs_xhtml + "title", new XText(title)));
                    }
                }

                // Render out the content
                using (StringWriter sw = new StringWriter())

                    using (XmlWriter xw = XmlWriter.Create(sw, new XmlWriterSettings()
                    {
                        OmitXmlDeclaration = true
                    }))
                    {
                        htmlContent.WriteTo(xw);
                        xw.Flush();

                        String retVal = sw.ToString();
                        if (!String.IsNullOrEmpty(preProcessLocalization))
                        {
                            var assetString = this.GetStrings(preProcessLocalization);
                            retVal = this.m_localizationRegex.Replace(retVal, (m) => assetString.FirstOrDefault(o => o.Key == m.Groups[1].Value).Value ?? m.Groups[1].Value);
                        }

                        var byteData = Encoding.UTF8.GetBytes(retVal);
                        // Add to cache
                        lock (s_syncLock)
                            if (!s_cache.ContainsKey(assetPath))
                            {
                                s_cache.Add(assetPath, byteData);
                            }

                        return(byteData);
                    }
            }
            else
            {
                return(null);
            }
        }
예제 #7
0
        /// <summary>
        /// Resolve the asset
        /// </summary>
        public AppletAsset ResolveAsset(String assetPath, AppletAsset relative = null, String language = null)
        {
            if (assetPath == null)
            {
                return(null);
            }

            // Is the asset start with ~
            if (assetPath.StartsWith("~"))
            {
                assetPath = "/" + relative.Manifest.Info.Id + assetPath.Substring(1);
            }

            Uri path = null;

            if (!Uri.TryCreate(assetPath, UriKind.RelativeOrAbsolute, out path))
            {
                return(null);
            }
            else
            {
                AppletManifest resolvedManifest = null;
                String         pathLeft         = path.IsAbsoluteUri ? path.AbsolutePath.Substring(1) :
                                                  path.OriginalString.StartsWith("/") ? path.OriginalString.Substring(1) : path.OriginalString;
                // Is the host specified?
                if (path.IsAbsoluteUri && !String.IsNullOrEmpty(path.Host))
                {
                    resolvedManifest = this.FirstOrDefault(o => o.Info.Id == path.Host);
                }
                else
                {
                    // We can accept /org.x.y.z or /org/x/y/z
                    StringBuilder applId = new StringBuilder();
                    while (pathLeft.Contains("/"))
                    {
                        applId.AppendFormat("{0}.", pathLeft.Substring(0, pathLeft.IndexOf("/")));
                        pathLeft         = pathLeft.Substring(pathLeft.IndexOf("/") + 1);
                        resolvedManifest = this.FirstOrDefault(o => o.Info.Id == applId.ToString(0, applId.Length - 1));
                        if (resolvedManifest != null)
                        {
                            break;
                        }
                    }
                }
                if (resolvedManifest == null)
                {
                    resolvedManifest = relative?.Manifest;
                }

                // Is there a resource?
                if (resolvedManifest != null)
                {
                    if (pathLeft.EndsWith("/") || String.IsNullOrEmpty(pathLeft))
                    {
                        pathLeft += "index.html";
                    }
                    pathLeft = pathLeft.ToLower(); // case insensitive
                    return(resolvedManifest.Assets.FirstOrDefault(o => o.Name == pathLeft));
                }


                return(null);
            }
        }
예제 #8
0
        /// <summary>
        /// Get the asset
        /// </summary>
        public Stream Get()
        {
            this.ThrowIfNotRunning();

            try
            {
                if (!RestOperationContext.Current.Data.TryGetValue("lang", out object lang))
                {
                    lang = AuthenticationContext.Current.Principal.GetClaimValue(SanteDBClaimTypes.Language) ?? CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
                }
                else if (lang is String[] ls)
                {
                    lang = ls[0];
                }
                if (!RestOperationContext.Current.Data.TryGetValue(AgsAuthorizationServiceBehavior.SessionPropertyName, out object sessionId))
                {
                    sessionId = AuthenticationContext.Current.Principal.GetClaimValue(SanteDBClaimTypes.SanteDBSessionIdClaim);
                }
                else if (sessionId is ISession ses)
                {
                    sessionId = BitConverter.ToString(ses.Id);
                }

                var etag = $"{ApplicationContext.Current.ExecutionUuid}.{lang}.{sessionId}";

                if (RestOperationContext.Current.IncomingRequest.Headers["If-None-Match"] == etag)
                {
                    RestOperationContext.Current.OutgoingResponse.StatusCode = 304; /// not modified
                    return(null);
                }

                // Navigate asset
                AppletAsset navigateAsset        = null;
                var         appletManagerService = ApplicationContext.Current.GetService <IAppletManagerService>();

                String appletPath = RestOperationContext.Current.IncomingRequest.Url.AbsolutePath.ToLower();
                if (!m_cacheApplets.TryGetValue(appletPath, out navigateAsset))
                {
                    if (appletPath == "/") // startup asset
                    {
                        navigateAsset = appletManagerService.Applets.DefaultApplet?.Assets.FirstOrDefault(o => o.Name == "index.html");
                    }
                    else
                    {
                        navigateAsset = appletManagerService.Applets.ResolveAsset(appletPath);
                    }

                    if (navigateAsset == null)
                    {
                        throw new FileNotFoundException(appletPath);
                    }

                    lock (m_lockObject)
                    {
                        if (!m_cacheApplets.ContainsKey(appletPath) && appletManagerService.Applets.CachePages)
                        {
                            m_cacheApplets.Add(appletPath, navigateAsset);
                        }
                    }
                }

                // Navigate policy?
                if (navigateAsset.Policies != null)
                {
                    foreach (var policy in navigateAsset.Policies)
                    {
                        new PolicyPermission(System.Security.Permissions.PermissionState.Unrestricted, policy).Demand();
                    }
                }


                RestOperationContext.Current.OutgoingResponse.AddHeader("ETag", etag);
                RestOperationContext.Current.OutgoingResponse.ContentType = navigateAsset.MimeType;

                // Write asset
                var content = appletManagerService.Applets.RenderAssetContent(navigateAsset, lang?.ToString(), bindingParameters: new Dictionary <String, String>()
                {
                    { "csp_nonce", RestOperationContext.Current.ServiceEndpoint.Behaviors.OfType <SecurityPolicyHeadersBehavior>().FirstOrDefault()?.Nonce },
#if DEBUG
                    { "env_type", "debug" },
#else
                    { "env_type", "release" },
#endif
                    { "host_type", ApplicationServiceContext.Current.HostType.ToString() }
                });
                return(new MemoryStream(content));
            }
            catch (RemoteOperationException ex) // The page demanded something upstream but the upstream service isn't responding
            {
                throw new DomainStateException($"The remote server is currently unavailable", ex);
            }
        }
예제 #9
0
        /// <summary>
        /// Render asset content
        /// </summary>
        public byte[] RenderAssetContent(AppletAsset asset, string preProcessLocalization = null, bool staticScriptRefs = true, bool allowCache = true, IDictionary <String, String> bindingParameters = null)
        {
            // TODO: This method needs to be cleaned up since it exists from the old/early OpenIZ days
            // First, is there an object already
            byte[] cacheObject = null;
            string assetPath   = String.Format("{0}?lang={1}", asset.ToString(), preProcessLocalization);

            var cacheKey = $"{assetPath};{String.Join(";", bindingParameters?.Select(o => $"{o.Key}={o.Value}") ?? new string[0] { })}";

            if (allowCache && this.CachePages && s_cache.TryGetValue(cacheKey, out cacheObject))
            {
                return(cacheObject);
            }

            // Resolve content
            var content = asset.Content;

            if (content == null && this.Resolver != null)
            {
                content = this.Resolver(asset);
            }

            if (content is String) // Content is a string
            {
                // Inject CSP
                if (asset.MimeType == "text/javascript" || asset.MimeType == "application/json")
                {
                    var retVal = content as String;
                    if (bindingParameters != null)
                    {
                        retVal = this.m_bindingRegex.Replace(retVal, (m) => bindingParameters.TryGetValue(m.Groups[1].Value, out string v) ? v : m.ToString());
                    }
                    cacheObject = Encoding.UTF8.GetBytes(retVal);
                    if (allowCache)
                    {
                        s_cache.TryAdd(cacheKey, cacheObject);
                    }
                    return(cacheObject);
                }
                else
                {
                    return(Encoding.UTF8.GetBytes(content as String));
                }
            }
            else if (content is byte[]) // Content is a binary asset
            {
                // is the content compressed?
                if (Encoding.UTF8.GetString(content as byte[], 0, 4) == "LZIP")
                {
                    using (var ms = new MemoryStream(content as byte[]))
                        using (var ls = new SharpCompress.Compressors.LZMA.LZipStream(new NonDisposingStream(ms), SharpCompress.Compressors.CompressionMode.Decompress))
                            using (var oms = new MemoryStream())
                            {
                                byte[] buffer = new byte[2048];
                                int    br     = 1;
                                while (br > 0)
                                {
                                    br = ls.Read(buffer, 0, 2048);
                                    oms.Write(buffer, 0, br);
                                }

                                content = oms.ToArray();
                                if (allowCache)
                                {
                                    s_cache.TryAdd(cacheKey, content as byte[]);
                                }
                                return(content as byte[]);
                            }
                }
                else
                {
                    return(content as byte[]);
                }
            }
            else if (content is XElement) // Content is XML
            {
                using (MemoryStream ms = new MemoryStream())
                    using (XmlWriter xw = XmlWriter.Create(ms))
                    {
                        (content as XElement).WriteTo(xw);
                        xw.Flush();
                        ms.Flush();
                        return(ms.ToArray());
                    }
            }
            else if (content is AppletAssetHtml) // Content is HTML
            {
                // Is the content HTML?
                var sourceAsset = content as AppletAssetHtml;
                var htmlAsset   = new AppletAssetHtml()
                {
                    Html   = new XElement(sourceAsset.Html),
                    Layout = sourceAsset.Layout,
                    Script = new List <AssetScriptReference>(sourceAsset.Script),
                    Titles = new List <LocaleString>(sourceAsset.Titles),
                    Style  = new List <string>(sourceAsset.Style)
                };
                XElement htmlContent = null;

                if (htmlAsset.Static)
                {
                    htmlContent = htmlAsset.Html as XElement;
                }
                else
                {
                    // Type of tag to render basic content
                    switch (htmlAsset.Html.Name.LocalName)
                    {
                    case "html":     // The content is a complete HTML page
                    {
                        htmlContent = htmlAsset.Html as XElement;
                        var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view"));

                        // STRIP - SanteDBJS references
                        var xel  = htmlContent.Descendants().OfType <XElement>().Where(o => o.Name == xs_xhtml + "script" && o.Attribute("src")?.Value.Contains("SanteDB") == true).ToArray();
                        var head = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head");
                        if (head == null)
                        {
                            head = new XElement(xs_xhtml + "head");
                            htmlContent.Add(head);
                        }

                        head.Add(headerInjection.Where(o => !head.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href"))))));

                        // Inject any business rules as static refs
                        var body = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "body");
                        if (body != null)
                        {
                            body.Add(
                                this.SelectMany(o => o.Assets.Where(a => a.Name.StartsWith("rules/"))).Select(o => new XElement(xs_xhtml + "script", new XAttribute("src", $"/{o.Manifest.Info.Id}/{o.Name}"), new XAttribute("type", "text/javascript"), new XAttribute("nonce", bindingParameters.TryGetValue("csp_nonce", out string nonce) ? nonce : ""), new XText("// Script reference")))
                                );
                        }
                        //                            head.Add(headerInjection);
                        break;
                    }

                    case "body":     // The content is an HTML Body element, we must inject the HTML header
                    {
                        htmlContent = htmlAsset.Html as XElement;

                        // Inject special headers
                        var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view"));

                        // Render the bundles
                        var bodyElement = htmlAsset.Html as XElement;

                        htmlContent = new XElement(xs_xhtml + "html", new XAttribute("ng-app", asset.Name), new XElement(xs_xhtml + "head", headerInjection), bodyElement);
                    }
                    break;

                    default:
                    {
                        if (String.IsNullOrEmpty(htmlAsset.Layout))
                        {
                            htmlContent = htmlAsset.Html as XElement;
                        }
                        else
                        {
                            // Get the layout
                            var layoutAsset = this.ResolveAsset(htmlAsset.Layout, relativeAsset: asset);
                            if (layoutAsset == null)
                            {
                                throw new FileNotFoundException(String.Format("Layout asset {0} not found", htmlAsset.Layout));
                            }

                            using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(layoutAsset, preProcessLocalization, bindingParameters: bindingParameters)))
                                htmlContent = XDocument.Load(ms).FirstNode as XElement;


                            // Find the <!--#include virtual="content" --> tag
                            var contentNode = htmlContent.DescendantNodes().OfType <XComment>().SingleOrDefault(o => o.Value.Trim() == "#include virtual=\"content\"");
                            if (contentNode != null)
                            {
                                contentNode.AddAfterSelf(htmlAsset.Html as XElement);
                                contentNode.Remove();
                            }

                            // Injection headers
                            var headerInjection = this.GetInjectionHeaders(asset, htmlContent.DescendantNodes().OfType <XElement>().Any(o => o.Name == xs_xhtml + "ui-view"));
                            var headElement     = (htmlContent.Element(xs_xhtml + "head") as XElement);
                            headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href"))))));
                        }
                    }
                    break;
                    } // switch


                    // Now process SSI directives - <!--#include virtual="XXXXXXX" -->
                    var includes = htmlContent.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList();
                    foreach (var inc in includes)
                    {
                        String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX
                        if (assetName.EndsWith("\""))
                        {
                            assetName = assetName.Substring(0, assetName.Length - 1);
                        }
                        if (assetName == "content")
                        {
                            continue;
                        }
                        var includeAsset = this.ResolveAsset(assetName, relativeAsset: asset);
                        if (includeAsset == null)
                        {
                            inc.AddAfterSelf(new XElement(xs_xhtml + "strong", new XText(String.Format("{0} NOT FOUND", assetName))));
                            inc.Remove();
                        }
                        else
                        {
                            using (MemoryStream ms = new MemoryStream(this.RenderAssetContent(includeAsset, preProcessLocalization, bindingParameters: bindingParameters)))
                            {
                                try
                                {
                                    var xel = XDocument.Load(ms).Elements().First() as XElement;
                                    if (xel.Name == xs_xhtml + "html")
                                    {
                                        inc.AddAfterSelf(xel.Element(xs_xhtml + "body").Elements());
                                    }
                                    else
                                    {
                                        //var headerInjection = this.GetInjectionHeaders(includeAsset);

                                        //var headElement = htmlContent.Element(xs_xhtml + "head");
                                        //headElement?.Add(headerInjection.Where(o => !headElement.Elements(o.Name).Any(e => (e.Attributes("src") != null && (e.Attributes("src") == o.Attributes("src"))) || (e.Attributes("href") != null && (e.Attributes("href") == o.Attributes("href"))))));

                                        inc.AddAfterSelf(xel);
                                    }
                                    inc.Remove();
                                }
                                catch (Exception e)
                                {
                                    throw new XmlException($"Error in Asset: {includeAsset}", e);
                                }
                            }
                        }
                    }

                    // Re-write
                    foreach (var itm in htmlContent.DescendantNodes().OfType <XElement>().SelectMany(o => o.Attributes()).Where(o => o.Value.StartsWith("~")))
                    {
                        itm.Value = String.Format("/{0}/{1}", asset.Manifest.Info.Id, itm.Value.Substring(2));
                        //itm.Value = itm.Value.Replace(APPLET_SCHEME, this.AppletBase).Replace(ASSET_SCHEME, this.AssetBase).Replace(DRAWABLE_SCHEME, this.DrawableBase);
                    }

                    // Render Title
                    var headTitle = htmlContent.DescendantNodes().OfType <XElement>().FirstOrDefault(o => o.Name == xs_xhtml + "head");
                    var title     = htmlAsset.GetTitle(preProcessLocalization);
                    if (headTitle != null && !String.IsNullOrEmpty(title))
                    {
                        headTitle.Add(new XElement(xs_xhtml + "title", new XText(title)));
                    }
                }

                // Render out the content
                using (StringWriter sw = new StringWriter())
                    using (XmlWriter xw = XmlWriter.Create(sw, new XmlWriterSettings()
                    {
                        OmitXmlDeclaration = true
                    }))
                    {
                        htmlContent.WriteTo(xw);
                        xw.Flush();

                        String retVal = sw.ToString();
                        if (!String.IsNullOrEmpty(preProcessLocalization))
                        {
                            var assetString = ApplicationServiceContext.Current.GetService <ILocalizationService>().GetStrings(preProcessLocalization);
                            retVal = this.m_localizationRegex.Replace(retVal, (m) => assetString.FirstOrDefault(o => o.Key == m.Groups[1].Value).Value ?? m.Groups[1].Value);
                        }

                        // Binding objects
                        if (bindingParameters != null)
                        {
                            retVal = this.m_bindingRegex.Replace(retVal, (m) => bindingParameters.TryGetValue(m.Groups[1].Value, out string v) ? v : m.ToString());
                        }
                        var byteData = Encoding.UTF8.GetBytes(retVal);
                        // Add to cache
                        if (allowCache)
                        {
                            s_cache.TryAdd(cacheKey, byteData);
                        }

                        return(byteData);
                    }
            }
            else if (content is AppletAssetVirtual virtualContent) // Virtual asset
            {
                if (!s_cache.TryGetValue(assetPath, out byte[] data))
예제 #10
0
        /// <summary>
        /// Resolve the asset
        /// </summary>
        public AppletAsset ResolveAsset(String assetPath, AppletManifest relativeManifest = null, AppletAsset relativeAsset = null)
        {
            if (assetPath == null)
            {
                return(null);
            }

            // Manifest to search for asset
            AppletManifest searchManifest = null;

            // Is the asset start with ~
            if (assetPath.StartsWith("/"))
            { // Absolute
                var pathRegex = new Regex(@"^\/(.*?)\/(.*)$");
                var pathData  = pathRegex.Match(assetPath);
                if (pathData.Success)
                {
                    searchManifest = this.FirstOrDefault(o => o.Info.Id == pathData.Groups[1].Value);
                    assetPath      = pathData.Groups[2].Value;
                }
                else
                {
                    throw new InvalidCastException("Absolute references must be in format /id.to.the.applet/path/to/the/file");
                }
            }
            else if (assetPath.StartsWith("~"))
            {
                assetPath      = assetPath.Substring(2); // it is in current path
                searchManifest = relativeManifest ?? relativeAsset?.Manifest;
                if (searchManifest == null)
                {
                    throw new InvalidOperationException("Cannot search relative manifest with no reference/related asset");
                }
            }
            else
            {
                searchManifest = relativeManifest ?? relativeAsset?.Manifest;
            }

            if (assetPath.EndsWith("/") || String.IsNullOrEmpty(assetPath))
            {
                assetPath += "index.html";
            }
            assetPath = assetPath.ToLower(); // case insensitive
            return(searchManifest?.Assets.FirstOrDefault(o => o.Name == assetPath));
        }
예제 #11
0
        /// <summary>
        /// Get applet asset
        /// </summary>
        public object ResolveAppletAsset(AppletAsset navigateAsset)
        {
            String itmPath = System.IO.Path.Combine(
                this.m_appletBaseDir[navigateAsset.Manifest],
                navigateAsset.Name);

            if (navigateAsset.MimeType == "text/html")
            {
                XElement xe = XElement.Load(itmPath);

                // Now we have to iterate throuh and add the asset\
                AppletAssetHtml htmlAsset = null;

                if (xe.Elements().OfType <XElement>().Any(o => o.Name == xs_openiz + "widget"))
                {
                    var widgetEle = xe.Elements().OfType <XElement>().FirstOrDefault(o => o.Name == xs_openiz + "widget");
                    htmlAsset = new AppletWidget()
                    {
                        Icon        = widgetEle.Element(xs_openiz + "icon")?.Value,
                        Type        = (AppletWidgetType)Enum.Parse(typeof(AppletWidgetType), widgetEle.Attribute("type")?.Value),
                        Scope       = (AppletWidgetScope)Enum.Parse(typeof(AppletWidgetScope), widgetEle.Attribute("scope")?.Value),
                        Description = widgetEle.Elements().Where(o => o.Name == xs_openiz + "description").Select(o => new LocaleString()
                        {
                            Value = o.Value, Language = o.Attribute("lang")?.Value
                        }).ToList(),
                        Name       = widgetEle.Attribute("name")?.Value,
                        Controller = widgetEle.Element(xs_openiz + "controller")?.Value,
                    };
                }
                else
                {
                    htmlAsset = new AppletAssetHtml();
                    // View state data
                    htmlAsset.ViewState = xe.Elements().OfType <XElement>().Where(o => o.Name == xs_openiz + "state").Select(o => new AppletViewState()
                    {
                        Name       = o.Attribute("name")?.Value,
                        Route      = o.Elements().OfType <XElement>().FirstOrDefault(r => r.Name == xs_openiz + "url" || r.Name == xs_openiz + "route")?.Value,
                        IsAbstract = Boolean.Parse(o.Attribute("abstract")?.Value ?? "False"),
                        View       = o.Elements().OfType <XElement>().Where(v => v.Name == xs_openiz + "view")?.Select(v => new AppletView()
                        {
                            Name  = v.Attribute("name")?.Value,
                            Title = v.Elements().OfType <XElement>().Where(t => t.Name == xs_openiz + "title")?.Select(t => new LocaleString()
                            {
                                Language = t.Attribute("lang")?.Value,
                                Value    = t?.Value
                            }).ToList(),
                            Controller = v.Element(xs_openiz + "controller")?.Value
                        }).ToList()
                    }).FirstOrDefault();
                    htmlAsset.Layout = ResolveName(xe.Attribute(xs_openiz + "layout")?.Value);
                    htmlAsset.Static = xe.Attribute(xs_openiz + "static")?.Value == "true";
                }

                htmlAsset.Titles = new List <LocaleString>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "title").Select(o => new LocaleString()
                {
                    Language = o.Attribute("lang")?.Value, Value = o.Value
                }));
                htmlAsset.Bundle = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "bundle").Select(o => ResolveName(o.Value)));
                htmlAsset.Script = new List <AssetScriptReference>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "script").Select(o => new AssetScriptReference()
                {
                    Reference = ResolveName(o.Value),
                    IsStatic  = Boolean.Parse(o.Attribute("static")?.Value ?? "true")
                }));
                htmlAsset.Style = new List <string>(xe.Descendants().OfType <XElement>().Where(o => o.Name == xs_openiz + "style").Select(o => ResolveName(o.Value)));

                var demand = xe.DescendantNodes().OfType <XElement>().Where(o => o.Name == xs_openiz + "demand").Select(o => o.Value).ToList();

                var includes = xe.DescendantNodes().OfType <XComment>().Where(o => o?.Value?.Trim().StartsWith("#include virtual=\"") == true).ToList();
                foreach (var inc in includes)
                {
                    String assetName = inc.Value.Trim().Substring(18); // HACK: Should be a REGEX
                    if (assetName.EndsWith("\""))
                    {
                        assetName = assetName.Substring(0, assetName.Length - 1);
                    }
                    if (assetName == "content")
                    {
                        continue;
                    }
                    var includeAsset = ResolveName(assetName);
                    inc.AddAfterSelf(new XComment(String.Format("#include virtual=\"{0}\"", includeAsset)));
                    inc.Remove();
                }

                var xel = xe.Descendants().OfType <XElement>().Where(o => o.Name.Namespace == xs_openiz).ToList();
                if (xel != null)
                {
                    foreach (var x in xel)
                    {
                        x.Remove();
                    }
                }
                htmlAsset.Html = xe;
                return(htmlAsset);
            }
            else if (navigateAsset.MimeType == "text/javascript" ||
                     navigateAsset.MimeType == "text/css" ||
                     navigateAsset.MimeType == "application/json" ||
                     navigateAsset.MimeType == "text/xml")
            {
                var script = File.ReadAllText(itmPath);
                if (itmPath.Contains("openiz.js") || itmPath.Contains("openiz.min.js"))
                {
                    script += this.GetShimMethods();
                }
                return(script);
            }
            else
            {
                return(File.ReadAllBytes(itmPath));
            }
        }