From 8fcd5efa61f76e1b7689ec86a492bc9521fdbb8b Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Fri, 3 Nov 2023 10:35:38 -0400 Subject: [PATCH 01/16] Stubs out filters --- .../jinjava/lib/filter/CloseHtmlFilter.java | 32 +++++++++++++++++++ .../jinjava/lib/filter/RenderFilter.java | 6 ++++ 2 files changed, 38 insertions(+) create mode 100644 src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java new file mode 100644 index 000000000..4f436145f --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java @@ -0,0 +1,32 @@ +package com.hubspot.jinjava.lib.filter; + +import com.hubspot.jinjava.doc.annotations.JinjavaDoc; +import com.hubspot.jinjava.doc.annotations.JinjavaParam; +import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; +import com.hubspot.jinjava.interpret.JinjavaInterpreter; + +@JinjavaDoc( + value = "Closes open HTML tags in a string", + input = @JinjavaParam(value = "s", desc = "String to close", required = true), + snippets = { + @JinjavaSnippet( + code = "{{ \"

Hello, world\"|closehtml }}" + ) + } +) +public class CloseHtmlFilter implements Filter{ + + @Override + public String getName() { + return "render"; + } + + @Override + public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { + /* + Closes open HTML tags. + */ + + return null; + } +} diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java index c257815a3..c6d0c9659 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java @@ -24,6 +24,12 @@ public String getName() { @Override public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { + if (args.length > 0) { + /* + This means a render limit length has been provided. + Here we begin a left to right render where we add to an HTML string until the length reaches a certain limit. + */ + } return interpreter.render(Objects.toString(var)); } } From bfb78f5a5b83c06e2692aabb03cac86206c02d2c Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Mon, 6 Nov 2023 13:08:20 -0500 Subject: [PATCH 02/16] Turned on prettier and changed filter name --- .../hubspot/jinjava/lib/filter/CloseHtmlFilter.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java index 4f436145f..df7526d2e 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java @@ -8,17 +8,13 @@ @JinjavaDoc( value = "Closes open HTML tags in a string", input = @JinjavaParam(value = "s", desc = "String to close", required = true), - snippets = { - @JinjavaSnippet( - code = "{{ \"

Hello, world\"|closehtml }}" - ) - } + snippets = { @JinjavaSnippet(code = "{{ \"

Hello, world\"|closehtml }}") } ) -public class CloseHtmlFilter implements Filter{ +public class CloseHtmlFilter implements Filter { @Override public String getName() { - return "render"; + return "closehtml"; } @Override From 87e6a0ea3abe362a8f3c75a44d7a4203e6277c5b Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Mon, 6 Nov 2023 13:11:37 -0500 Subject: [PATCH 03/16] Stubbed out if case statement --- src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java index c6d0c9659..63dd8225c 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java @@ -29,6 +29,7 @@ public Object filter(Object var, JinjavaInterpreter interpreter, String... args) This means a render limit length has been provided. Here we begin a left to right render where we add to an HTML string until the length reaches a certain limit. */ + return interpreter.render(Objects.toString(var)); } return interpreter.render(Objects.toString(var)); } From baae46e0101cf01b1c06c25cdfe1f7f986338e72 Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Tue, 7 Nov 2023 13:17:45 -0500 Subject: [PATCH 04/16] Using max output param to clamp outputs --- .../jinjava/interpret/JinjavaInterpreter.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index d58483865..bc5c51ee1 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -94,6 +94,7 @@ public class JinjavaInterpreter implements PyishSerializable { private final Set errorSet = new HashSet<>(); private static final int MAX_ERROR_SIZE = 100; + private static final long NO_LIMIT = -1; public JinjavaInterpreter( Jinjava application, @@ -263,14 +264,38 @@ public String render(String template) { } /** - * Render the given root node, processing extend parents. Equivalent to render(root, true) + * Render the given root node, processing extend parents. Equivalent to render(root, true, -1) * * @param root * node to render * @return rendered result */ public String render(Node root) { - return render(root, true); + return render(root, true, NO_LIMIT); + } + + /** + * Render the given root node with an option to process extend parents. + * Equivalent to render(root, processExtendRoots, -1). + * @param root + * node to render + * @param processExtendRoots + * @return + */ + public String render(Node root, boolean processExtendRoots) { + return render(root, processExtendRoots, NO_LIMIT); + } + + /** + * Rendee the given root node to a certain limit, processing extend parents. + * @param root + * node to render + * @param renderLimit + * the number of characters in response text + * @return + */ + public String render(Node root, long renderLimit) { + return render(root, true, renderLimit); } /** @@ -280,10 +305,15 @@ public String render(Node root) { * node to render * @param processExtendRoots * if true, also render all extend parents + * @param renderLimit + * the number of characters the result may contain * @return rendered result */ - public String render(Node root, boolean processExtendRoots) { - OutputList output = new OutputList(config.getMaxOutputSize()); + public String render(Node root, boolean processExtendRoots, long renderLimit) { + long maxOutput = (renderLimit == NO_LIMIT) + ? config.getMaxOutputSize() + : (Math.min(renderLimit, config.getMaxOutputSize())); + OutputList output = new OutputList(maxOutput); for (Node node : root.getChildren()) { lineNumber = node.getLineNumber(); From 0a82efb1ecf38fb245fa77ee936cdfb3009ad002 Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Tue, 7 Nov 2023 13:33:31 -0500 Subject: [PATCH 05/16] Calls new render limit method from filter --- .../hubspot/jinjava/interpret/JinjavaInterpreter.java | 11 ++++++++--- .../com/hubspot/jinjava/lib/filter/RenderFilter.java | 11 ++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index bc5c51ee1..d46568fc2 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -75,6 +75,8 @@ public class JinjavaInterpreter implements PyishSerializable { public static final String IGNORED_OUTPUT_FROM_EXTENDS_NOTE = "ignored_output_from_extends"; + public static final long NO_LIMIT = -1; + private final Multimap blocks = ArrayListMultimap.create(); private final LinkedList extendParentRoots = new LinkedList<>(); private final Map revertibleObjects = new HashMap<>(); @@ -94,7 +96,6 @@ public class JinjavaInterpreter implements PyishSerializable { private final Set errorSet = new HashSet<>(); private static final int MAX_ERROR_SIZE = 100; - private static final long NO_LIMIT = -1; public JinjavaInterpreter( Jinjava application, @@ -260,7 +261,11 @@ public String renderFlat(String template) { * @return rendered result */ public String render(String template) { - return render(parse(template), true); + return render(template, NO_LIMIT); + } + + public String render(String template, long renderLimit) { + return render(parse(template), true, renderLimit); } /** @@ -287,7 +292,7 @@ public String render(Node root, boolean processExtendRoots) { } /** - * Rendee the given root node to a certain limit, processing extend parents. + * Render the given root node to a certain limit, processing extend parents. * @param root * node to render * @param renderLimit diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java index 63dd8225c..1a2809e5a 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java @@ -5,6 +5,7 @@ import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; import com.hubspot.jinjava.interpret.JinjavaInterpreter; import java.util.Objects; +import org.apache.commons.lang3.math.NumberUtils; @JinjavaDoc( value = "Renders a template string early to be used by other filters and functions", @@ -25,11 +26,11 @@ public String getName() { @Override public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { if (args.length > 0) { - /* - This means a render limit length has been provided. - Here we begin a left to right render where we add to an HTML string until the length reaches a certain limit. - */ - return interpreter.render(Objects.toString(var)); + String firstArg = args[0]; + return interpreter.render( + Objects.toString(var), + NumberUtils.toLong(firstArg, JinjavaInterpreter.NO_LIMIT) + ); } return interpreter.render(Objects.toString(var)); } From 0e4692af1053e9fc4e0fdd31b509c247d37c144b Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Tue, 7 Nov 2023 14:05:28 -0500 Subject: [PATCH 06/16] Basic functionality working with two tests --- .../jinjava/interpret/JinjavaInterpreter.java | 18 ++++++------------ .../jinjava/lib/filter/RenderFilter.java | 5 +---- .../jinjava/lib/filter/RenderFilterTest.java | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index d46568fc2..2e66bd233 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -75,8 +75,6 @@ public class JinjavaInterpreter implements PyishSerializable { public static final String IGNORED_OUTPUT_FROM_EXTENDS_NOTE = "ignored_output_from_extends"; - public static final long NO_LIMIT = -1; - private final Multimap blocks = ArrayListMultimap.create(); private final LinkedList extendParentRoots = new LinkedList<>(); private final Map revertibleObjects = new HashMap<>(); @@ -261,7 +259,7 @@ public String renderFlat(String template) { * @return rendered result */ public String render(String template) { - return render(template, NO_LIMIT); + return render(template, config.getMaxOutputSize()); } public String render(String template, long renderLimit) { @@ -276,7 +274,7 @@ public String render(String template, long renderLimit) { * @return rendered result */ public String render(Node root) { - return render(root, true, NO_LIMIT); + return render(root, true, config.getMaxOutputSize()); } /** @@ -288,7 +286,7 @@ public String render(Node root) { * @return */ public String render(Node root, boolean processExtendRoots) { - return render(root, processExtendRoots, NO_LIMIT); + return render(root, processExtendRoots, config.getMaxOutputSize()); } /** @@ -315,11 +313,7 @@ public String render(Node root, long renderLimit) { * @return rendered result */ public String render(Node root, boolean processExtendRoots, long renderLimit) { - long maxOutput = (renderLimit == NO_LIMIT) - ? config.getMaxOutputSize() - : (Math.min(renderLimit, config.getMaxOutputSize())); - OutputList output = new OutputList(maxOutput); - + OutputList output = new OutputList(renderLimit); for (Node node : root.getChildren()) { lineNumber = node.getLineNumber(); position = node.getStartPosition(); @@ -375,8 +369,8 @@ public String render(Node root, boolean processExtendRoots, long renderLimit) { return output.getValue(); } } - StringBuilder ignoredOutput = new StringBuilder(); + StringBuilder ignoredOutput = new StringBuilder(); // render all extend parents, keeping the last as the root output if (processExtendRoots) { Set extendPaths = new HashSet<>(); @@ -441,6 +435,7 @@ public String render(Node root, boolean processExtendRoots, long renderLimit) { } resolveBlockStubs(output); + if (ignoredOutput.length() > 0) { return ( EagerReconstructionUtils.labelWithNotes( @@ -456,7 +451,6 @@ public String render(Node root, boolean processExtendRoots, long renderLimit) { output.getValue() ); } - return output.getValue(); } diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java index 1a2809e5a..405148d40 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java @@ -27,10 +27,7 @@ public String getName() { public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { if (args.length > 0) { String firstArg = args[0]; - return interpreter.render( - Objects.toString(var), - NumberUtils.toLong(firstArg, JinjavaInterpreter.NO_LIMIT) - ); + return interpreter.render(Objects.toString(var), NumberUtils.toLong(firstArg, 0)); } return interpreter.render(Objects.toString(var)); } diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java index 04e238b7a..bd5e80011 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java @@ -20,4 +20,18 @@ public void itRendersObject() { assertThat(filter.filter(stringToRender, interpreter)).isEqualTo("world"); } + + @Test + public void itRendersObjectWithinLimit() { + String stringToRender = "{% if null %}Hello{% else %}world{% endif %}"; + + assertThat(filter.filter(stringToRender, interpreter, "5")).isEqualTo("world"); + } + + @Test + public void itDoesNotRenderObjectOverLimit() { + String stringToRender = "{% if null %}Hello{% else %}world{% endif %}"; + + assertThat(filter.filter(stringToRender, interpreter, "4")).isEqualTo(""); + } } From be44efa67ed9176f12c94c0bb762c29a954eacbb Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Tue, 7 Nov 2023 15:37:12 -0500 Subject: [PATCH 07/16] Added two more tests --- .../jinjava/lib/filter/RenderFilterTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java index bd5e80011..5e279e204 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java @@ -34,4 +34,19 @@ public void itDoesNotRenderObjectOverLimit() { assertThat(filter.filter(stringToRender, interpreter, "4")).isEqualTo(""); } + + @Test + public void itRendersPartialObjectOverLimit() { + String stringToRender = "Hello{% if null %}Hello{% else %}world{% endif %}"; + + assertThat(filter.filter(stringToRender, interpreter, "7")).isEqualTo("Hello"); + } + + @Test + public void itCountsHtmlTags() { + String stringToRender = "

Hello

{% if null %}Hello{% else %}world{% endif %}"; + + assertThat(filter.filter(stringToRender, interpreter, "15")) + .isEqualTo("

Hello

"); + } } From 630768f53777be5c7801bf7a35ecd5a90c9fb274 Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Tue, 14 Nov 2023 16:09:59 -0500 Subject: [PATCH 08/16] Removed close html filter because limited rendering works on whole HTML nodes --- .../jinjava/lib/filter/CloseHtmlFilter.java | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java deleted file mode 100644 index df7526d2e..000000000 --- a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.hubspot.jinjava.lib.filter; - -import com.hubspot.jinjava.doc.annotations.JinjavaDoc; -import com.hubspot.jinjava.doc.annotations.JinjavaParam; -import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; -import com.hubspot.jinjava.interpret.JinjavaInterpreter; - -@JinjavaDoc( - value = "Closes open HTML tags in a string", - input = @JinjavaParam(value = "s", desc = "String to close", required = true), - snippets = { @JinjavaSnippet(code = "{{ \"

Hello, world\"|closehtml }}") } -) -public class CloseHtmlFilter implements Filter { - - @Override - public String getName() { - return "closehtml"; - } - - @Override - public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { - /* - Closes open HTML tags. - */ - - return null; - } -} From 16fb43f71a0ed008f40b368a4bda5fe7b3c9961e Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Tue, 14 Nov 2023 16:16:15 -0500 Subject: [PATCH 09/16] Added back closehtml filter and test case that demonstrates it --- .../jinjava/lib/filter/CloseHtmlFilter.java | 28 +++++++++++++++++++ .../jinjava/lib/filter/RenderFilterTest.java | 9 ++++++ 2 files changed, 37 insertions(+) create mode 100644 src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java new file mode 100644 index 000000000..df7526d2e --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java @@ -0,0 +1,28 @@ +package com.hubspot.jinjava.lib.filter; + +import com.hubspot.jinjava.doc.annotations.JinjavaDoc; +import com.hubspot.jinjava.doc.annotations.JinjavaParam; +import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; +import com.hubspot.jinjava.interpret.JinjavaInterpreter; + +@JinjavaDoc( + value = "Closes open HTML tags in a string", + input = @JinjavaParam(value = "s", desc = "String to close", required = true), + snippets = { @JinjavaSnippet(code = "{{ \"

Hello, world\"|closehtml }}") } +) +public class CloseHtmlFilter implements Filter { + + @Override + public String getName() { + return "closehtml"; + } + + @Override + public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { + /* + Closes open HTML tags. + */ + + return null; + } +} diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java index 5e279e204..156720a10 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/RenderFilterTest.java @@ -49,4 +49,13 @@ public void itCountsHtmlTags() { assertThat(filter.filter(stringToRender, interpreter, "15")) .isEqualTo("

Hello

"); } + + @Test + public void itDoesNotAlwaysCompleteHtmlTags() { + String stringToRender = + "

Hello, {% if null %}world{% else %}world!{% endif %}

"; + + assertThat(filter.filter(stringToRender, interpreter, "17")) + .isEqualTo("

Hello, world!"); + } } From daf2c8488644dd813f5d0158aac1f5f7192ece12 Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Wed, 15 Nov 2023 13:12:56 -0500 Subject: [PATCH 10/16] Added close html filter implementation with Jsoup --- .../jinjava/lib/filter/CloseHtmlFilter.java | 8 +++---- .../lib/filter/CloseHtmlFilterTest.java | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java index df7526d2e..07368b341 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java @@ -4,6 +4,8 @@ import com.hubspot.jinjava.doc.annotations.JinjavaParam; import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; import com.hubspot.jinjava.interpret.JinjavaInterpreter; +import java.util.Objects; +import org.jsoup.Jsoup; @JinjavaDoc( value = "Closes open HTML tags in a string", @@ -19,10 +21,6 @@ public String getName() { @Override public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { - /* - Closes open HTML tags. - */ - - return null; + return Jsoup.parse(Objects.toString(var)).toString(); } } diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java new file mode 100644 index 000000000..ea20539ce --- /dev/null +++ b/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java @@ -0,0 +1,24 @@ +package com.hubspot.jinjava.lib.filter; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.common.collect.ImmutableMap; +import com.hubspot.jinjava.BaseInterpretingTest; +import com.hubspot.jinjava.BaseJinjavaTest; +import org.junit.Before; +import org.junit.Test; + +public class CloseHtmlFilterTest extends BaseInterpretingTest { + CloseHtmlFilter f; + + @Before + public void setup() { + f = new CloseHtmlFilter(); + } + + @Test + public void itClosesTags() { + String openTags = "

Hello, world!"; + assertThat(f.filter(openTags, interpreter)).isEqualTo("

Hello, world!

"); + } +} From b4c604ffcb729b1431e22c8000bb0593e33200cc Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Wed, 15 Nov 2023 13:37:57 -0500 Subject: [PATCH 11/16] Using document traversal to close HTML tags --- .../hubspot/jinjava/lib/filter/CloseHtmlFilter.java | 3 ++- .../jinjava/lib/filter/CloseHtmlFilterTest.java | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java index 07368b341..382f14f79 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java @@ -6,6 +6,7 @@ import com.hubspot.jinjava.interpret.JinjavaInterpreter; import java.util.Objects; import org.jsoup.Jsoup; +import org.jsoup.safety.Safelist; @JinjavaDoc( value = "Closes open HTML tags in a string", @@ -21,6 +22,6 @@ public String getName() { @Override public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { - return Jsoup.parse(Objects.toString(var)).toString(); + return Jsoup.parseBodyFragment(Objects.toString(var)).body().html(); } } diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java index ea20539ce..9e7d4ef44 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java @@ -21,4 +21,17 @@ public void itClosesTags() { String openTags = "

Hello, world!"; assertThat(f.filter(openTags, interpreter)).isEqualTo("

Hello, world!

"); } + + @Test + public void itIgnoresClosedTags() { + String openTags = "

Hello, world!

"; + assertThat(f.filter(openTags, interpreter)).isEqualTo("

Hello, world!

"); + } + + @Test + public void itClosesMultipleTags() { + String openTags = "

Hello, world!"; + assertThat(f.filter(openTags, interpreter)) + .isEqualTo("

Hello, world!

"); + } } From 09f051b8ebcb55cd6e1b3f04dc8becc37237cf1e Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Wed, 15 Nov 2023 14:05:13 -0500 Subject: [PATCH 12/16] Removed references to safelist for Jsoup --- .../java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java | 1 - .../com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java index 382f14f79..f15315bd8 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilter.java @@ -6,7 +6,6 @@ import com.hubspot.jinjava.interpret.JinjavaInterpreter; import java.util.Objects; import org.jsoup.Jsoup; -import org.jsoup.safety.Safelist; @JinjavaDoc( value = "Closes open HTML tags in a string", diff --git a/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java b/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java index 9e7d4ef44..4b7f3be51 100644 --- a/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java +++ b/src/test/java/com/hubspot/jinjava/lib/filter/CloseHtmlFilterTest.java @@ -2,9 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.google.common.collect.ImmutableMap; import com.hubspot.jinjava.BaseInterpretingTest; -import com.hubspot.jinjava.BaseJinjavaTest; import org.junit.Before; import org.junit.Test; From 38b50a5902272890ae4b601732cea18f7d7cf681 Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Thu, 16 Nov 2023 13:19:57 -0500 Subject: [PATCH 13/16] Removed unnecessary method and formalized default case for non-number args --- .../jinjava/interpret/JinjavaInterpreter.java | 18 +++--------------- .../jinjava/lib/filter/RenderFilter.java | 9 ++++++++- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index 2e66bd233..d127f597d 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -267,7 +267,7 @@ public String render(String template, long renderLimit) { } /** - * Render the given root node, processing extend parents. Equivalent to render(root, true, -1) + * Render the given root node, processing extend parents. Equivalent to render(root, true) * * @param root * node to render @@ -279,7 +279,7 @@ public String render(Node root) { /** * Render the given root node with an option to process extend parents. - * Equivalent to render(root, processExtendRoots, -1). + * Equivalent to render(root, processExtendRoots). * @param root * node to render * @param processExtendRoots @@ -289,18 +289,6 @@ public String render(Node root, boolean processExtendRoots) { return render(root, processExtendRoots, config.getMaxOutputSize()); } - /** - * Render the given root node to a certain limit, processing extend parents. - * @param root - * node to render - * @param renderLimit - * the number of characters in response text - * @return - */ - public String render(Node root, long renderLimit) { - return render(root, true, renderLimit); - } - /** * Render the given root node using this interpreter's current context * @@ -312,7 +300,7 @@ public String render(Node root, long renderLimit) { * the number of characters the result may contain * @return rendered result */ - public String render(Node root, boolean processExtendRoots, long renderLimit) { + private String render(Node root, boolean processExtendRoots, long renderLimit) { OutputList output = new OutputList(renderLimit); for (Node node : root.getChildren()) { lineNumber = node.getLineNumber(); diff --git a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java index 405148d40..4cd6763cb 100644 --- a/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java +++ b/src/main/java/com/hubspot/jinjava/lib/filter/RenderFilter.java @@ -1,5 +1,6 @@ package com.hubspot.jinjava.lib.filter; +import com.hubspot.jinjava.JinjavaConfig; import com.hubspot.jinjava.doc.annotations.JinjavaDoc; import com.hubspot.jinjava.doc.annotations.JinjavaParam; import com.hubspot.jinjava.doc.annotations.JinjavaSnippet; @@ -27,7 +28,13 @@ public String getName() { public Object filter(Object var, JinjavaInterpreter interpreter, String... args) { if (args.length > 0) { String firstArg = args[0]; - return interpreter.render(Objects.toString(var), NumberUtils.toLong(firstArg, 0)); + return interpreter.render( + Objects.toString(var), + NumberUtils.toLong( + firstArg, + JinjavaConfig.newBuilder().build().getMaxOutputSize() + ) + ); } return interpreter.render(Objects.toString(var)); } From 4e2e4a1779394d0973e0a470ef81d7dd7c673517 Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Thu, 16 Nov 2023 17:06:45 -0500 Subject: [PATCH 14/16] Clamp output size to config max if not 0 --- .../com/hubspot/jinjava/interpret/JinjavaInterpreter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index d127f597d..1fb6a5e94 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -301,7 +301,10 @@ public String render(Node root, boolean processExtendRoots) { * @return rendered result */ private String render(Node root, boolean processExtendRoots, long renderLimit) { - OutputList output = new OutputList(renderLimit); + long safeRenderSize = (config.getMaxOutputSize() == 0) + ? renderLimit + : Math.min(renderLimit, config.getMaxOutputSize()); + OutputList output = new OutputList(safeRenderSize); for (Node node : root.getChildren()) { lineNumber = node.getLineNumber(); position = node.getStartPosition(); From 254d5fc75cf402691a6d69fa889564615c92c352 Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Mon, 20 Nov 2023 17:32:34 -0500 Subject: [PATCH 15/16] Added safer limit clamping function --- .../jinjava/interpret/JinjavaInterpreter.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index 1fb6a5e94..1bb10fad0 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -301,10 +301,7 @@ public String render(Node root, boolean processExtendRoots) { * @return rendered result */ private String render(Node root, boolean processExtendRoots, long renderLimit) { - long safeRenderSize = (config.getMaxOutputSize() == 0) - ? renderLimit - : Math.min(renderLimit, config.getMaxOutputSize()); - OutputList output = new OutputList(safeRenderSize); + OutputList output = new OutputList(clampOutputSizeSafely(renderLimit)); for (Node node : root.getChildren()) { lineNumber = node.getLineNumber(); position = node.getStartPosition(); @@ -927,6 +924,20 @@ private String getWrappedErrorMessage( } } + private long clampOutputSizeSafely(long providedLimit) { + long configMaxOutput = config.getMaxOutputSize(); + + if (configMaxOutput == 0) { + return providedLimit; + } + + if (providedLimit <= 0) { + return configMaxOutput; + } + + return Math.min(providedLimit, configMaxOutput); + } + @Override @SuppressWarnings("unchecked") public T appendPyishString(T appendable) From 10b4ff64b628b32236a54037eb03b12c0e0898ee Mon Sep 17 00:00:00 2001 From: Aaron Segal Date: Tue, 21 Nov 2023 16:10:40 -0500 Subject: [PATCH 16/16] Extracted clamp to helper class with tests and fixed negative config bug --- .../jinjava/interpret/JinjavaInterpreter.java | 19 ++------ .../jinjava/util/RenderLimitUtils.java | 23 ++++++++++ .../jinjava/util/RenderLimitUtilsTest.java | 46 +++++++++++++++++++ 3 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/hubspot/jinjava/util/RenderLimitUtils.java create mode 100644 src/test/java/com/hubspot/jinjava/util/RenderLimitUtilsTest.java diff --git a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java index 1bb10fad0..475355a16 100644 --- a/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java +++ b/src/main/java/com/hubspot/jinjava/interpret/JinjavaInterpreter.java @@ -50,6 +50,7 @@ import com.hubspot.jinjava.tree.output.OutputNode; import com.hubspot.jinjava.tree.output.RenderedOutputNode; import com.hubspot.jinjava.util.EagerReconstructionUtils; +import com.hubspot.jinjava.util.RenderLimitUtils; import com.hubspot.jinjava.util.Variable; import com.hubspot.jinjava.util.WhitespaceUtils; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -301,7 +302,9 @@ public String render(Node root, boolean processExtendRoots) { * @return rendered result */ private String render(Node root, boolean processExtendRoots, long renderLimit) { - OutputList output = new OutputList(clampOutputSizeSafely(renderLimit)); + OutputList output = new OutputList( + RenderLimitUtils.clampProvidedRenderLimitToConfig(renderLimit, config) + ); for (Node node : root.getChildren()) { lineNumber = node.getLineNumber(); position = node.getStartPosition(); @@ -924,20 +927,6 @@ private String getWrappedErrorMessage( } } - private long clampOutputSizeSafely(long providedLimit) { - long configMaxOutput = config.getMaxOutputSize(); - - if (configMaxOutput == 0) { - return providedLimit; - } - - if (providedLimit <= 0) { - return configMaxOutput; - } - - return Math.min(providedLimit, configMaxOutput); - } - @Override @SuppressWarnings("unchecked") public T appendPyishString(T appendable) diff --git a/src/main/java/com/hubspot/jinjava/util/RenderLimitUtils.java b/src/main/java/com/hubspot/jinjava/util/RenderLimitUtils.java new file mode 100644 index 000000000..61f2de594 --- /dev/null +++ b/src/main/java/com/hubspot/jinjava/util/RenderLimitUtils.java @@ -0,0 +1,23 @@ +package com.hubspot.jinjava.util; + +import com.hubspot.jinjava.JinjavaConfig; + +public class RenderLimitUtils { + + public static long clampProvidedRenderLimitToConfig( + long providedLimit, + JinjavaConfig jinjavaConfig + ) { + long configMaxOutput = jinjavaConfig.getMaxOutputSize(); + + if (configMaxOutput <= 0) { + return providedLimit; + } + + if (providedLimit <= 0) { + return configMaxOutput; + } + + return Math.min(providedLimit, configMaxOutput); + } +} diff --git a/src/test/java/com/hubspot/jinjava/util/RenderLimitUtilsTest.java b/src/test/java/com/hubspot/jinjava/util/RenderLimitUtilsTest.java new file mode 100644 index 000000000..898e5a40d --- /dev/null +++ b/src/test/java/com/hubspot/jinjava/util/RenderLimitUtilsTest.java @@ -0,0 +1,46 @@ +package com.hubspot.jinjava.util; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.hubspot.jinjava.JinjavaConfig; +import org.junit.Test; + +public class RenderLimitUtilsTest { + + @Test + public void itPicksLowerLimitWhenConfigIsSet() { + assertThat( + RenderLimitUtils.clampProvidedRenderLimitToConfig(100, configWithOutputSize(10)) + ) + .isEqualTo(10); + } + + @Test + public void itKeepsConfigLimitWhenConfigSetAndUnlimitedProvided() { + assertThat( + RenderLimitUtils.clampProvidedRenderLimitToConfig(0, configWithOutputSize(10)) + ) + .isEqualTo(10); + assertThat( + RenderLimitUtils.clampProvidedRenderLimitToConfig(-10, configWithOutputSize(10)) + ) + .isEqualTo(10); + } + + @Test + public void itUsesProvidedLimitWhenConfigIsUnlimited() { + assertThat( + RenderLimitUtils.clampProvidedRenderLimitToConfig(10, configWithOutputSize(0)) + ) + .isEqualTo(10); + + assertThat( + RenderLimitUtils.clampProvidedRenderLimitToConfig(10, configWithOutputSize(-10)) + ) + .isEqualTo(10); + } + + private JinjavaConfig configWithOutputSize(long size) { + return JinjavaConfig.newBuilder().withMaxOutputSize(size).build(); + } +}