/// <summary>
        /// Writes a given path to the stream
        /// </summary>
        /// <param name="type"></param>
        /// <param name="path">The path could be a local url or an absolute url</param>
        /// <param name="context"></param>
        /// <param name="sw"></param>
        /// <returns>If successful returns a CompositeFileDefinition, otherwise returns null</returns>
        public CompositeFileDefinition WritePathToStream(ClientDependencyType type, string path, HttpContextBase context, StreamWriter sw)
        {
            CompositeFileDefinition def = null;

            if (!string.IsNullOrEmpty(path))
            {
                try
                {
                    var fi = new FileInfo(context.Server.MapPath(path));

                    //all config based extensions and all extensions registered by file writers
                    var fileBasedExtensions = ClientDependencySettings.Instance.FileBasedDependencyExtensionList
                                              .Union(FileWriters.GetRegisteredExtensions());

                    if (fileBasedExtensions.Contains(fi.Extension.ToUpper()))
                    {
                        //if the file doesn't exist, then we'll assume it is a URI external request
                        def = !fi.Exists
                            ? WriteFileToStream(sw, path, type, context)      //external request
                            : WriteFileToStream(sw, fi, type, path, context); //internal request
                    }
                    else
                    {
                        //if it's not a file based dependency, try to get the request output.
                        def = WriteFileToStream(sw, path, type, context);
                    }
                }
                catch (Exception ex)
                {
                    if (ex is NotSupportedException ||
                        ex is ArgumentException ||
                        ex is HttpException)
                    {
                        //could not parse the string into a fileinfo or couldn't mappath, so we assume it is a URI
                        def = WriteFileToStream(sw, path, type, context);
                    }
                    else
                    {
                        //if this fails, log the exception, but continue
                        ClientDependencySettings.Instance.Logger.Error(string.Format("Could not load file contents from {0}. EXCEPTION: {1}", path, ex.Message), ex);
                    }
                }
            }

            if (type == ClientDependencyType.Javascript)
            {
                sw.Write(";;;"); //write semicolons in case the js isn't formatted correctly. This also helps for debugging.
            }

            return(def);
        }
        /// <summary>
        /// Writes a given path to the stream
        /// </summary>
        /// <param name="type"></param>
        /// <param name="path">The path could be a local url or an absolute url</param>
        /// <param name="context"></param>
        /// <param name="sw"></param>
        /// <returns>If successful returns a CompositeFileDefinition, otherwise returns null</returns>
        public CompositeFileDefinition WritePathToStream(ClientDependencyType type, string path, HttpContextBase context, StreamWriter sw)
        {
            path = path.Trim();

            if (string.IsNullOrEmpty(path) || !PathHelper.TryGetFileExtension(path, out var extension))
            {
                return(null);
            }

            CompositeFileDefinition def = null;

            //all config based extensions and all extensions registered by file writers
            var fileBasedExtensions = ClientDependencySettings.Instance.FileBasedDependencyExtensionList
                                      .Union(FileWriters.GetRegisteredExtensions())
                                      .ToList();

            try
            {
                if (fileBasedExtensions.Contains(extension, StringComparer.InvariantCultureIgnoreCase))
                {
                    if (CanProcessLocally(context, path, out IVirtualFileWriter virtualWriter))
                    {
                        //internal request
                        if (virtualWriter != null)
                        {
                            var vf = virtualWriter.FileProvider.GetFile(path);
                            def = WriteVirtualFileToStream(sw, vf, virtualWriter, type, context);
                        }
                        else
                        {
                            if (PathHelper.TryGetFileInfo(path, context, out var fi))
                            {
                                def = WriteFileToStream(sw, fi, type, path, context);
                            }
                        }
                    }
                    else
                    {
                        //Before we try to load it by URI, we want to check if the URI is a local file request.
                        //We can try to detect if it is and try to load it from the file system.
                        //If the file isn't local and doesn't exist then we'll continue trying to load it via the URI.

                        //NOTE: At this stage we've already validated that the file type is based on the file types registered with CDF.

                        if (Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out Uri uri))
                        {
                            if (uri.IsLocalUri(context))
                            {
                                //extract the path of the request and ensure it starts with the virtual path marker (~/) so that the file
                                //can only be looked up local to this website.
                                var absPath = uri.AbsolutePath.EnsureStartsWith("/").EnsureStartsWith("~");

                                if (PathHelper.TryGetFileInfo(absPath, context, out var fi))
                                {
                                    //Re-validate the extension since URIs and file names can parse differently
                                    extension = fi.Extension;
                                    if (fileBasedExtensions.Contains(extension, StringComparer.InvariantCultureIgnoreCase))
                                    {
                                        def = WriteFileToStream(sw, fi, type, path, context);
                                    }
                                }
                            }
                            else
                            {
                                //external request to a file based dependency
                                def = WriteFileToStream(sw, path, type, context);
                            }
                        }
                    }
                }
                else
                {
                    //if it's not a file based dependency, try to get the request output.
                    def = WriteFileToStream(sw, path, type, context);
                }
            }
            catch (Exception ex)
            {
                //if this fails, log the exception, but continue
                ClientDependencySettings.Instance.Logger.Error($"Could not load file contents from {path}. EXCEPTION: {ex.Message}", ex);
            }

            if (def == null)
            {
                return(null);
            }

            if (type == ClientDependencyType.Javascript)
            {
                sw.Write(";;;"); //write semicolons in case the js isn't formatted correctly. This also helps for debugging.
            }

            return(def);
        }
