Example #1
0
        public override string MinifyString(string source)
        {
            var settings = new HtmlMinificationSettings
            {
                RemoveOptionalEndTags = false,

                AttributeQuotesRemovalMode = WESettings.Instance.Html.MinificationMode,
                RemoveRedundantAttributes  = false,
                //EmptyTagRenderMode = HtmlEmptyTagRenderMode.Slash,
            };

            var minifier = new HtmlMinifier(settings);
            MarkupMinificationResult result = minifier.Minify(source, generateStatistics: true);

            if (result.Errors.Count == 0)
            {
                WebEssentialsPackage.DTE.StatusBar.Text = "Web Essentials: HTML minified by " + result.Statistics.SavedInPercent + "%";
                return(result.MinifiedContent);
            }
            else
            {
                WebEssentialsPackage.DTE.StatusBar.Text = "Web Essentials: Cannot minify the current selection.  See Output Window for details.";
                Logger.ShowMessage("Cannot minify the selection:\r\n\r\n" + String.Join(Environment.NewLine, result.Errors.Select(e => e.Message)));
                return(null);
            }
        }
Example #2
0
        private string Minify(string markup)
        {
            MarkupMinificationResult result = _htmlMinifier.Minify(markup, string.Empty, Encoding.UTF8, true);

            if (result.Errors.Count == 0)
            {
                MinificationStatistics statistics = result.Statistics;
                if (statistics != null)
                {
                    Console.WriteLine();
                    Console.WriteLine($"Original size: {statistics.OriginalSize:N0} Bytes | Minified size: {statistics.MinifiedSize:N0} Bytes | Saved: {statistics.SavedInPercent:N2}%");
                }
                //Console.WriteLine($"{Environment.NewLine}Minified content:{Environment.NewLine}{Environment.NewLine}{result.MinifiedContent}");

                return(result.MinifiedContent);
            }
            else
            {
                IList <MinificationErrorInfo> errors = result.Errors;

                Console.WriteLine();
                Console.WriteLine($"Found {errors.Count:N0} error(s):");

                foreach (var error in errors)
                {
                    Console.WriteLine($" - Line {error.LineNumber}, Column {error.ColumnNumber}: {error.Message}");
                }

                return(markup);
            }
        }
Example #3
0
        /// <summary>
        /// Safely Attempts to minify the provided string.
        /// </summary>
        /// <param name="recording">The string to minify</param>
        /// <returns>Minified version of the string, or, if errors were encountered, returns the original string.</returns>
        private string Minify(string recording)
        {
            var settings    = new HtmlMinificationSettings();
            var cssMinifier = new KristensenCssMinifier();
            var jsMinifier  = new CrockfordJsMinifier();

            var minifier = new HtmlMinifier(settings, cssMinifier, jsMinifier);

            MarkupMinificationResult result = minifier.Minify(recording);

            if (result.Errors.Count != 0)
            {
                var builder = new StringBuilder("Attempt to minify rendering failed");

                foreach (var error in result.Errors)
                {
                    builder.AppendLine(error.Category + " - " + error.Message);
                }

                Log.Warn(builder.ToString(), this);
                return(recording);
            }

            return(result.MinifiedContent);
        }
