1/*
2 * Copyright (C) 2010 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.clearsilver.jsilver.autoescape;
18
19import com.google.clearsilver.jsilver.exceptions.JSilverAutoEscapingException;
20
21public enum EscapeMode {
22  ESCAPE_NONE("none", false), ESCAPE_HTML("html", false), ESCAPE_JS("js", false), ESCAPE_URL("url",
23      false), ESCAPE_IS_CONSTANT("constant", false),
24
25  // These modes are used as starting modes, and a parser parses the
26  // subsequent template contents to determine the right escaping command to use.
27  ESCAPE_AUTO("auto", true), // Identical to ESCAPE_AUTO_HTML
28  ESCAPE_AUTO_HTML("auto_html", true), ESCAPE_AUTO_JS("auto_js", true), ESCAPE_AUTO_JS_UNQUOTED(
29      "auto_js_unquoted", true), ESCAPE_AUTO_STYLE("auto_style", true), ESCAPE_AUTO_ATTR(
30      "auto_attr", true), ESCAPE_AUTO_UNQUOTED_ATTR("auto_attr_unquoted", true), ESCAPE_AUTO_ATTR_URI(
31      "auto_attr_uri", true), ESCAPE_AUTO_UNQUOTED_ATTR_URI("auto_attr_uri_unquoted", true), ESCAPE_AUTO_ATTR_URI_START(
32      "auto_attr_uri_start", true), ESCAPE_AUTO_UNQUOTED_ATTR_URI_START(
33      "auto_attr_uri_start_unquoted", true), ESCAPE_AUTO_ATTR_JS("auto_attr_js", true), ESCAPE_AUTO_ATTR_UNQUOTED_JS(
34      "auto_attr_unquoted_js", true), ESCAPE_AUTO_UNQUOTED_ATTR_JS("auto_attr_js_unquoted", true), ESCAPE_AUTO_UNQUOTED_ATTR_UNQUOTED_JS(
35      "auto_attr_js_unquoted_js", true), ESCAPE_AUTO_ATTR_CSS("auto_attr_style", true), ESCAPE_AUTO_UNQUOTED_ATTR_CSS(
36      "auto_attr_style_unquoted", true);
37
38  private String escapeCmd;
39  private boolean autoEscaper;
40
41  private EscapeMode(String escapeCmd, boolean autoEscaper) {
42    this.escapeCmd = escapeCmd;
43    this.autoEscaper = autoEscaper;
44  }
45
46  /**
47   * This function maps the type of escaping requested (escapeCmd) to the appropriate EscapeMode. If
48   * no explicit escaping is requested, but doAutoEscape is true, the function chooses auto escaping
49   * (EscapeMode.ESCAPE_AUTO). This mirrors the behaviour of ClearSilver.
50   *
51   * @param escapeCmd A string indicating type of escaping requested.
52   * @param doAutoEscape Whether auto escaping should be applied if escapeCmd is null. Corresponds
53   *        to the Config.AutoEscape HDF variable.
54   * @return
55   */
56  public static EscapeMode computeEscapeMode(String escapeCmd, boolean doAutoEscape) {
57    EscapeMode escapeMode;
58
59    // If defined, the explicit escaping mode (configured using "Config.VarEscapeMode")
60    // takes preference over auto escaping
61    if (escapeCmd != null) {
62      for (EscapeMode e : EscapeMode.values()) {
63        if (e.escapeCmd.equals(escapeCmd)) {
64          return e;
65        }
66      }
67      throw new JSilverAutoEscapingException("Invalid escaping mode specified: " + escapeCmd);
68
69    } else {
70      if (doAutoEscape) {
71        escapeMode = ESCAPE_AUTO;
72      } else {
73        escapeMode = ESCAPE_NONE;
74      }
75      return escapeMode;
76    }
77  }
78
79  /**
80   * Calls {@link #computeEscapeMode(String, boolean)} with {@code doAutoEscape = false}.
81   *
82   * @param escapeCmd A string indicating type of escaping requested.
83   * @return EscapeMode
84   * @throws JSilverAutoEscapingException if {@code escapeCmd} is not recognized.
85   */
86  public static EscapeMode computeEscapeMode(String escapeCmd) {
87    return computeEscapeMode(escapeCmd, false);
88  }
89
90  /**
91   * Computes the EscapeMode of the result of concatenating two values. The EscapeModes of the two
92   * values are provided by {@code left} and {@code right} respectively. For now, if either of the
93   * values was escaped or a constant, we return {@code ESCAPE_IS_CONSTANT}. This is how ClearSilver
94   * behaves.
95   *
96   * @return {@code ESCAPE_NONE} if either of the values was not escaped or constant. {@code
97   *         ESCAPE_IS_CONSTANT} otherwise.
98   */
99  public static EscapeMode combineModes(EscapeMode left, EscapeMode right) {
100    if (left.equals(ESCAPE_NONE) || right.equals(ESCAPE_NONE)) {
101      // If either of the values has not been escaped,
102      // do not trust the result.
103      return ESCAPE_NONE;
104    } else {
105      // For now, indicate that this result is always safe in all contexts.
106      // This is what ClearSilver does. We may introduce a stricter autoescape
107      // rule later on which also requires that the escaping be the same as the
108      // context its used in.
109      return ESCAPE_IS_CONSTANT;
110    }
111  }
112
113  public boolean isAutoEscapingMode() {
114    return autoEscaper;
115  }
116
117  // TODO: Simplify enum names, and just use toString() instead.
118  public String getEscapeCommand() {
119    return escapeCmd;
120  }
121}
122