Beispiel #3
0
        /// <summary>
        /// Writes a given path to the stream
        /// </summary>
        /// <param name="type"></param>
        /// <param name="path">The path could be a local url or an absolute url</param>
        /// <param name="context"></param>
        /// <param name="sw"></param>
        /// <returns>If successful returns a CompositeFileDefinition, otherwise returns null</returns>
        public CompositeFileDefinition WritePathToStream(ClientDependencyType type, string path, HttpContextBase context, StreamWriter sw)
        {
            CompositeFileDefinition def = null;

            if (!string.IsNullOrEmpty(path))
            {
                try
                {
                    var fi = new FileInfo(context.Server.MapPath(path));

                    //all config based extensions and all extensions registered by file writers
                    var fileBasedExtensions = ClientDependencySettings.Instance.FileBasedDependencyExtensionList
                                              .Union(FileWriters.GetRegisteredExtensions());

                    if (fileBasedExtensions.Contains(fi.Extension.ToUpper()))
                    {
                        //if the file doesn't exist, then we'll assume it is a URI external request
                        def = !fi.Exists
                            ? WriteFileToStream(sw, path, type, context)      //external request
                            : WriteFileToStream(sw, fi, type, path, context); //internal request
                    }
                    else
                    {
                        //if it's not a file based dependency, try to get the request output.
                        def = WriteFileToStream(sw, path, type, context);
                    }
                }
                catch (Exception ex)
                {
                    if (ex is NotSupportedException ||
                        ex is ArgumentException ||
                        ex is HttpException)
                    {
                        //could not parse the string into a fileinfo or couldn't mappath, so we assume it is a URI

                        //before we try to load it by URI, we want to check if the URI is a local request, we'll try to detect if it is and
                        // then try to load it from the file system, if the file isn't there then we'll continue trying to load it via the URI.
                        Uri uri;
                        if (Uri.TryCreate(path, UriKind.RelativeOrAbsolute, out uri) && uri.IsLocalUri(context))
                        {
                            var localPath = uri.PathAndQuery;
                            var fi        = new FileInfo(context.Server.MapPath(localPath));
                            if (fi.Exists)
                            {
                                try
                                {
                                    WriteFileToStream(sw, fi, type, path, context); //internal request
                                }
                                catch (Exception ex1)
                                {
                                    ClientDependencySettings.Instance.Logger.Error(string.Format("Could not load file contents from {0}. EXCEPTION: {1}", path, ex1.Message), ex1);
                                }
                            }
                        }

                        def = WriteFileToStream(sw, path, type, context);
                    }
                    else
                    {
                        //if this fails, log the exception, but continue
                        ClientDependencySettings.Instance.Logger.Error(string.Format("Could not load file contents from {0}. EXCEPTION: {1}", path, ex.Message), ex);
                    }
                }
            }

            if (type == ClientDependencyType.Javascript)
            {
                sw.Write(";;;"); //write semicolons in case the js isn't formatted correctly. This also helps for debugging.
            }

            return(def);
        }
