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); } }
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); } }
/// <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); }
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); }
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(); }
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); }
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); } }
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(); } }