Skip to content

Commit cb1d656

Browse files
committed
Validate Jiffle input variable names according to grammar, escape javadocs when including Jiffle sources in output
1 parent 8d2ab59 commit cb1d656

File tree

4 files changed

+188
-18
lines changed

4 files changed

+188
-18
lines changed

jt-jiffle/jt-jiffle-language/src/main/java/it/geosolutions/jaiext/jiffle/Jiffle.java

+30-14
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public class Jiffle {
128128

129129
public static final Logger LOGGER = Logger.getLogger(Jiffle.class.getName());
130130

131-
private static Pattern BLOCK_COMMENT_STRIPPER = Pattern.compile("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)");
131+
boolean includeScript;
132132

133133
/**
134134
* Constants for runtime model. Jiffle supports two runtime models:
@@ -272,7 +272,20 @@ public Jiffle(File scriptFile, Map<String, Jiffle.ImageRole> params)
272272
setImageParams(params);
273273
compile();
274274
}
275-
275+
276+
/**
277+
* Returns true if the script is to be included in the output
278+
*
279+
* @return
280+
*/
281+
public boolean isIncludeScript() {
282+
return includeScript;
283+
}
284+
285+
public void setIncludeScript(boolean includeScript) {
286+
this.includeScript = includeScript;
287+
}
288+
276289
/**
277290
* Sets the script. Calling this method will clear any previous script
278291
* and runtime objects.
@@ -481,7 +494,7 @@ public JiffleDirectRuntime getRuntimeInstance() throws
481494
*/
482495
public JiffleRuntime getRuntimeInstance(Jiffle.RuntimeModel model) throws
483496
it.geosolutions.jaiext.jiffle.JiffleException {
484-
return createRuntimeInstance(model, getRuntimeBaseClass(model), false);
497+
return createRuntimeInstance(model, getRuntimeBaseClass(model), includeScript);
485498
}
486499

487500
/**
@@ -512,7 +525,7 @@ public <T extends JiffleRuntime> T getRuntimeInstance(Class<T> baseClass) throws
512525
" does not implement a required Jiffle runtime interface");
513526
}
514527

515-
return (T) createRuntimeInstance(model, baseClass, false);
528+
return (T) createRuntimeInstance(model, baseClass, includeScript);
516529
}
517530

518531
private JiffleRuntime createRuntimeInstance(RuntimeModel model, Class<? extends JiffleRuntime> runtimeClass, boolean scriptInDocs) throws
@@ -558,7 +571,14 @@ private JiffleRuntime createRuntimeInstance(RuntimeModel model, Class<? extends
558571
return runtime;
559572

560573
} catch (Exception ex) {
561-
throw new it.geosolutions.jaiext.jiffle.JiffleException("Runtime source error for source: " + runtimeSource, ex);
574+
// do not display the source code in indirect runtime exception messages
575+
if (model == RuntimeModel.INDIRECT) {
576+
if (LOGGER.isLoggable(Level.FINE)) {
577+
LOGGER.fine("Runtime source error for source: " + runtimeSource);
578+
}
579+
throw new JiffleException("Runtime source error", ex);
580+
}
581+
throw new JiffleException("Runtime source error for source: " + runtimeSource, ex);
562582
}
563583
}
564584

@@ -613,22 +633,17 @@ private Class<? extends JiffleRuntime> getRuntimeBaseClass(RuntimeModel model) {
613633
return baseClass;
614634
}
615635

616-
private String createRuntimeSource(RuntimeModel model, String baseClassName, boolean scriptInDocs) {
636+
private String createRuntimeSource(RuntimeModel model, String baseClassName,
637+
boolean scriptInDocs) {
638+
SourceWriter writer = new SourceWriter(model);
617639
if (scriptInDocs) {
618-
throw new RuntimeException("Do no know how to clean the block comments yet");
640+
writer.setScript(theScript);
619641
}
620-
621-
SourceWriter writer = new SourceWriter(model);
622-
writer.setScript(stripComments(theScript));
623642
writer.setBaseClassName(baseClassName);
624643
scriptModel.write(writer);
625644
return writer.getSource();
626645
}
627646

628-
private String stripComments(String theScript) {
629-
return BLOCK_COMMENT_STRIPPER.matcher(theScript).replaceAll("");
630-
}
631-
632647
/**
633648
* Initializes this object's name and runtime base class.
634649
*/
@@ -648,6 +663,7 @@ private void clearCompiledObjects() {
648663

649664
/**
650665
* Builds the parse tree from the script.
666+
*
651667
* @param script
652668
*/
653669
private static Jiffle.Result<ParseTree> parseScript(String script) {

jt-jiffle/jt-jiffle-language/src/main/java/it/geosolutions/jaiext/jiffle/parser/node/Script.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,17 @@
5252
import it.geosolutions.jaiext.jiffle.parser.UndefinedOptionException;
5353

5454
import java.util.Collections;
55-
import java.util.List;
5655
import java.util.Map;
5756
import java.util.Objects;
5857
import java.util.Set;
58+
import java.util.regex.Pattern;
5959

6060
/** @author michael */
6161
public class Script implements Node {
62+
63+
/** <pre>ID : (Letter) (Letter | UNDERSCORE | Digit | Dot)*</pre> */
64+
private static final Pattern VALID_IDENTIFIER = Pattern.compile("^[a-zA-Z][_a-zA-Z0-9\\.]*$");
65+
6266
private final StatementList stmts;
6367
private final RepeatedReadOptimizer readOptimizer;
6468
private Map<String, String> options;
@@ -79,6 +83,20 @@ public Script(
7983
this.globals = globals;
8084
this.stmts = stmts;
8185
this.readOptimizer = readOptimizer;
86+
validate();
87+
}
88+
89+
private void validate() {
90+
for (String name : sourceImages) {
91+
if (!VALID_IDENTIFIER.matcher(name).matches()) {
92+
throw new JiffleParserException("Invalid source image name: " + name);
93+
}
94+
}
95+
for (String name : destImages) {
96+
if (!VALID_IDENTIFIER.matcher(name).matches()) {
97+
throw new JiffleParserException("Invalid dest image name: " + name);
98+
}
99+
}
82100
}
83101

84102
public void write(SourceWriter w) {
@@ -97,11 +115,13 @@ public void write(SourceWriter w) {
97115
String[] lines = script.split("\n");
98116
w.line("/**");
99117
w.line(" * Java runtime class generated from the following Jiffle script: ");
100-
w.line(" *<code>");
118+
w.line(" *<pre>");
101119
for (String line : lines) {
102-
w.append(" * ").append(line).newLine();
120+
// In case the script itself includes comments, they best to be escaped
121+
String escaped = line.replace("*/", "*&#47;").replace("/*", "&#47;*");
122+
w.append(" * ").append(escaped).newLine();
103123
}
104-
w.line(" *</code>");
124+
w.line(" *</pre>");
105125
w.line(" */");
106126
}
107127

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
2+
* http://www.geo-solutions.it/
3+
* Copyright 2018 GeoSolutions
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package it.geosolutions.jaiext.jiffle.runtime;
18+
19+
import it.geosolutions.jaiext.jiffle.Jiffle;
20+
import it.geosolutions.jaiext.jiffle.JiffleException;
21+
import org.junit.Test;
22+
23+
import java.util.HashMap;
24+
import java.util.Map;
25+
26+
import static org.junit.Assert.assertFalse;
27+
import static org.junit.Assert.assertTrue;
28+
29+
public class JiffleRuntimeTest {
30+
31+
@Test
32+
public void testSkipSource() throws Exception {
33+
Jiffle jiffle = getJiffleWithComment();
34+
String source = jiffle.getRuntimeSource(false);
35+
36+
// by default, it does not contain the source
37+
assertFalse(source.contains("This is a comment"));
38+
}
39+
40+
@Test
41+
public void testEscapeSource() throws Exception {
42+
Jiffle jiffle = getJiffleWithComment();
43+
String source = jiffle.getRuntimeSource(true);
44+
45+
// source is in the javadocs, and properly escaped
46+
assertTrue(source.contains("* &#47;* This is a comment *&#47;"));
47+
assertTrue(source.contains("* dest=10;"));
48+
}
49+
50+
private Jiffle getJiffleWithComment() throws JiffleException {
51+
String script = "/* This is a comment */\ndest=10;";
52+
Jiffle jiffle = new Jiffle();
53+
jiffle.setScript(script);
54+
Map<String, Jiffle.ImageRole> params = new HashMap<>();
55+
params.put("dest", Jiffle.ImageRole.DEST);
56+
jiffle.setImageParams(params);
57+
58+
jiffle.compile();
59+
return jiffle;
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
2+
* http://www.geo-solutions.it/
3+
* Copyright 2018 GeoSolutions
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package it.geosolutions.jaiext.jiffle.runtime;
18+
19+
import it.geosolutions.jaiext.jiffle.Jiffle;
20+
import it.geosolutions.jaiext.jiffle.JiffleException;
21+
import it.geosolutions.jaiext.jiffle.parser.JiffleParserException;
22+
import org.junit.Assert;
23+
import org.junit.Test;
24+
25+
import java.util.HashMap;
26+
import java.util.Map;
27+
28+
import static org.junit.Assert.assertEquals;
29+
30+
public class ScriptTest {
31+
32+
@Test
33+
public void testValidateSourceImages() throws Exception {
34+
checkInvalidSourceName("a b");
35+
checkInvalidSourceName("99a");
36+
checkInvalidSourceName("#abc");
37+
checkInvalidSourceName("/abc");
38+
checkInvalidSourceName("{abc");
39+
}
40+
41+
@Test
42+
public void testValidateDestinationImages() throws Exception {
43+
checkInvalidDestinationName("a b");
44+
checkInvalidDestinationName("99a");
45+
checkInvalidDestinationName("#abc");
46+
checkInvalidDestinationName("/abc");
47+
checkInvalidDestinationName("{abc");
48+
}
49+
50+
private void checkInvalidSourceName(String name) throws JiffleException {
51+
Jiffle jiffle = new Jiffle();
52+
jiffle.setScript("dst=0;");
53+
Map<String, Jiffle.ImageRole> params = new HashMap<>();
54+
params.put(name, Jiffle.ImageRole.SOURCE);
55+
jiffle.setImageParams(params);
56+
57+
JiffleParserException exception =
58+
Assert.assertThrows(JiffleParserException.class, () -> jiffle.compile());
59+
assertEquals("Invalid source image name: " + name, exception.getMessage());
60+
}
61+
62+
private void checkInvalidDestinationName(String name) throws JiffleException {
63+
Jiffle jiffle = new Jiffle();
64+
jiffle.setScript("dst=0;");
65+
Map<String, Jiffle.ImageRole> params = new HashMap<>();
66+
params.put(name, Jiffle.ImageRole.DEST);
67+
jiffle.setImageParams(params);
68+
69+
JiffleParserException exception =
70+
Assert.assertThrows(JiffleParserException.class, () -> jiffle.compile());
71+
assertEquals("Invalid dest image name: " + name, exception.getMessage());
72+
}
73+
}

0 commit comments

Comments
 (0)