Beispiel #4
0
        /// <summary>
        /// Because we can have both internal and external dependencies rendered, we need to stagger the script tag output... if they are external, we need to stop the compressing/combining
        /// and write out the external dependency, then resume the compressing/combining handler.
        /// </summary>
        /// <param name="dependencies"></param>
        /// <param name="http"></param>
        /// <param name="builder"></param>
        /// <param name="renderCompositeFiles"></param>
        /// <param name="renderSingle"></param>
        protected void WriteStaggeredDependencies(
            IEnumerable <IClientDependencyFile> dependencies,
            HttpContextBase http,
            StringBuilder builder,
            Func <IEnumerable <IClientDependencyFile>, HttpContextBase, IDictionary <string, string>, string> renderCompositeFiles,
            Func <string, IDictionary <string, string>, string> renderSingle)
        {
            var fileBasedExtensions = ClientDependencySettings.Instance.FileBasedDependencyExtensionList
                                      .Union(FileWriters.GetRegisteredExtensions())
                                      .ToArray();

            var currNonRemoteFiles = new List <IClientDependencyFile>();

            foreach (var f in dependencies)
            {
                //need to parse out the request's extensions and remove query strings
                //need to force non-bundled lines for items with query parameters or a hash value.
                var extension = f.FilePath.Contains('?') || f.FilePath.Contains('#') ? "" : Path.GetExtension(f.FilePath);
                var stringExt = "";
#if !Net35
                if (!string.IsNullOrWhiteSpace(extension))
#else
                if (!string.IsNullOrEmpty(extension))
#endif
                {
                    stringExt = extension.ToUpper().Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0];
                }

                //if this is a protocol-relative/protocol-less uri, then we need to add the protocol for the remaining
                // logic to work properly
                if (f.FilePath.StartsWith("//"))
                {
                    f.FilePath = Regex.Replace(f.FilePath, @"^\/\/", http.Request.Url.GetLeftPart(UriPartial.Scheme));
                }


                // if it is an external resource OR
                // if it is a non-standard JS/CSS resource (i.e. a server request)
                // then we need to break the sequence
                // unless it has been explicitely required that the dependency be bundled
                if ((!http.IsAbsolutePath(f.FilePath) && !fileBasedExtensions.Contains(stringExt))
                    //now check for external resources
                    || (http.IsAbsolutePath(f.FilePath)
                        //remote dependencies aren't local
                        && !new Uri(f.FilePath, UriKind.RelativeOrAbsolute).IsLocalUri(http)
                        // not required to be bundled
                        && !f.ForceBundle))
                {
                    //we've encountered an external dependency, so we need to break the sequence and restart it after
                    //we output the raw script tag
                    if (currNonRemoteFiles.Count > 0)
                    {
                        //render the current buffer
                        StaggerOnDifferentAttributes(http, builder, currNonRemoteFiles, renderCompositeFiles);
                        //clear the buffer
                        currNonRemoteFiles.Clear();
                    }
                    //write out the single script tag
                    builder.Append(renderSingle(f.FilePath, GetHtmlAttributes(f)));
                }
                else
                {
                    //its a normal registration, add to the buffer
                    currNonRemoteFiles.Add(f);
                }
            }
            //now check if there's anything in the buffer to render
            if (currNonRemoteFiles.Count > 0)
            {
                //render the current buffer
                StaggerOnDifferentAttributes(http, builder, currNonRemoteFiles, renderCompositeFiles);
            }
        }
        /// <summary>
        /// Because we can have both internal and external dependencies rendered, we need to stagger the script tag output... if they are external, we need to stop the compressing/combining
        /// and write out the external dependency, then resume the compressing/combining handler.
        /// </summary>
        /// <param name="dependencies"></param>
        /// <param name="http"></param>
        /// <param name="builder"></param>
        /// <param name="renderCompositeFiles"></param>
        /// <param name="renderSingle"></param>
        protected void WriteStaggeredDependencies(
            IEnumerable <IClientDependencyFile> dependencies,
            HttpContextBase http,
            StringBuilder builder,
            Func <IEnumerable <IClientDependencyFile>, HttpContextBase, IDictionary <string, string>, string> renderCompositeFiles,
            Func <string, IDictionary <string, string>, string> renderSingle)
        {
            //This action will stagger the output based on whether or not the html attribute declarations are the same for each dependency
            Action <IEnumerable <IClientDependencyFile> > staggerOnDifferentAttributes = (list) =>
            {
                var sameAttributes = new List <IClientDependencyFile>();
                var currHtmlAttr   = GetHtmlAttributes(list.ElementAt(0));
                foreach (var c in list)
                {
                    if (!currHtmlAttr.IsEqualTo(GetHtmlAttributes(c)))
                    {
                        //if the attributes are different we need to stagger
                        if (sameAttributes.Any())
                        {
                            //render the current buffer
                            builder.Append(renderCompositeFiles(sameAttributes, http, currHtmlAttr));
                            //clear the buffer
                            sameAttributes.Clear();
                        }
                    }

                    //add the item to the buffer and set the current html attributes
                    sameAttributes.Add(c);
                    currHtmlAttr = GetHtmlAttributes(c);
                }

                //if there's anything in the buffer then write the remaining
                if (sameAttributes.Any())
                {
                    builder.Append(renderCompositeFiles(sameAttributes, http, currHtmlAttr));
                }
            };

            var fileBasedExtensions = ClientDependencySettings.Instance.FileBasedDependencyExtensionList
                                      .Union(FileWriters.GetRegisteredExtensions())
                                      .ToArray();

            var currNonRemoteFiles = new List <IClientDependencyFile>();

            foreach (var f in dependencies)
            {
                // if it is an external resource OR
                // if it is a non-standard JS/CSS resource (i.e. a server request)
                // then we need to break the sequence
                // unless it has been explicitely required that the dependency be bundled
                if (!http.IsAbsolutePath(f.FilePath) && !fileBasedExtensions.Contains(Path.GetExtension(f.FilePath).ToUpper())
                    //now check for external resources
                    || (http.IsAbsolutePath(f.FilePath)
                        //remote dependencies aren't local
                        && !new Uri(f.FilePath, UriKind.RelativeOrAbsolute).IsLocalUri(http)
                        // not required to be bundled
                        && !f.ForceBundle))
                {
                    //we've encountered an external dependency, so we need to break the sequence and restart it after
                    //we output the raw script tag
                    if (currNonRemoteFiles.Count > 0)
                    {
                        //render the current buffer
                        staggerOnDifferentAttributes(currNonRemoteFiles);
                        //clear the buffer
                        currNonRemoteFiles.Clear();
                    }
                    //write out the single script tag
                    builder.Append(renderSingle(f.FilePath, GetHtmlAttributes(f)));
                }
                else
                {
                    //its a normal registration, add to the buffer
                    currNonRemoteFiles.Add(f);
                }
            }
            //now check if there's anything in the buffer to render
            if (currNonRemoteFiles.Count > 0)
            {
                //render the current buffer
                staggerOnDifferentAttributes(currNonRemoteFiles);
            }
        }