This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new 96f986a Add extended option to trimSpaces 96f986a is described below commit 96f986a392f99c6f0d9fe3e18bc605a4f0e0a15d Author: Mark Thomas <ma...@apache.org> AuthorDate: Tue Mar 16 17:47:23 2021 +0000 Add extended option to trimSpaces --- java/org/apache/jasper/Options.java | 7 ++- java/org/apache/jasper/TrimSpacesOption.java | 3 +- java/org/apache/jasper/compiler/Compiler.java | 8 +++- java/org/apache/jasper/compiler/Generator.java | 22 +++++++++ .../compiler/NewlineReductionServletWriter.java | 54 ++++++++++++++++++++++ test/org/apache/jasper/compiler/TestGenerator.java | 52 ++++++++++++++++++++- test/webapp/jsp/trim-spaces-extended.jsp | 49 ++++++++++++++++++++ webapps/docs/changelog.xml | 7 +++ webapps/docs/jasper-howto.xml | 11 +++-- 9 files changed, 204 insertions(+), 9 deletions(-) diff --git a/java/org/apache/jasper/Options.java b/java/org/apache/jasper/Options.java index 248750a..32e59fd 100644 --- a/java/org/apache/jasper/Options.java +++ b/java/org/apache/jasper/Options.java @@ -101,8 +101,11 @@ public interface Options { * @return {@link TrimSpacesOption#TRUE} to remove template text that * consists only of whitespace from the output completely, * {@link TrimSpacesOption#SINGLE} to replace such template text - * with a single space or {@link TrimSpacesOption#FALSE} to leave - * such template text unchanged + * with a single space, {@link TrimSpacesOption#FALSE} to leave + * such template text unchanged or {@link TrimSpacesOption#EXTENDED} + * to remove template text that consists only of whitespace and to + * replace any sequence of whitespace and new lines within template + * text with a single new line. */ public TrimSpacesOption getTrimSpaces(); diff --git a/java/org/apache/jasper/TrimSpacesOption.java b/java/org/apache/jasper/TrimSpacesOption.java index faf7476..2890aa3 100644 --- a/java/org/apache/jasper/TrimSpacesOption.java +++ b/java/org/apache/jasper/TrimSpacesOption.java @@ -19,5 +19,6 @@ package org.apache.jasper; public enum TrimSpacesOption { FALSE, TRUE, - SINGLE + SINGLE, + EXTENDED } diff --git a/java/org/apache/jasper/compiler/Compiler.java b/java/org/apache/jasper/compiler/Compiler.java index 81c9fc1..ac6f321 100644 --- a/java/org/apache/jasper/compiler/Compiler.java +++ b/java/org/apache/jasper/compiler/Compiler.java @@ -32,6 +32,7 @@ import java.util.Map.Entry; import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; import org.apache.jasper.Options; +import org.apache.jasper.TrimSpacesOption; import org.apache.jasper.servlet.JspServletWrapper; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -316,7 +317,12 @@ public abstract class Compiler { javaEncoding); } - writer = new ServletWriter(new PrintWriter(osw)); + if ((ctxt!=null) && ctxt.getOptions().getTrimSpaces().equals(TrimSpacesOption.EXTENDED)) { + writer = new NewlineReductionServletWriter(new PrintWriter(osw)); + } else { + writer = new ServletWriter(new PrintWriter(osw)); + } + ctxt.setWriter(writer); return writer; } diff --git a/java/org/apache/jasper/compiler/Generator.java b/java/org/apache/jasper/compiler/Generator.java index 7be9edb..e51c93f 100644 --- a/java/org/apache/jasper/compiler/Generator.java +++ b/java/org/apache/jasper/compiler/Generator.java @@ -40,6 +40,8 @@ import java.util.Map.Entry; import java.util.Set; import java.util.TimeZone; import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.el.MethodExpression; import javax.el.ValueExpression; @@ -52,6 +54,7 @@ import org.apache.el.util.JreCompat; import org.apache.jasper.Constants; import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.TrimSpacesOption; import org.apache.jasper.compiler.Node.NamedAttribute; import org.apache.jasper.runtime.JspRuntimeLibrary; import org.xml.sax.Attributes; @@ -97,6 +100,10 @@ class Generator { "org.apache.jasper.compiler.Generator.STRICT_GET_PROPERTY", "true")); + private static final Pattern PRE_TAG_PATTERN = Pattern.compile("(?s).*(<pre>|</pre>).*"); + + private static final Pattern BLANK_LINE_PATTERN = Pattern.compile("(\\s*(\\n|\\r)+\\s*)"); + private final ServletWriter out; private final ArrayList<GenBuffer> methodsBuffered; @@ -2110,6 +2117,21 @@ class Generator { public void visit(Node.TemplateText n) throws JasperException { String text = n.getText(); + // If the extended option is being used attempt to minimize the + // frequency of regex operations. + if ((ctxt != null) && ctxt.getOptions().getTrimSpaces().equals(TrimSpacesOption.EXTENDED) && + text.contains("\n")) { + // Ensure there are no <pre> or </pre> tags embedded in this + // text - if there are, we want to NOT modify the whitespace. + Matcher preMatcher = PRE_TAG_PATTERN.matcher(text); + if (!preMatcher.matches()) { + Matcher matcher = BLANK_LINE_PATTERN.matcher(text); + String revisedText = matcher.replaceAll("\n"); + // Leading and trailing whitespace can be trimmed so remove + // it here as the regex won't remove it. + text = revisedText.trim(); + } + } int textSize = text.length(); if (textSize == 0) { diff --git a/java/org/apache/jasper/compiler/NewlineReductionServletWriter.java b/java/org/apache/jasper/compiler/NewlineReductionServletWriter.java new file mode 100644 index 0000000..ed6fbfe --- /dev/null +++ b/java/org/apache/jasper/compiler/NewlineReductionServletWriter.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.io.PrintWriter; + +/** + * This class filters duplicate newlines instructions from the compiler output, + * and therefore from the runtime JSP. The duplicates typically happen because + * the compiler has multiple branches that write them, but they operate + * independently and don't realize that the previous output was identical. + * + * Removing these lines makes the JSP more efficient by executing fewer + * operations during runtime. + */ +public class NewlineReductionServletWriter extends ServletWriter { + + private static final String NEWLINE_WRITE_TEXT = "out.write('\\n');"; + + private boolean lastWriteWasNewline; + + public NewlineReductionServletWriter(PrintWriter writer) { + super(writer); + } + + @Override + public void printil(String s) { + if (s.equals(NEWLINE_WRITE_TEXT)) { + if (lastWriteWasNewline) { + // do nothing + return; + } else { + lastWriteWasNewline = true; + } + } else { + lastWriteWasNewline = false; + } + super.printil(s); + } +} \ No newline at end of file diff --git a/test/org/apache/jasper/compiler/TestGenerator.java b/test/org/apache/jasper/compiler/TestGenerator.java index e370817..b28decc 100644 --- a/test/org/apache/jasper/compiler/TestGenerator.java +++ b/test/org/apache/jasper/compiler/TestGenerator.java @@ -17,8 +17,10 @@ package org.apache.jasper.compiler; +import java.io.File; import java.io.IOException; import java.util.Date; +import java.util.Scanner; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.JspException; @@ -30,8 +32,12 @@ import javax.servlet.jsp.tagext.VariableInfo; import org.junit.Assert; import org.junit.Test; +import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; +import org.apache.catalina.Wrapper; +import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.jasper.servlet.JasperInitializer; import org.apache.tomcat.util.buf.ByteChunk; public class TestGenerator extends TomcatBaseTest { @@ -212,7 +218,7 @@ public class TestGenerator extends TomcatBaseTest { response.contains("[1:attribute1: '', attribute2: '']")); Assert.assertTrue(response, response.contains("[2:attribute1: '', attribute2: '']")); - } + } public static class Bug56529 extends TagSupport { @@ -285,4 +291,48 @@ public class TestGenerator extends TomcatBaseTest { System.out.println(result); assertEcho(result, "ASYNC"); } + + @Test + public void testTrimSpacesExtended01() throws Exception { + doTestTrimSpacesExtended(false); + } + + @Test + public void testTrimSpacesExtended02() throws Exception { + doTestTrimSpacesExtended(true); + } + + private void doTestTrimSpacesExtended(boolean removeBlankLines) throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp"); + Context ctxt = tomcat.addContext("", appDir.getAbsolutePath()); + ctxt.addServletContainerInitializer(new JasperInitializer(), null); + + Tomcat.initWebappDefaults(ctxt); + Wrapper w = (Wrapper) ctxt.findChild("jsp"); + if (removeBlankLines) { + w.addInitParameter("trimSpaces", "extended"); + } + + tomcat.start(); + + ByteChunk res = getUrl("http://localhost:" + getPort() + "/jsp/trim-spaces-extended.jsp"); + + String result = res.toString(); + Scanner scanner = new Scanner(result); + int blankLineCount = 0; + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.length() == 0) { + blankLineCount++; + } + } + if (!removeBlankLines && blankLineCount == 0) { + Assert.fail("TrimSpaceOptions.EXTENDED not configured but balnk lines have been removed"); + } else if (removeBlankLines && blankLineCount > 0) { + Assert.fail("TrimSpaceOptions.EXTENDED does not allow the line to be just a new line character"); + } + scanner.close(); + } } diff --git a/test/webapp/jsp/trim-spaces-extended.jsp b/test/webapp/jsp/trim-spaces-extended.jsp new file mode 100644 index 0000000..817f44f --- /dev/null +++ b/test/webapp/jsp/trim-spaces-extended.jsp @@ -0,0 +1,49 @@ +<%-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--%> +<!doctype html> +<html> +<head> + <title>Apache Tomcat JSP White Space Trim Optimisation Configuration</title> +</head> +<body> + + + +<h4>Apache Tomcat JSP white space trim test page</h4> +<p>If the value of init param jspWhiteSpaceTrimming is set to true, the compiler +trims all the excess white spaces and empty line characters from the JSP files +and thus reduces build size.</p> + + + + + + + + + + + + + + + + + + +</body> +</html> \ No newline at end of file diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 777f9f8..bad4825 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -142,6 +142,13 @@ the list of OSGi exported packages for the Jasper embedded JAR. Patch provided by Sokratis Zappis. (markt) </fix> + <add> + Add a new option for the <code>trimSpaces</code> configuration. + <code>extended</code> will attempt to remove leading and trailing + whitespace from template text and collapse sequences of whitespace and + newlines within template text into a single new line. Based on a pull + request by kamnani. (markt) + </add> </changelog> </subsection> </section> diff --git a/webapps/docs/jasper-howto.xml b/webapps/docs/jasper-howto.xml index 5efee11..c111074 100644 --- a/webapps/docs/jasper-howto.xml +++ b/webapps/docs/jasper-howto.xml @@ -193,10 +193,13 @@ debugging be suppressed? <code>true</code> or <code>false</code>, default <li><strong>trimSpaces</strong> - Should template text that consists entirely of whitespace be removed from the output (<code>true</code>), replaced with a -single space (<code>single</code>) or left unchanged (<code>false</code>)? Note -that if a JSP page or tag file specifies a <code>trimDirectiveWhitespaces</code> -value of <code>true</code>, that will take precedence over this configuration -setting for that page/tag. Default <code>false</code>.</li> +single space (<code>single</code>) or left unchanged (<code>false</code>)? +Alternatively, the <code>extended</code> option will remove leading and trailing +whitespace from template text and collapse sequences of whitespace and newlines +within the template text to a single new line. Note that if a JSP page or tag +file specifies a <code>trimDirectiveWhitespaces</code> value of +<code>true</code>, that will take precedence over this configuration setting for +that page/tag. Default <code>false</code>.</li> <li><strong>xpoweredBy</strong> - Determines whether X-Powered-By response header is added by generated servlet. <code>true</code> or <code>false</code>, --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org