Example #4
0
        public override string MinifyString(string source)
        {
            var weHtmlSettings = WESettings.Instance.Html;
            var settings       = new HtmlMinificationSettings
            {
                // Tags
                RemoveOptionalEndTags = false,
                //EmptyTagRenderMode = HtmlEmptyTagRenderMode.Slash,

                // Attributes
                AttributeQuotesRemovalMode = weHtmlSettings.AttributeQuotesRemovalMode,
                RemoveRedundantAttributes  = false,

                // JavaScript templating
                ProcessableScriptTypeList        = weHtmlSettings.ProcessableScriptTypeList,
                MinifyKnockoutBindingExpressions = weHtmlSettings.MinifyKnockoutBindingExpressions,
                MinifyAngularBindingExpressions  = weHtmlSettings.MinifyAngularBindingExpressions,
                CustomAngularDirectiveList       = weHtmlSettings.CustomAngularDirectiveList
            };

            var minifier = new HtmlMinifier(settings);
            MarkupMinificationResult result = minifier.Minify(source, generateStatistics: true);

            if (result.Errors.Count == 0)
            {
                WebEssentialsPackage.DTE.StatusBar.Text = "Web Essentials: HTML minified by " + result.Statistics.SavedInPercent + "%";
                return(result.MinifiedContent);
            }
            else
            {
                WebEssentialsPackage.DTE.StatusBar.Text = "Web Essentials: Cannot minify the current selection.  See Output Window for details.";
                Logger.ShowMessage("Cannot minify the selection:\r\n\r\n" + String.Join(Environment.NewLine, result.Errors.Select(e => e.Message)));
                return(null);
            }
        }
        public override void Close()
        {
            byte[] cacheBytes = _cacheStream.ToArray();
            int    cacheSize  = cacheBytes.Length;

            bool isMinified = false;

            if (WebMarkupMinContext.Current.CheckResponseSize(cacheSize))
            {
                string content = _encoding.GetString(cacheBytes);

                MarkupMinificationResult minificationResult = _minifier.Minify(content,
                                                                               _currentUrl, _encoding, false);
                if (minificationResult.Errors.Count == 0)
                {
                    byte[] output = _encoding.GetBytes(minificationResult.MinifiedContent);
                    _stream.Write(output, 0, output.GetLength(0));

                    isMinified = true;
                }
            }

            if (!isMinified)
            {
                _stream.Write(cacheBytes, 0, cacheSize);
            }

            _cacheStream.SetLength(0);
            _stream.Close();
        }
        public void Render(HtmlTextWriter writer, Action <HtmlTextWriter> renderHandler)
        {
            if (!DisableMinification)
            {
                IMarkupMinificationManager minificationManager =
                    _minificationManager ?? GetDefaultMinificationManager();
                HttpContext  context  = HttpContext.Current;
                HttpResponse response = context.Response;
                HttpRequest  request  = context.Request;

                using (var htmlwriter = new HtmlTextWriter(new StringWriter()))
                {
                    renderHandler(htmlwriter);

                    string content    = htmlwriter.InnerWriter.ToString();
                    bool   isMinified = false;

                    Encoding encoding     = response.ContentEncoding;
                    int      responseSize = encoding.GetByteCount(content);
                    string   httpMethod   = request.HttpMethod;
                    string   mediaType    = response.ContentType;
                    string   currentUrl   = request.RawUrl;

                    if (response.StatusCode == 200 &&
                        _configuration.IsAllowableResponseSize(responseSize) &&
                        minificationManager.IsSupportedHttpMethod(httpMethod) &&
                        minificationManager.IsSupportedMediaType(mediaType) &&
                        minificationManager.IsProcessablePage(currentUrl))
                    {
                        IMarkupMinifier          minifier           = minificationManager.CreateMinifier();
                        MarkupMinificationResult minificationResult = minifier.Minify(content,
                                                                                      currentUrl, encoding, minificationManager.GenerateStatistics);
                        if (minificationResult.Errors.Count == 0)
                        {
                            if (_configuration.IsPoweredByHttpHeadersEnabled())
                            {
                                minificationManager.AppendPoweredByHttpHeader((key, value) =>
                                {
                                    response.Headers[key] = value;
                                });
                            }

                            writer.Write(minificationResult.MinifiedContent);

                            isMinified = true;
                        }
                    }

                    if (!isMinified)
                    {
                        writer.Write(content);
                    }
                }
            }
            else
            {
                renderHandler(writer);
            }
        }
        private static MinificationResult MinifyHtml(string file, bool produceGzipFile)
        {
            var settings = new HtmlMinificationSettings
            {
                RemoveOptionalEndTags      = false,
                AttributeQuotesRemovalMode = WebMarkupMin.Core.HtmlAttributeQuotesRemovalMode.Html5,
                RemoveRedundantAttributes  = false,
            };

            string content = File.ReadAllText(file);
            string minFile = GetMinFileName(file);

            var minifier  = new HtmlMinifier(settings);
            var minResult = new MinificationResult(file, null, null);

            try
            {
                MarkupMinificationResult result = minifier.Minify(content, generateStatistics: true);
                minResult.MinifiedContent = result.MinifiedContent;

                if (!result.Errors.Any())
                {
                    OnBeforeWritingMinFile(file, minFile);
                    File.WriteAllText(minFile, result.MinifiedContent, new UTF8Encoding(true));
                    OnAfterWritingMinFile(file, minFile);

                    if (produceGzipFile)
                    {
                        GzipFile(minFile);
                    }
                }
                else
                {
                    foreach (var error in result.Errors)
                    {
                        minResult.Errors.Add(new MinificationError
                        {
                            FileName     = file,
                            Message      = error.Message,
                            LineNumber   = error.LineNumber,
                            ColumnNumber = error.ColumnNumber
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                minResult.Errors.Add(new MinificationError
                {
                    FileName     = file,
                    Message      = ex.Message,
                    LineNumber   = 0,
                    ColumnNumber = 0
                });
            }

            return(minResult);
        }
Example #8
0
        public override void Close()
        {
            bool isEncodedContent = HttpHeadersHelpers.IsEncodedContent(_response.Headers);

            if (!isEncodedContent)
            {
                byte[] cachedBytes     = _cachedStream.ToArray();
                int    cachedByteCount = cachedBytes.Length;

                bool isMinified = false;

                if (_configuration.IsAllowableResponseSize(cachedByteCount))
                {
                    string          content  = _encoding.GetString(cachedBytes);
                    IMarkupMinifier minifier = _minificationManager.CreateMinifier();

                    MarkupMinificationResult minificationResult = minifier.Minify(content,
                                                                                  _currentUrl, _encoding, _minificationManager.GenerateStatistics);
                    if (minificationResult.Errors.Count == 0)
                    {
                        if (_configuration.IsPoweredByHttpHeadersEnabled())
                        {
                            _minificationManager.AppendPoweredByHttpHeader((key, value) =>
                            {
                                _response.Headers[key] = value;
                            });
                        }

                        using (var writer = new StreamWriter(_originalStream, _encoding))
                        {
                            writer.Write(minificationResult.MinifiedContent);
                        }

                        isMinified = true;
                    }
                }

                if (!isMinified)
                {
                    _cachedStream.Seek(0, SeekOrigin.Begin);
                    _cachedStream.CopyTo(_originalStream);
                }
            }

            _cachedStream.Clear();
            _originalStream.Close();

            if (isEncodedContent)
            {
                throw new InvalidOperationException(
                          string.Format(
                              AspNetCommonStrings.MarkupMinificationIsNotApplicableToEncodedContent,
                              _response.Headers["Content-Encoding"]
                              )
                          );
            }
        }
        private static MinificationResult MinifyHtml(Bundle bundle)
        {
            string file     = bundle.GetAbsoluteOutputFile();
            string content  = ReadAllText(file);
            var    settings = HtmlOptions.GetSettings(bundle);
            string minFile  = GetMinFileName(file);

            var minifier  = new HtmlMinifier(settings);
            var minResult = new MinificationResult(file, null, null);

            try
            {
                MarkupMinificationResult result = minifier.Minify(content, generateStatistics: true);
                minResult.MinifiedContent = result.MinifiedContent.Trim();

                if (!result.Errors.Any())
                {
                    bool containsChanges = FileHelpers.HasFileContentChanged(minFile, result.MinifiedContent);

                    OnBeforeWritingMinFile(file, minFile, bundle, containsChanges);

                    if (containsChanges)
                    {
                        File.WriteAllText(minFile, result.MinifiedContent, new UTF8Encoding(false));
                    }

                    OnAfterWritingMinFile(file, minFile, bundle, containsChanges);

                    GzipFile(minFile, bundle, containsChanges);
                }
                else
                {
                    foreach (var error in result.Errors)
                    {
                        minResult.Errors.Add(new MinificationError
                        {
                            FileName     = file,
                            Message      = error.Message,
                            LineNumber   = error.LineNumber,
                            ColumnNumber = error.ColumnNumber
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                minResult.Errors.Add(new MinificationError
                {
                    FileName     = file,
                    Message      = ex.Message,
                    LineNumber   = 0,
                    ColumnNumber = 0
                });
            }

            return(minResult);
        }
        static void Main(string[] args)
        {
            const string htmlInput = @"<!DOCTYPE html>
    <html>
        <head>
            <meta charset=""utf-8"" />
            <title>The test document</title>
            <link href=""favicon.ico"" rel=""shortcut icon"" type=""image/x-icon"" />
            <meta name=""viewport"" content=""width=device-width"" />
            <link rel=""stylesheet"" type=""text/css"" href=""/Content/Site.css"" />
        </head>
        <body>
            <p>Lorem ipsum dolor sit amet...</p>
    
            <script src=""http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.min.js""></script>
            <script>
                (window.jquery) || document.write('<script src=""/Scripts/jquery-1.9.1.min.js""><\/script>');
            </script>
        </body>
    </html>";

            var htmlMinifier = new HtmlMinifier();

            MarkupMinificationResult result = htmlMinifier.Minify(htmlInput,
                                                                  generateStatistics: true);

            if (result.Errors.Count == 0)
            {
                MinificationStatistics statistics = result.Statistics;
                if (statistics != null)
                {
                    Console.WriteLine("Original size: {0:N0} Bytes",
                                      statistics.OriginalSize);
                    Console.WriteLine("Minified size: {0:N0} Bytes",
                                      statistics.MinifiedSize);
                    Console.WriteLine("Saved: {0:N2}%",
                                      statistics.SavedInPercent);
                }
                Console.WriteLine("Minified content:{0}{0}{1}",
                                  Environment.NewLine, result.MinifiedContent);
            }
            else
            {
                IList <MinificationErrorInfo> errors = result.Errors;

                Console.WriteLine("Found {0:N0} error(s):", errors.Count);
                Console.WriteLine();

                foreach (var error in errors)
                {
                    Console.WriteLine("Line {0}, Column {1}: {2}",
                                      error.LineNumber, error.ColumnNumber, error.Message);
                    Console.WriteLine();
                }
            }
            Console.ReadLine();
        }
Example #11
0
        public static string MinifyString(string extension, string content)
        {
            if (extension == ".css")
            {
                Minifier    minifier = new Minifier();
                CssSettings settings = new CssSettings();
                settings.CommentMode = CssComment.None;

                if (WESettings.GetBoolean(WESettings.Keys.KeepImportantComments))
                {
                    settings.CommentMode = CssComment.Important;
                }

                return(minifier.MinifyStyleSheet(content, settings));
            }
            else if (extension == ".js")
            {
                Minifier     minifier = new Minifier();
                CodeSettings settings = new CodeSettings()
                {
                    EvalTreatment             = EvalTreatment.MakeImmediateSafe,
                    PreserveImportantComments = WESettings.GetBoolean(WESettings.Keys.KeepImportantComments)
                };

                return(minifier.MinifyJavaScript(content, settings));
            }
            else if (_htmlExt.Contains(extension.ToLowerInvariant()))
            {
                var minifyer = new XhtmlMinifier();
                MarkupMinificationResult result = minifyer.Minify(content, generateStatistics: true);

                if (result.Errors.Count == 0)
                {
                    EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: HTML minified by " + result.Statistics.SavedInPercent + "%";
                    return(result.MinifiedContent);
                }
                else
                {
                    EditorExtensionsPackage.DTE.StatusBar.Text = "Web Essentials: Cannot minify the current selection";
                    return(content);
                }
            }

            return(null);
        }
        public override void Close()
        {
            byte[] cacheBytes = _cacheStream.ToArray();
            int    cacheSize  = cacheBytes.Length;

            bool isMinified = false;

            if (_configuration.IsAllowableResponseSize(cacheSize))
            {
                string          content  = _encoding.GetString(cacheBytes);
                IMarkupMinifier minifier = _minificationManager.CreateMinifier();

                MarkupMinificationResult minificationResult = minifier.Minify(content,
                                                                              _currentUrl, _encoding, false);
                if (minificationResult.Errors.Count == 0)
                {
                    if (_configuration.IsPoweredByHttpHeadersEnabled())
                    {
                        _minificationManager.AppendPoweredByHttpHeader((key, value) =>
                        {
                            _response.Headers[key] = value;
                        });
                    }

                    using (var writer = new StreamWriter(_stream, _encoding))
                    {
                        writer.Write(minificationResult.MinifiedContent);
                    }

                    isMinified = true;
                }
            }

            if (!isMinified)
            {
                _cacheStream.Seek(0, SeekOrigin.Begin);
                _cacheStream.CopyTo(_stream);
            }

            _cacheStream.SetLength(0);
            _stream.Close();
        }
        /// <summary>
        /// HTML minification.
        /// </summary>
        /// <param name="html">Code to minify.</param>
        /// <returns>Minified html.</returns>
        public static string MinifyHtml(string html)
        {
            var settings     = new HtmlMinificationSettings();
            var cssMinifier  = new KristensenCssMinifier();
            var jsMinifier   = new CrockfordJsMinifier();
            var htmlMinifier = new HtmlMinifier(settings, cssMinifier, jsMinifier);

            MarkupMinificationResult result = htmlMinifier.Minify(
                html,
                generateStatistics: false);

            if (result.Errors.Count == 0)
            {
                return(result.MinifiedContent);
            }
            else
            {
                return(html);
            }
        }
        private static string Minify(string html)
        {
            var settings = new HtmlMinificationSettings
            {
                RemoveOptionalEndTags      = false,
                AttributeQuotesRemovalMode = HtmlAttributeQuotesRemovalMode.Html5,
                RemoveRedundantAttributes  = false,
                WhitespaceMinificationMode = WhitespaceMinificationMode.Aggressive,
                MinifyEmbeddedCssCode      = true,
                MinifyEmbeddedJsCode       = true,
                MinifyInlineCssCode        = true,
                MinifyInlineJsCode         = true,
            };

            var minifier = new HtmlMinifier(settings);
            MarkupMinificationResult result = minifier.Minify(html, generateStatistics: true);

            if (result.Errors.Count == 0)
            {
                return(result.MinifiedContent);
            }

            return(html);
        }
Example #15
0
        public async Task Invoke(HttpContext context)
        {
            bool useMinification = _options.IsMinificationEnabled() && _minificationManagers.Count > 0;
            bool useCompression  = _options.IsCompressionEnabled() && _compressionManager != null;

            if (!useMinification && !useCompression)
            {
                await _next.Invoke(context);

                return;
            }

            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;

            using (var cachedStream = new MemoryStream())
            {
                Stream originalStream = response.Body;
                response.Body = cachedStream;

                try
                {
                    await _next.Invoke(context);
                }
                catch (Exception)
                {
                    response.Body = originalStream;
                    cachedStream.SetLength(0);

                    throw;
                }

                byte[] cachedBytes     = cachedStream.ToArray();
                int    cachedByteCount = cachedBytes.Length;
                bool   isProcessed     = false;

                response.Body = originalStream;
                cachedStream.SetLength(0);

                if (request.Method == "GET" && response.StatusCode == 200 &&
                    _options.IsAllowableResponseSize(cachedByteCount))
                {
                    string   contentType = response.ContentType;
                    string   mediaType   = null;
                    Encoding encoding    = null;

                    if (contentType != null)
                    {
                        MediaTypeHeaderValue mediaTypeHeader;

                        if (MediaTypeHeaderValue.TryParse(contentType, out mediaTypeHeader))
                        {
                            mediaType = mediaTypeHeader.MediaType.ToLowerInvariant();
                            encoding  = mediaTypeHeader.Encoding;
                        }
                    }

                    encoding = encoding ?? Encoding.GetEncoding(0);

                    string      currentUrl  = request.Path.Value;
                    QueryString queryString = request.QueryString;
                    if (queryString.HasValue)
                    {
                        currentUrl += queryString.Value;
                    }

                    string            content          = encoding.GetString(cachedBytes);
                    string            processedContent = content;
                    IHeaderDictionary responseHeaders  = response.Headers;
                    bool isEncodedContent = responseHeaders.IsEncodedContent();
                    Action <string, string> appendHttpHeader = (key, value) =>
                    {
                        responseHeaders.Append(key, new StringValues(value));
                    };

                    if (useMinification)
                    {
                        foreach (IMarkupMinificationManager minificationManager in _minificationManagers)
                        {
                            if (mediaType != null && minificationManager.IsSupportedMediaType(mediaType) &&
                                minificationManager.IsProcessablePage(currentUrl))
                            {
                                if (isEncodedContent)
                                {
                                    throw new InvalidOperationException(
                                              string.Format(
                                                  AspNetCommonStrings.MarkupMinificationIsNotApplicableToEncodedContent,
                                                  responseHeaders["Content-Encoding"]
                                                  )
                                              );
                                }

                                IMarkupMinifier minifier = minificationManager.CreateMinifier();

                                MarkupMinificationResult minificationResult = minifier.Minify(processedContent, currentUrl, encoding, false);
                                if (minificationResult.Errors.Count == 0)
                                {
                                    processedContent = minificationResult.MinifiedContent;
                                    if (_options.IsPoweredByHttpHeadersEnabled())
                                    {
                                        minificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
                                    }

                                    isProcessed = true;
                                }
                            }

                            if (isProcessed)
                            {
                                break;
                            }
                        }
                    }

                    if (useCompression && !isEncodedContent &&
                        _compressionManager.IsSupportedMediaType(mediaType))
                    {
                        byte[] processedBytes = encoding.GetBytes(processedContent);

                        using (var inputStream = new MemoryStream(processedBytes))
                            using (var outputStream = new MemoryStream())
                            {
                                string      acceptEncoding = request.Headers["Accept-Encoding"];
                                ICompressor compressor     = _compressionManager.CreateCompressor(acceptEncoding);

                                using (Stream compressedStream = compressor.Compress(outputStream))
                                {
                                    await inputStream.CopyToAsync(compressedStream);
                                }

                                byte[] compressedBytes     = outputStream.ToArray();
                                int    compressedByteCount = compressedBytes.Length;

                                if (outputStream.CanWrite)
                                {
                                    outputStream.SetLength(0);
                                }
                                inputStream.SetLength(0);

                                responseHeaders["Content-Length"] = compressedByteCount.ToString();
                                compressor.AppendHttpHeaders(appendHttpHeader);
                                await originalStream.WriteAsync(compressedBytes, 0, compressedByteCount);
                            }

                        isProcessed = true;
                    }
                    else
                    {
                        if (isProcessed)
                        {
                            byte[] processedBytes     = encoding.GetBytes(processedContent);
                            int    processedByteCount = processedBytes.Length;

                            responseHeaders["Content-Length"] = processedByteCount.ToString();
                            await originalStream.WriteAsync(processedBytes, 0, processedByteCount);
                        }
                    }
                }

                if (!isProcessed)
                {
                    await originalStream.WriteAsync(cachedBytes, 0, cachedByteCount);
                }
            }
        }
        public async Task Invoke(HttpContext context)
        {
            bool useMinification = _options.IsMinificationEnabled() && _minificationManagers.Count > 0;
            bool useCompression  = _options.IsCompressionEnabled() && _compressionManager != null;

            if (!useMinification && !useCompression)
            {
                await _next.Invoke(context);

                return;
            }

            HttpRequest  request  = context.Request;
            HttpResponse response = context.Response;

            using (var cacheStream = new MemoryStream())
            {
                Stream originalStream = response.Body;
                response.Body = cacheStream;

                await _next.Invoke(context);

                byte[] cacheBytes  = cacheStream.ToArray();
                int    cacheSize   = cacheBytes.Length;
                bool   isProcessed = false;

                response.Body = originalStream;

                if (request.Method == "GET" && response.StatusCode == 200 &&
                    _options.IsAllowableResponseSize(cacheSize))
                {
                    string   contentType = response.ContentType;
                    string   mediaType   = null;
                    Encoding encoding    = Encoding.GetEncoding(0);

                    if (contentType != null)
                    {
                        MediaTypeHeaderValue mediaTypeHeader;

                        if (MediaTypeHeaderValue.TryParse(contentType, out mediaTypeHeader))
                        {
                            mediaType = mediaTypeHeader.MediaType.ToLowerInvariant();
                            encoding  = mediaTypeHeader.Encoding;
                        }
                    }

                    string      currentUrl  = request.Path.Value;
                    QueryString queryString = request.QueryString;
                    if (queryString.HasValue)
                    {
                        currentUrl += queryString.Value;
                    }

                    string content          = encoding.GetString(cacheBytes);
                    string processedContent = content;
                    Action <string, string> appendHttpHeader = (key, value) =>
                    {
                        response.Headers.Append(key, new StringValues(value));
                    };

                    if (useMinification)
                    {
                        foreach (IMarkupMinificationManager minificationManager in _minificationManagers)
                        {
                            if (mediaType != null && minificationManager.IsSupportedMediaType(mediaType) &&
                                minificationManager.IsProcessablePage(currentUrl))
                            {
                                IMarkupMinifier minifier = minificationManager.CreateMinifier();

                                MarkupMinificationResult minificationResult = minifier.Minify(processedContent, currentUrl, encoding, false);
                                if (minificationResult.Errors.Count == 0)
                                {
                                    processedContent = minificationResult.MinifiedContent;
                                    if (_options.IsPoweredByHttpHeadersEnabled())
                                    {
                                        minificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
                                    }

                                    isProcessed = true;
                                }
                            }

                            if (isProcessed)
                            {
                                break;
                            }
                        }
                    }

                    if (useCompression && _compressionManager.IsSupportedMediaType(mediaType))
                    {
                        string acceptEncoding = request.Headers["Accept-Encoding"];

                        ICompressor compressor       = _compressionManager.CreateCompressor(acceptEncoding);
                        Stream      compressedStream = compressor.Compress(originalStream);
                        compressor.AppendHttpHeaders(appendHttpHeader);

                        using (var writer = new StreamWriter(compressedStream, encoding))
                        {
                            await writer.WriteAsync(processedContent);
                        }

                        isProcessed = true;
                    }
                    else
                    {
                        if (isProcessed)
                        {
                            using (var writer = new StreamWriter(originalStream, encoding))
                            {
                                await writer.WriteAsync(processedContent);
                            }
                        }
                    }
                }

                if (!isProcessed)
                {
                    cacheStream.Seek(0, SeekOrigin.Begin);
                    await cacheStream.CopyToAsync(originalStream);
                }

                cacheStream.SetLength(0);
            }
        }
Example #17
0
        public async Task Finish()
        {
            if (_minificationEnabled)
            {
                byte[] cachedBytes     = _cachedStream.ToArray();
                int    cachedByteCount = cachedBytes.Length;

                bool isMinified = false;

                if (cachedByteCount > 0 && _options.IsAllowableResponseSize(cachedByteCount))
                {
                    Encoding encoding = _encoding ?? Encoding.GetEncoding(0);
                    string   content  = encoding.GetString(cachedBytes);

                    IMarkupMinifier          minifier           = _currentMinificationManager.CreateMinifier();
                    MarkupMinificationResult minificationResult = minifier.Minify(content, _currentUrl,
                                                                                  _encoding, _currentMinificationManager.GenerateStatistics);

                    if (minificationResult.Errors.Count == 0)
                    {
                        IHeaderDictionary       responseHeaders  = _context.Response.Headers;
                        Action <string, string> appendHttpHeader = (key, value) =>
                        {
                            responseHeaders.Append(key, new StringValues(value));
                        };

                        if (_options.IsPoweredByHttpHeadersEnabled())
                        {
                            _currentMinificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
                        }
                        responseHeaders.Remove(HeaderNames.ContentMD5);

                        string processedContent   = minificationResult.MinifiedContent;
                        byte[] processedBytes     = encoding.GetBytes(processedContent);
                        int    processedByteCount = processedBytes.Length;

                        if (_compressionEnabled)
                        {
                            _currentCompressor.AppendHttpHeaders(appendHttpHeader);
                            responseHeaders.Remove(HeaderNames.ContentLength);
                            await _compressionStream.WriteAsync(processedBytes, 0, processedByteCount);
                        }
                        else
                        {
                            responseHeaders[HeaderNames.ContentLength] = processedByteCount.ToString();
                            await _originalStream.WriteAsync(processedBytes, 0, processedByteCount);
                        }

                        isMinified = true;
                    }

                    if (!isMinified)
                    {
                        Stream outputStream = _compressionEnabled ? _compressionStream : _originalStream;

                        _cachedStream.Seek(0, SeekOrigin.Begin);
                        await _cachedStream.CopyToAsync(outputStream);
                    }
                }

                _cachedStream.Clear();
            }
        }
        public void ProcessingXmlNodesIsCorrect()
        {
            // Arrange
            var minifier = new HtmlMinifier(new HtmlMinificationSettings(true));

            const string input1 = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
                                  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" +
                                  "  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
                                  "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" " +
                                  "xmlns:bi=\"urn:schemas-microsoft-com:mscom:bi\">\n" +
                                  "	<head>\n" +
                                  "		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"+
                                  "		<title>Some title...</title>\n"+
                                  "	</head>\n" +
                                  "	<body>\n" +
                                  "		<div id=\"content\">\n"+
                                  "			<p>Some text...</p>\n"+
                                  "		</div>\n"+
                                  "	</body>\n" +
                                  "</html>"
            ;
            const string targetOutput1 = "\n" +
                                         "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " +
                                         "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" +
                                         "<html xml:lang=\"en\" " +
                                         "xmlns:bi=\"urn:schemas-microsoft-com:mscom:bi\">\n" +
                                         "	<head>\n"+
                                         "		<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"+
                                         "		<title>Some title...</title>\n"+
                                         "	</head>\n"+
                                         "	<body>\n"+
                                         "		<div id=\"content\">\n"+
                                         "			<p>Some text...</p>\n"+
                                         "		</div>\n"+
                                         "	</body>\n"+
                                         "</html>"
            ;

            const string input2 = "<svg version=\"1.1\" baseProfile=\"full\" " +
                                  "xmlns=\"http://www.w3.org/2000/svg\" " +
                                  "xmlns:xlink=\"http://www.w3.org/1999/xlink\" " +
                                  "xmlns:ev=\"http://www.w3.org/2001/xml-events\" " +
                                  "width=\"100%\" height=\"100%\">\n" +
                                  "	<rect fill=\"white\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" />\n" +
                                  "	<rect fill=\"silver\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" rx=\"1em\" />\n" +
                                  "</svg>"
            ;
            const string targetOutput2 = "<svg version=\"1.1\" baseProfile=\"full\" " +
                                         "xmlns=\"http://www.w3.org/2000/svg\" " +
                                         "xmlns:xlink=\"http://www.w3.org/1999/xlink\" " +
                                         "xmlns:ev=\"http://www.w3.org/2001/xml-events\" " +
                                         "width=\"100%\" height=\"100%\">\n" +
                                         "	<rect fill=\"white\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" />\n"+
                                         "	<rect fill=\"silver\" x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" rx=\"1em\" />\n"+
                                         "</svg>"
            ;

            const string input3 = "<svg xmlns=\"http://www.w3.org/2000/svg\" " +
                                  "xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n" +
                                  "	<svg x=\"10\">\n" +
                                  "		<rect x=\"10\" y=\"10\" height=\"100\" width=\"100\" "+
                                  "style=\"stroke:#ff0000; fill: #0000ff\"/>\n" +
                                  "	</svg>\n" +
                                  "	<svg x=\"200\">\n" +
                                  "		<rect x=\"10\" y=\"10\" height=\"100\" width=\"100\" "+
                                  "style=\"stroke:#009900; fill: #00cc00\"/>\n" +
                                  "	</svg>\n" +
                                  "</svg>"
            ;
            const string targetOutput3 = "<svg xmlns=\"http://www.w3.org/2000/svg\" " +
                                         "xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n" +
                                         "	<svg x=\"10\">\n"+
                                         "		<rect x=\"10\" y=\"10\" height=\"100\" width=\"100\" "+
                                         "style=\"stroke:#ff0000; fill: #0000ff\" />\n" +
                                         "	</svg>\n"+
                                         "	<svg x=\"200\">\n"+
                                         "		<rect x=\"10\" y=\"10\" height=\"100\" width=\"100\" "+
                                         "style=\"stroke:#009900; fill: #00cc00\" />\n" +
                                         "	</svg>\n"+
                                         "</svg>";

            const string input4 = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">\n" +
                                  "	<infinity />\n" +
                                  "</math>"
            ;
            const string targetOutput4 = input4;

            // Act
            MarkupMinificationResult result1 = minifier.Minify(input1);
            string output1 = result1.MinifiedContent;
            IList <MinificationErrorInfo> warnings1 = result1.Warnings;

            MarkupMinificationResult result2 = minifier.Minify(input2);
            string output2 = result2.MinifiedContent;
            IList <MinificationErrorInfo> warnings2 = result2.Warnings;

            MarkupMinificationResult result3 = minifier.Minify(input3);
            string output3 = result3.MinifiedContent;
            IList <MinificationErrorInfo> warnings3 = result3.Warnings;

            MarkupMinificationResult result4 = minifier.Minify(input4);
            string output4 = result4.MinifiedContent;
            IList <MinificationErrorInfo> warnings4 = result4.Warnings;

            // Assert
            Assert.Equal(targetOutput1, output1);
            Assert.Equal(3, warnings1.Count);
            Assert.Equal(1, warnings1[0].LineNumber);
            Assert.Equal(1, warnings1[0].ColumnNumber);
            Assert.Equal(4, warnings1[1].LineNumber);
            Assert.Equal(44, warnings1[1].ColumnNumber);
            Assert.Equal(4, warnings1[2].LineNumber);
            Assert.Equal(58, warnings1[2].ColumnNumber);

            Assert.Equal(targetOutput2, output2);
            Assert.Equal(2, warnings2.Count);
            Assert.Equal(1, warnings2[0].LineNumber);
            Assert.Equal(74, warnings2[0].ColumnNumber);
            Assert.Equal(1, warnings2[1].LineNumber);
            Assert.Equal(117, warnings2[1].ColumnNumber);

            Assert.Equal(targetOutput3, output3);
            Assert.Equal(1, warnings3.Count);
            Assert.Equal(1, warnings3[0].LineNumber);
            Assert.Equal(41, warnings3[0].ColumnNumber);

            Assert.Equal(targetOutput4, output4);
            Assert.Equal(0, warnings4.Count);
        }
        protected async Task InternalFinishAsync()
        {
            if (_minificationEnabled)
            {
                bool isMinified      = false;
                int  cachedByteCount = (int)_cachedStream.Length;
                IHeaderDictionary       responseHeaders  = _context.Response.Headers;
                Action <string, string> appendHttpHeader = (key, value) =>
                {
                    responseHeaders.Append(key, new StringValues(value));
                };

                if (cachedByteCount > 0 && _options.IsAllowableResponseSize(cachedByteCount))
                {
                    Encoding encoding = _encoding ?? _options.DefaultEncoding;
#if NETSTANDARD1_3
                    byte[] cachedBytes = _cachedStream.ToArray();
                    string content     = encoding.GetString(cachedBytes);
#else
                    byte[] cachedBytes = _cachedStream.GetBuffer();
                    string content     = encoding.GetString(cachedBytes, 0, cachedByteCount);
#endif

                    IMarkupMinifier          minifier           = _currentMinificationManager.CreateMinifier();
                    MarkupMinificationResult minificationResult = minifier.Minify(content, _currentUrl,
                                                                                  _encoding, _currentMinificationManager.GenerateStatistics);

                    if (minificationResult.Errors.Count == 0)
                    {
                        if (_options.IsPoweredByHttpHeadersEnabled())
                        {
                            _currentMinificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
                        }
                        responseHeaders.Remove(HeaderNames.ContentMD5);

                        string processedContent   = minificationResult.MinifiedContent;
                        var    byteArrayPool      = ArrayPool <byte> .Shared;
                        int    processedByteCount = encoding.GetByteCount(processedContent);
                        byte[] processedBytes     = byteArrayPool.Rent(processedByteCount);

                        try
                        {
                            encoding.GetBytes(processedContent, 0, processedContent.Length, processedBytes, 0);

                            if (_compressionEnabled)
                            {
                                _currentCompressor.AppendHttpHeaders(appendHttpHeader);
                                responseHeaders.Remove(HeaderNames.ContentLength);
                                await _compressionStream.WriteAsync(processedBytes, 0, processedByteCount);
                            }
                            else
                            {
                                responseHeaders[HeaderNames.ContentLength] = processedByteCount.ToString();
                                await _originalStream.WriteAsync(processedBytes, 0, processedByteCount);
                            }
                        }
                        finally
                        {
                            byteArrayPool.Return(processedBytes);
                        }

                        isMinified = true;
                    }
                }

                if (!isMinified)
                {
                    Stream outputStream;

                    if (_compressionEnabled)
                    {
                        outputStream = _compressionStream;
                        _currentCompressor.AppendHttpHeaders(appendHttpHeader);
                    }
                    else
                    {
                        outputStream = _originalStream;
                    }

                    _cachedStream.Seek(0, SeekOrigin.Begin);
                    await _cachedStream.CopyToAsync(outputStream);
                }

                _cachedStream.Clear();
            }
        }