Пример #1
0
		private string HeadCacheKey (Uri currentUrl, ConfigSection.HeadCachingOption headCachingOption)
		{
			const string keyPrefix = "HeadCacheKey__";

			switch (headCachingOption) {
			case ConfigSection.HeadCachingOption.PerSite:
                    // Always return the same key for all pages
				return keyPrefix;

			case ConfigSection.HeadCachingOption.PerFolder:
                    // Key is based on domain + folder, but not the file
                    //
                    // If no .aspx file is specific, AbsoluteUri will still include
                    // the actual file, such as default.aspx.
				int idxLastSlash = currentUrl.AbsoluteUri.LastIndexOf ('/');
				if (idxLastSlash == -1) {
					return keyPrefix + currentUrl.ToString ();
				}

				return keyPrefix + currentUrl.AbsoluteUri.Substring (0, idxLastSlash);

			case ConfigSection.HeadCachingOption.PerPage:
                    // Key is based on folder + file, but not on query string
				return keyPrefix + currentUrl.AbsolutePath;

			case ConfigSection.HeadCachingOption.PerUrl:
				return keyPrefix + currentUrl.ToString ();

			default:
				throw new Exception (
                        "HeadCacheKey - unknown headCachingOption: " + headCachingOption.ToString ());
			}
		}
Пример #2
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="headHtmlSb"></param>
        /// <param name="groupRegexp"></param>
        /// <param name="fileType"></param>
        /// <param name="tagTemplate"></param>
        /// <param name="totalFileNames"></param>
        /// <param name="combineFiles"></param>
        /// <param name="placeCombinedFilesAtEnd">
        /// This is only relevant if combineFiles equals All.
        /// If placeCombinedFilesAtEnd is true, the tag loading the combined file
        /// replaces the very last file group (important if you're loading js, because it means that if any
        /// js is dependent on a library loaded from a CDN, all the js will load after that library.
        /// 
        /// If placeCombinedFilesAtEnd is false, the tag replaces the very first file group.
        /// You'd use this with CSS, to get it load possibly sooner than the js.
        /// </param>
        /// <param name="urlProcessor"></param>
        private void ProcessFileType(
            string headHtml,
            string groupRegexp,
            FileTypeUtilities.FileType fileType,
            string tagTemplate,
            List<string> totalFileNames,
            ConfigSection.CombineOption combineFiles,
            bool placeCombinedFilesAtEnd,
            bool minifyCSS, bool minifyJavaScript,
            UrlProcessor urlProcessor)
        {
            List<groupInfo> allGroups = new List<groupInfo>();
            List<Uri> totalFileUrlsList = new List<Uri>();

            Regex r = new Regex(groupRegexp, RegexOptions.IgnoreCase);
            Match m = r.Match(headHtml);

            // Visit each group of script or link tags. Record the html of each file group
            // and a list of the urls in the tags in that file group in allGroups.
            while (m.Success)
            {
                string fileGroup = m.Value;
                CaptureCollection fileUrls = m.Groups["url"].Captures;

                // Visit the src or href of each individual script or link tag in the group,
                // and add to a list of urls.

                List<Uri> fileUrlsList = new List<Uri>();
                for (int j = 0; j < fileUrls.Count; j++)
                {
                    Uri fileUrl = new Uri(HttpContext.Current.Request.Url, fileUrls[j].Value);
                    fileUrlsList.Add(fileUrl);
                    totalFileUrlsList.Add(fileUrl);
                }

                allGroups.Add(new groupInfo() { fileGroup = fileGroup, fileUrlsList = fileUrlsList });
                m = m.NextMatch();
            }

            // Process each file group in allGroups
            switch (combineFiles)
            {
                case ConfigSection.CombineOption.None:
                    // In each group, process all URLs individually into tags.
                    // Note that CombinedFile.Url not only has the ability to combine urls, but also
                    // to insert version info - and we still want that to be able to use far future cache expiry,
                    // even if not combining files.
                    // Concatenate the tags and replace the group with the concatenated tags.
                    foreach (groupInfo g in allGroups)
                    {
                        StringBuilder tagsInGroup = new StringBuilder();

                        foreach (Uri u in g.fileUrlsList)
                        {
                            string versionedUrl = CombinedFile.Url(
                                HttpContext.Current, new List<Uri>(new Uri[] { u }), fileType,
                                minifyCSS, minifyJavaScript,
                                urlProcessor, totalFileNames);
                            string versionedFileTag =
                                string.Format(tagTemplate, versionedUrl);
                            tagsInGroup.Append(versionedFileTag);
                        }

                        // Be sure to trim the group before storing it (that is, remove space at the front and end).
                        // If you don't, you may store a group with white space at either end, that then doesn't match
                        // a group in some other file that is exactly the same, except for the white space at either end.
                        Replacements.Add(new Replacement { original = g.fileGroup.Trim(), replacement = tagsInGroup.ToString() });
                    }

                    break;

                case ConfigSection.CombineOption.PerGroup:
                    // In each group, process all URLs together into a combined tag.
                    // Replace the group with that one tag.
                    foreach (groupInfo g in allGroups)
                    {
                        string combinedFileUrl = CombinedFile.Url(
                            HttpContext.Current, g.fileUrlsList, fileType, minifyCSS, minifyJavaScript, urlProcessor, totalFileNames);
                        string combinedFileTag =
                            string.Format(tagTemplate, combinedFileUrl);

                        Replacements.Add(new Replacement { original = g.fileGroup.Trim(), replacement = combinedFileTag });
                    }

                    break;

                case ConfigSection.CombineOption.All:
                    // Combine all urls into a single tag. Then insert that tag in the head.
                    // Also, remove all groups.
                    {
                        string combinedFileUrl = CombinedFile.Url(
                            HttpContext.Current, totalFileUrlsList, fileType, minifyCSS, minifyJavaScript, urlProcessor, totalFileNames);
                        string combinedFileTag =
                            string.Format(tagTemplate, combinedFileUrl);

                        int idxFileGroupToReplace = placeCombinedFilesAtEnd ? (allGroups.Count - 1) : 0;

                        Replacements.Add(
                            new Replacement { original = allGroups[idxFileGroupToReplace].fileGroup.Trim(), replacement = combinedFileTag });

                        // Replace all file groups with empty string, except for the one
                        // we just replaced with the tag.
                        allGroups.RemoveAt(idxFileGroupToReplace);
                        foreach (groupInfo g in allGroups)
                        {
                            Replacements.Add(
                                new Replacement { original = g.fileGroup.Trim(), replacement = "" });
                        }
                    }
                    break;

                default:
                    throw new ArgumentException("ProcessFileType - combineFiles=" + combineFiles.ToString());
            }
        }
