add: an non-HTML-encoding mode for templates for e.g. producing emails
authorFelix Dörre <felix@dogcraft.de>
Thu, 28 Jul 2016 15:44:38 +0000 (17:44 +0200)
committerFelix Dörre <felix@dogcraft.de>
Thu, 28 Jul 2016 16:48:47 +0000 (18:48 +0200)
fixes #50

Change-Id: Ide91f467068d3d740c32ce67c3505fe61ef89b47

src/org/cacert/gigi/output/template/Outputable.java
src/org/cacert/gigi/output/template/PlainOutputable.java
src/org/cacert/gigi/output/template/SprintfCommand.java
src/org/cacert/gigi/output/template/Template.java
src/org/cacert/gigi/output/template/TranslateCommand.java
src/org/cacert/gigi/pages/error/AccessDenied.java
tests/org/cacert/gigi/template/TestTemplateUnescaped.java [new file with mode: 0644]

index 02fea41193086bf4c2af3fa1a1ab5dbdbe644208..1e6d9f10041c3552fa80daa91a5cac41d710f889 100644 (file)
@@ -10,6 +10,8 @@ import org.cacert.gigi.localisation.Language;
  */
 public interface Outputable {
 
+    public static final String OUT_KEY_PLAIN = "output-content-plain";
+
     /**
      * Writes this object's content to the given output stream.
      * 
index 1ab349751f7133f1976b918b40da20f57953f585..3c56b7fabebd2758709be0eef25016683400d4db 100644 (file)
@@ -11,12 +11,16 @@ public class PlainOutputable implements Outputable {
     String text;
 
     public PlainOutputable(String text) {
-        this.text = HTMLEncoder.encodeHTML(text);
+        this.text = text;
     }
 
     @Override
     public void output(PrintWriter out, Language l, Map<String, Object> vars) {
-        out.print(text);
+        if (vars.containsKey(OUT_KEY_PLAIN)) {
+            out.print(text);
+        } else {
+            out.print(HTMLEncoder.encodeHTML(text));
+        }
     }
 
 }
index 51ea9cf209c16531a2637837c5410057aee9e011..64ede7823776692b11f7e2ba6100e1e07d9d6a3d 100644 (file)
@@ -78,7 +78,7 @@ public final class SprintfCommand implements Translatable {
         Matcher m = replacant.matcher(parts);
         int pos = 0;
         while (m.find()) {
-            out.print(HTMLEncoder.encodeHTML(parts.substring(pos, m.start())));
+            out.print(escape(vars, parts.substring(pos, m.start())));
             String var = store[Integer.parseInt(m.group(1))];
             if (var.startsWith("$!")) {
                 Template.outputVar(out, l, vars, var.substring(3, var.length() - 1), true);
@@ -92,7 +92,14 @@ public final class SprintfCommand implements Translatable {
             pos = m.end();
 
         }
-        out.print(HTMLEncoder.encodeHTML(parts.substring(pos)));
+        out.print(escape(vars, parts.substring(pos)));
+    }
+
+    private String escape(Map<String, Object> vars, String target) {
+        if (vars.containsKey(OUT_KEY_PLAIN)) {
+            return target;
+        }
+        return HTMLEncoder.encodeHTML(target);
     }
 
     @Override
index e80885710959c0ce23ba67c02350b4f94a6d39e7..9dbe4dc76c720a19beaa4424ebe46db1988686f4 100644 (file)
@@ -201,6 +201,9 @@ public class Template implements Outputable {
     }
 
     protected static void outputVar(PrintWriter out, Language l, Map<String, Object> vars, String varname, boolean unescaped) {
+        if (vars.containsKey(Outputable.OUT_KEY_PLAIN)) {
+            unescaped = true;
+        }
         Object s = vars.get(varname);
 
         if (s == null) {
index d291e9d414b3d4ce0111b3edf1c1ff85963b9294..6532d94682e7cbff6cb100788106b9f5f56293d1 100644 (file)
@@ -26,7 +26,12 @@ public final class TranslateCommand implements Translatable {
 
     @Override
     public void output(PrintWriter out, Language l, Map<String, Object> vars) {
-        out.print(HTMLEncoder.encodeHTML(l.getTranslation(raw)));
+        String translation = l.getTranslation(raw);
+        if (vars.containsKey(Outputable.OUT_KEY_PLAIN)) {
+            out.print(translation);
+        } else {
+            out.print(HTMLEncoder.encodeHTML(translation));
+        }
     }
 
     /**
index 60c48bf276224974a75bba6c115c50462814b03a..4908c75a970f415d4b370881dffdafe9a1d76d93 100644 (file)
@@ -1,6 +1,7 @@
 package org.cacert.gigi.pages.error;
 
 import java.io.IOException;
+import java.util.Collections;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -15,7 +16,7 @@ public class AccessDenied extends Page {
 
     @Override
     public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        getDefaultTemplate().output(resp.getWriter(), Page.getLanguage(req), null);
+        getDefaultTemplate().output(resp.getWriter(), Page.getLanguage(req), Collections.<String, Object>emptyMap());
     }
 
     @Override
diff --git a/tests/org/cacert/gigi/template/TestTemplateUnescaped.java b/tests/org/cacert/gigi/template/TestTemplateUnescaped.java
new file mode 100644 (file)
index 0000000..8c8a568
--- /dev/null
@@ -0,0 +1,46 @@
+package org.cacert.gigi.template;
+
+import static org.junit.Assert.*;
+
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+
+import org.cacert.gigi.localisation.Language;
+import org.cacert.gigi.output.template.Outputable;
+import org.cacert.gigi.output.template.Template;
+import org.junit.Test;
+
+public class TestTemplateUnescaped {
+
+    private String testExecute(HashMap<String, Object> vars, String input) {
+        Template t = new Template(new StringReader(input));
+        StringWriter str = new StringWriter();
+        PrintWriter pw = new PrintWriter(str);
+        t.output(pw, Language.getInstance(Locale.ENGLISH), vars);
+        pw.flush();
+        return str.toString();
+    }
+
+    HashMap<String, Object> vars = new HashMap<>(Collections.<String, Object>singletonMap(Outputable.OUT_KEY_PLAIN, "yes"));
+
+    @Test
+    public void testVarNoEscape() {
+        vars.put("var", "val");
+        assertEquals("vall", testExecute(vars, "<?=$var?>l"));
+        vars.put("var", "val<");
+        assertEquals("val<l", testExecute(vars, "<?=$var?>l"));
+        assertEquals("val<l", testExecute(vars, "<?=$!var?>l"));
+        vars.put("var", "val\">");
+        assertEquals("val\">l", testExecute(vars, "<?=$var?>l"));
+        assertEquals("val\">l", testExecute(vars, "<?=$!var?>l"));
+    }
+
+    @Test
+    public void testTranslateNoEscape() {
+        assertEquals("\"tex<>l", testExecute(vars, "<?=_\"tex<>?>l"));
+    }
+}