Пример #3
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="headHtml">
        /// the current contents of the head
        /// </param>
        /// <param name="totalFileNames">
        /// totalFileNames will be filled with a list of the names of all
        /// CSS and JavaScript files loaded in the head (that is, those
        /// that get combined and/or minified).
        /// </param>
        /// <param name="combineCSSFiles">
        /// If true, the CSS files in the group are combined into a single file.
        /// </param>
        /// <param name="combineJavaScriptFiles">
        /// If true, the JavaScript files in the group are combined into a single file.
        /// </param>
        /// <param name="urlProcessor">
        /// Use this UrlProcessor to for example insert version ids.
        /// The ProcessedImageUrls property of this UrlProcessor has already been loaded with the 
        /// urls of the images on the page.
        /// </param>
        /// <returns>
        /// New content of the head
        /// </returns>
        public HeadAnalysis(
            string headHtml, List<string> totalFileNames,
            ConfigSection.CombineOption combineCSSFiles, ConfigSection.CombineOption combineJavaScriptFiles,
            bool minifyCSS, bool minifyJavaScript,
            UrlProcessor urlProcessor)
        {
            // Find groups of script or link tags that load a script or css file from
            // the local site. That is, their source does not start with
            // http:// or https://
            //
            // A script tag that has code between the <script> and </script>
            // has inline script, so we're not interested in that either.
            //
            // The files within each group will be served up as a single file
            // (which only exists in cache).
            // By combining js and css files only within the groups, we make sure
            // that the order of the script files is not changed.
            // 
            // An improvement would be to provide an option to 
            // move all css link tags above the script tags, so you could
            // combine them all. Move them above, in case any javascript depends on the css.

            const string regexpScriptGroup =
                @"(?:<script[^>]*?src=(?:""|')(?<url>(?!http://)(?!https://)[^""']*?)(?:""|')[^>]*?>[\s\n\r]*</script>[\s\n\r]*)+";

            const string tagTemplateSript = "<script type=\"text/javascript\" src=\"{0}\"></script>";

            const string regexpCssGroup =
                @"(?:<link[^>]*?href=(?:""|')(?<url>(?!http://)(?!https://)[^""']*?\.css)(?:""|')[^>]*?>[\s\n\r]*)+";

            const string tagTemplateCss = "<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />";

            // ProcessFileType adds records to the Replacements list

            Replacements = new List<Replacement>();

            ProcessFileType(
                headHtml,
                regexpScriptGroup,
                FileTypeUtilities.FileType.JavaScript,
                tagTemplateSript,
                totalFileNames,
                combineJavaScriptFiles,
                true,
                minifyCSS, minifyJavaScript,
                urlProcessor);

            ProcessFileType(
                headHtml,
                regexpCssGroup,
                FileTypeUtilities.FileType.CSS,
                tagTemplateCss,
                totalFileNames,
                combineCSSFiles,
                false,
                minifyCSS, minifyJavaScript,
                urlProcessor);

            // The urlProcessor now contains all image urls contained in CSS files.
            // Copy those urls to this.ProcessedImageUrls.
            ProcessedImageUrls = new List<string>(urlProcessor.ProcessedImageUrls);
            urlProcessor.ProcessedImageUrls.Clear();
        }
Пример #4
0
        // ------------------------

        public static bool OptionIsActive(ConfigSection.ActiveOption activeOption)
        {
            bool optionIsActive =
                (activeOption == ConfigSection.ActiveOption.Always) ||
                ((activeOption == ConfigSection.ActiveOption.ReleaseModeOnly) &&
                 (!HttpContext.Current.IsDebuggingEnabled)) ||
                ((activeOption == ConfigSection.ActiveOption.DebugModeOnly) &&
                 (HttpContext.Current.IsDebuggingEnabled));

            return optionIsActive;
        }