How To Use the Ctemplate (formerly Google Template) System

(as of )

Motivation

A template system can be used to separate output formatting specifications, which govern the appearance and location of output text and data elements, from the executable logic which prepares the data and makes decisions about what appears in the output.

Template systems lie along a continuum of power versus separation. "Powerful" constructs like variable assignment or conditional statements make it easy to modify the look of an application within the template system exclusively, without having to modify any of the underlying "application logic". They do so, however, at the cost of separation, turning the templates themselves into part of the application logic.

This template system leans strongly towards preserving the separation of logic and presentation. It is intentionally constrained in the features it supports and, as a result, applications tend to require quite a bit of code to instantiate a template. This may not be to everybody's tastes. However, while this design limits the power of the template language, it does not limit the power or flexibility of the template system. This system supports arbitrarily complex text formatting. Many Google applications, including the "main" Google web search, use this system for formatting output.

Finally, this system is designed with an eye towards efficiency. Template instantiation is very quick, with an eye towards minimizing both memory use and memory fragmentation.

Overview

There are two main parts to the Ctemplate System:

The templates are text files that contain the format specification for the formatted output, i.e, the template language. The data dictionaries contain the mappings from the template elements (markers) embedded in the templates to the data that they will format. Here's a simple template:

   <html><head><title>{{TITLE}}</title>{{META_TAGS}}</head>
   <body>{{BODY}}</body></html>

Here's a dictionary that one could use to instantiate the template:

   {"TITLE": "Template example",
    "BODY": "This is a simple template example.\nIt's boring",
    "DATE": "11/20/2005"}

If we instantiated the template with this dictionary (a process we call "expanding"), here's the output we would get:

   <html><head><title>Template example</title></head>
   <body>This is a simple template example.
It's boring</body></html>

{{TITLE}} and {{BODY}} are template elements, also called markers. In the dictionary, TITLE, BODY, and DATE are dictionary names, and the values associated with each one, such as 11/20/2005, are dictionary values.

A few points are clear even from this simple example:

  1. Dictionary keys and values are strings; the Ctemplate system is not typed.
  2. Dictionary values come already formatted. It was up to the application code to decide how to format the value for DATE, and to insert the date into the dictionary already formatted.
  3. Not all dictionary values must be used by a template. DATE is entirely ignored.
  4. Not all template elements may exist in the dictionary. In this example, {{META_TAGS}} is not found in the dictionary. This is perfectly legal; missing dictionary names evaluate to the empty string.

Templates

The template language has four major types of markers (the full list of marker types is described in the reference guide):

  1. Variable markers, which are replaced by text based on dictionary values. All markers in the above example are variable markers. Variable markers look like this: {{FOO}}
  2. Start section and end section markers, which delimit sections which may appear zero, one, or N times in the output. The number of times a section appears is determined by the data dictionaries, as explained below. Each time a section is expanded, it uses a different dictionary, so that the output values may be different from one iteration of a section expansion to another. Note that the specification of how sections expand is entirely dependent on the dictionary, as set up by the application; there is no way to specify a repeat count in the template language itself. Section markers look like this: {{#FOO}}...{{/FOO}}
  3. Template-include markers, which designate other templates to be expanded and inserted at the location where the marker appears. These are treated much like sections -- one may think of them as sections whose content is specified in a different file instead of inline -- and just like sections, can be expanded zero, one or N times in the output, each with a different dictionary and even a different include-file. Template-include markers look like this: {{>FOO}}
  4. Comment markers, which may annotate the template structure but drop completely out of the expanded output. Comment markers look like this: {{! comment lives here -- cool, no?}}

These marker types each have their own namespace. For readability, however, it is best to not overuse a single name.

Anything found in a template of the form {{...}} is interpreted as a template marker. All other text is considered formatting text and is output verbatim at template expansion time. Formatting text may consist of HTML tags, XML tags, linefeeds and other spacing characters, constant text, etc.

Data Dictionaries

A data dictionary is a map from keys to values. The keys are always strings, each string representing either a variable, a section, or a template-include file. (Comments are not stored in the data dictionary!) These values correspond to the name of the associated template marker: a section {{#FOO}} in the template text is matched to the key "FOO" in the dictionary, if it exists. Note the case must match as well.

The value associated with a key differs according to key type. The value associated with a variable is simple: it's the value for that variable. Both keys and values can be any 8-bit character-string, and may include internal NULs (\0).

The value associated with a section is more complicated, and somewhat recursive: it's a list of data dictionaries. Come template-expansion time, the section is expanded once for each dictionary in the list, so if there are two dictionaries in the list, then the section text will occur in the output twice. The first time, all variables/etc. in the section will be evaluated taking into account the first dictionary. The second time, all variables/etc. will be evaluated taking into account the second dictionary. (See below for a definition of "taking into account.")

A template-include is a special type of section, so the associated value is the same: a list of dictionaries. Template-includes also have one other, mandatory associated piece of information: the filename of the template to include.

The application program is responsible for building this data dictionary, including all nesting. It then applies this dictionary to a single template to produce formatted output.

Expanding a Template

A program using Ctemplate typically reads in templates at load time. During the course of program execution, the program will repeatedly perform the following two steps: first, instantiate a data dictionary, and second, apply the dictionary to the template to produce output.

The template system applies a dictionary to a template by finding all template markers in the template, and replacing them with the appropriate dictionary values. It matches template markers to dictionary keys in the obvious way. For instance, a template marker {{FOO}} matches the dictionary key FOO. The marker {{#BAR}} matches the dictionary key BAR, as does the marker {{/BAR}}. The marker {{>BAZ}} matches the dictionary key BAZ. (And of course, the marker {{! comment}} doesn't match any dictionary key at all.)

If no dictionary key is found for a given template marker, then the template marker is ignored: if a variable, it expands to the empty string; if a section or include-template, the section or include-template is expanded zero times.

All names are case sensitive. Names -- that is, variable keys and, as a result, template markers -- must be made of (7-bit ascii) alphanumeric characters and the underscore. The comment marker, which does not map to dictionary keys, may contain any characters whatsoever except }, the close-curly brace. It's a syntax error for any template marker to violate this rule.

Outside of the template markers, templates may contain any text whatsoever, including (single) curly braces and NUL characters.

Auto Escape Mode

The Auto Escape mode helps protect against cross-site scripting (XSS) attacks in web-applications by automatically escaping variables in your template. The Guide to using Auto Escape has an overview of Auto Escape as well as discussion of its limitations.

Auto Escape is enabled on a template-by-template basis. Simply add the AUTOESCAPE pragma to the desired template. That template will then be automatically escaped, independently of the templates it may include or it may be included from. The AUTOESCAPE pragma must be placed at the top of the template. It takes a 'context' argument saying what context the template is used in: html, javascript, css, xml, etc. (There's also a state=IN_TAG argument that is used when the template is just a snippet of html intended for use in a tag.) See the reference guide for a full description of autoescape arguments.

The table below shows four small sample templates along with their corresponding AUTOESCAPE pragma. The two most common contexts are HTML and JAVASCRIPT. We also show a sample template for the CSS context as well as a sample template for the IN_TAG state of HTML (although it is expected to be rarely used).

HTML JAVASCRIPT CSS HTML IN_TAG (uncommon)
    {{%AUTOESCAPE context="HTML"}}

    <body>
      <p>Hello {{USER}}</p>
      <p><a href="{{URL}}">Your Account</a></p>
    </body>
    
    {{%AUTOESCAPE context="JAVASCRIPT"}}

    function showMessage(user, msg) {
      alert("Hello: " + user + " Message: " + msg);
    }

    var user = '{{USER}}';
    var msg = '{{MSG}}';
    showMessage(user, msg);
    
    {{%AUTOESCAPE context="CSS"}}

    P.abstract {
      text-align:{{EDGE}};
      font-size:{{FONT_SIZE_PC}};
    }
    .italic {font-style:{{ITALIC}}}
    
    {{%AUTOESCAPE context="HTML" state="IN_TAG"}}

    class="{{CLASS}}" id="{{ID}}"
    

Auto-escaping works by automatically applying modifiers to every variable in the template. You can manually apply modifiers as well, and even define your own. See the reference guide for a full discussion of modifiers and how to use them.

Details on Dictionary Lookup

The dictionary structure is a tree: there's a 'main' dictionary, and then a list of sub-dictionaries for each section or include-template. Even with all this complexity, the lookup rules are mostly straightforward: when looking up a marker -- be it a variable, section, or include-template marker -- the system looks in the currently applicable dictionary. If it's found there, great. If not, and the parent dictionary is not an include-template, it continues the look in the parent dictionary, and possibly the grandparent, etc. That is, lookup has static scoping: you look in your dictionary and any parent dictionary that is associated with the same template-file. As soon as continuing the lookup would require you to jump to a new template-file (which is what include-template would do), we stop the lookup.

For instance, for a template that says {{#RESULTS}}{{RESULTNUM}}. {{>ONE_RESULT}}{{/RESULTS}}, "ONE_RESULT" is looked for in the "RESULTS" dictionary, and if not found there, is looked for in the main, top-level dictionary. Likewise, the variable "RESULTNUM" is looked for first in the "RESULTS" dictionary, then in the main dictionary if necessary. However, "ONE_RESULT" will not do equivalent cascading lookups. In fact, it will have no parent dictionaries at all, because it's a different template file and thus in a different scope.

Because of these scoping rules, it's perfectly reasonable to set all variables that are needed in a given template file, in the top-level dictionary for that template. In fact, the ShowSection() function is provided to support just this idiom. To avoid confusion in such a usage mode, it's strongly encouraged that you give unique names to all sections and include-templates in a single template file. (It's no problem, given the template scoping rules, for a single section or include-template name to be repeated across different template files.)

There's a single special case: the global variable dictionary. Every dictionary inherits its initial set of values from the global dictionary. Clients can set variables in the global dictionary just like they can in normal template dictionaries they create.

The system initializes the global dictionary with a few useful values for your convenience. All system variables are prefixed with BI, to emphasize they are "built in" variables.

As is usual for inheritance, if a user explicitly assigns a value to these variable-names in its own dictionary, this overrides the inherited value. So, dict->SetValue("BI_SPACE", "&nbsp;") causes BI_SPACE to have the value &nbsp;, rather than <space>, when expanding dict.

Note that only variables can be inherited from the global dictionary, not section dictionaries or include-file dictionaries.

A couple of small implementation notes: global inheritance is "last chance", so if a section's parent dictionary redefined BI_SPACE, say, the section dictionary inherits the parent-dict value, not the global-dict value. Second, variable inheritance happens at expand time, not at dictionary-create time. So if you create a section dictionary, and then afterwards set a variable in its parent dictionary (or in the global dictionary), the section will inherit that variable value, if it doesn't define the value itself.

Writing Application Code To Use Templates

Most application code concerns filling a template dictionary, but there is also code for expanding templates given a dictionary. A final category of code lets you inspect and control the template system.

Creating A Template Dictionary

The class TemplateDictionary is used for all template dictionary operations. new ctemplate::TemplateDictionary(name) is used to create a new top-level dictionary. dict->AddSectionDictionary(name) and dict->AddIncludeDictionary(name) are used to create sub-dictionaries for sections or include-files. After creating a dictionary, the application should call one or more functions for each marker in the template. As an example, consider the following template:

<html><body> {{! This page has no head section.}}
{{#CHANGE_USER}}
<A HREF="/login">Click here</A> if you are not {{USERNAME}}<br>
{{/CHANGE_USER}}

Last five searches:<ol>
{{#PREV_SEARCHES}
<li> {{PREV_SEARCH}}
{{/PREV_SEARCHES}}
</ol>

{{>RESULT_TEMPLATE}}

{{FOOTER}}
</body></html>

To instantiate the template, the user should call a function to set up FOOTER, and a function to say what to do for the sections CHANGE_USER and PREV_SEARCHES, and for the include-template RESULT_TEMPLATE. Quite likely, the application will also want to create a sub-dictionary for CHANGE_USER, and in that sub-dictionary call a function to set up USERNAME. There will also be sub-dictionaries for PREV_SEARCHES, each of which will need to set PREV_SEARCH. Only when this is all set up will the application be able to apply the dictionary to the template to get output.

The appropriate function to call for a given template marker depends on its type.

Variables

For variables, the only interesting action is to set the variable's value. For most variables, the right method to call is dict->SetValue(name, value). (The name and value can be specified as strings in a variety of ways: C++ strings, char *'s, or char *'s plus length.)

There are two other ways to set a variable's value as well, each with a different scoping rule. You can call ctemplate::TemplateDictionary::SetGlobalValue(name, value) -- no TemplateDictionary instance needed here -- to set a variable that can be used by all templates in an application. This is quite rare.

You can also call dict->SetTemplateGlobalValue(name, value). This sets a variable that is seen by all child dictionaries of this dictionary: sub-sections you create via AddSectionDictionary, and included templates you create via AddIncludeDictionary (both described below). This differs from SetValue(), because SetValue() values are never inherited across template-includes. Almost always, SetValue is what you want; SetTemplateGlobalValue is intended for variables that are "global" to a particular template tree not all template trees, such as a color scheme to use, a language code, etc.

To make it easier to use SetValue(), there are a few helper routines to help setting values of a few special forms.

Example:

   ctemplate::TemplateDictionary* dict = new ctemplate::TemplateDictionary("var example");
   dict->SetValue("FOOTER", "Aren't these great results?");

Sections

Sections are used in two ways in templates. One is to expand some text multiple times. This is how PREV_SEARCHES is used in the example above. In this case we'll have one small sub-dictionary for each of the five previous searches the user did. To do this, call AddSectionDictionary(section_name) to create the sub-dictionary. It returns a TemplateDictionary* that you can use to fill the sub-dictionary.

The other use of sections is to conditionally show or hide a block of text at template-expand time. This is how CHANGE_USER is used in the example template: if the user is logged in, we show the section with the user's username, otherwise we choose not to show the section.

This second case is a special case of the first, and the "standard" way to show a section is to expand it exactly one time, by calling AddSectionDictionary() once, and then setting USERNAME in the sub-dictionary.

However, the hide/show idiom is so common there are a few convenience methods to make it simpler. The first takes advantage of the fact sections inherit variables from their parent: you set USERNAME in the parent dictionary, rather than a section sub-dictionary, and then call ShowSection(), which adds a single, empty dictionary for that section. This causes the section to be shown once, and to inherit all its variable values from its parent.

A second convenience method is written for the particular case we have with USERNAME: if the user's username is non-empty, we wish to show the section with USERNAME set to the username, otherwise we wish to hide the section and show neither USERNAME nor the text around it. The method SetValueAndShowSection(name, value, section_name) does exactly that: if value is non-empty, add a single dictionary to section_name and call section_dict->AddValue(name, value).

Example:

   ctemplate::TemplateDictionary* dict = new ctemplate::TemplateDictionary("section example");
   const char* username = GetUsername();   // returns "" for no user
   if (username[0] != '\0') {
      ctemplate::TemplateDictionary* sub_dict = dict->AddSectionDictionary("CHANGE_USER");
      sub_dict->SetValue("USERNAME", username);
   } else {
      // don't need to do anything; we want a hidden section, which is the default
   }

   // Instead of the above 'if' statement, we could have done this:
   if (username[0] != '\0') {
      dict->ShowSection("CHANGE_USER");       // adds a single, empty dictionary
      dict->SetValue("USERNAME", username);   // take advantage of inheritance
   } else {
      // don't need to do anything; we want a hidden section, which is the default
   }

   // Or we could have done this:
   dict->SetValueAndShowSection("USERNAME", username, "CHANGE_USER");

   // Moving on...
   GetPrevSearches(prev_searches, &num_prev_searches);
   if (num_prev_searches > 0) {
      for (int i = 0; i < num_prev_searches; ++i) {
         TemplateDictionary* sub_dict = dict->AddSectionDictionary("PREV_SEARCHES");
         sub_dict->SetValue("PREV_SEARCH", prev_searches[i]);
      }
   }

Template-includes

Template-include markers are much like section markers, so AddIncludeDictionary(name) acts, not surprisingly, exactly like AddSectionDictionary(name). However, since variable inheritance doesn't work across include boundaries, there is no template-include equivalent to ShowSection() or SetValueAndShowSection().

One difference between template-includes and sections is that for a sub-dictionary that you create via AddIncludeDictionary(), you must call subdict->SetFilename() to indicate the name of the template to include. If you do not set this, the sub-dictionary will be ignored. The filename may be absolute, or relative, in which case it's relative to some entry in the template search path.

Example:

   using ctemplate::TemplateDictionary;
   TemplateDictionary* dict = new TemplateDictionary("include example");
   GetResults(results, &num_results);
   for (int i = 0; i < num_results; ++i) {
      TemplateDictionary* sub_dict = dict->AddIncludeDictionary("RESULT_TEMPLATE");
      sub_dict->SetFilename("results.tpl");
      FillResultsTemplate(sub_dict, results[i]);
   }

In practice, it's much more likely that FillResultsTemplate() will be the one to call SetFilename(). Note that it's not an error to call SetFilename() on a dictionary even if the dictionary is not being used for a template-include; in that case, the function is a no-op, but is perhaps still useful as self-documenting code.

Another property of template-includes is that they set the indentation level for the included template, that is, every line in the included template is indented by the same amount as the template-includes line itself. For instance, if you have a template PRINT_STUFF like this:

print "Hello!"
print "You are the 10th caller!"
print "Congratulations!"

and you include it in the template:

   if ShouldPrintStuff():
     {{>PRINT_STUFF}}
   else:
     pass

then when it is expanded, all three print lines will be indented, not just the first one:

   if ShouldPrintStuff():
     print "Hello!"
     print "You are the 10th caller!"
     print "Congratulations!"
   else:
     pass

Note that this behavior is immaterial when using STRIP_WHITESPACE, since in that case all leading whitespace is stripped.

Expanding a Template

Once you have a template dictionary, it's simplicity itself to expand the template with those dictionary values, putting the output in a string:

   ctemplate::TemplateDictionary dict("debug-name");
   FillDictionary(&dict, ...);
   string output;
   bool error_free = ctemplate::ExpandTemplate(<filename>, ctemplate::STRIP_WHITESPACE, &dict, &output);
   // output now holds the expanded template.
   // ExpandTemplate returns false if the system cannot load-and-parse
   // <filename> or any of the template files referenced by the
   // TemplateDictionary.

The first argument to ExpandTemplate is the filename holding the template to expand (though there are ways to use non-file-based templates as well). The second argument is the "strip" mode, which specifies how to treat whitespace in the template. It can take the following values:

The expanded template is written to the string output. If output was not empty before calling Expand(), the expanded template is appended to the end of output.

There is also a "power user" version of ExpandTemplate(), called ExpandWithData(), that allows you to pass in per-expand data. Another "power user" version allows you to expand the template into a custom output container, rather than a string. See the reference guide for more information about these advanced methods.

Getting a Template From a String Rather Than a File

The first argument to ExpandTemplate is named "filename", suggesting that the template has to be read from an on-disk file. But in reality, the "filename" argument is just a key into an internal cache. (By default, the template system looks on disk to satisfy a cache miss, hence the "filename" to describe this variable.) If you have a template specified in a string rather than a file, you can manually insert it into the cache via ctemplate::StringToTemplateCache().

StringToTemplateCache() parses the string you pass in as if it were a template file, and inserts it into the global cache with the key and strip-mode that you provide. You can then use this key and strip-mode as the first two arguments to ExpandTemplate. You can also use the key as the argument to ctemplate::TemplateDictionary::SetFilename().

Prefer file-based to string-based templates where possible. Updating a file-based template requires merely a data push, rather than pushing the new executable, and it also makes it easier for non-programmers to modify the template. One reason to use string-based templates is if you are in an environment where having data files could be dangerous—for instance, you work on a disk that is usually full, or need the template to work even in the face of disk I/O errors.

This package comes with a script, template-converter, that takes a template file as input and emits a C++ code snippet (an .h file) that defines a string with those template contents. This makes it easy to start by using a normal, file-based template, and then switch to StringToTemplateCache() later if you so desire.

Copying a Template Dictionary

You can use the MakeCopy() method on a template dictionary to make a "deep" copy of the template. This can be useful for situations like the following: you want to fill a template several times, each time with 90% of the values the same, but the last 10% different. Computing the values is slow. Here's how you can use MakeCopy() to do it:

  1. fill dict with 90%
  2. newdict1 = dict->MakeCopy();
  3. fill newdict1 with last 10%
  4. newdict2 = dict->MakeCopy();
  5. fill newdict2 with last 10%
  6. etc.

The Template Cache

When templates are loaded from disk, they are stored in an internal template cache, which is used by ExpandTemplate() and (most obviously) StringToTemplateCache(). You can define your own template cache with the TemplateCache class.

This is an advanced technique used when you want to support having several versions of a template file in memory at the same time (for instance, a webserver might want to keep an old version of a template file around until all old requests using that template are done being serviced). It also supports advanced operations like removing a template from the cache, and reloading templates from disk if they have changed.

See the reference manual for more details about the template cache.

Template and Threads

All expansion functions and static TemplateDictionary methods are threadsafe: you can safely call ctemplate::TemplateDictionary::SetGlobalValue() without needing to worry about locking.

Non-static TemplateDictionary methods are not thread-safe. It is not safe for two threads to assign values to the same template-dictionary without doing their own locking. Note that this is expected to be quite rare: usually only one thread will care about a given template-dictionary.

Testing Templates

Templates have the advantage that they separate the presentation of your data from the application logic that generates the data. Naturally, you want to do the same for testing: you would like to test the application's logic in a way that is robust to changes in the presentation.

The easiest way to test this logic is with unit tests that exercise the functions in your code that fill template dictionaries. The class ctemplate::TemplateDictionaryPeer in template_test_util.h is designed to help you do exactly that.

Here's a sample test using TemplateDictionaryPeer:

   void MyTestMethod() {
     // Create and populate the dictionary as your app normally would.
     // In this case, we create a dict with data like this:
     // { color:blue,
     //   shape_section: [
     //     { size:big, num_sides:7 },
     //     { size:big, num_sides:7 },
     //     { size:big, num_sides:7 }
     //   ]
     // }
     MyObject obj;
     ctemplate::TemplateDictionary dict;
     obj.FillDictionary(&dict);
     // Create a TemplateDictionaryPeer to gain access to the dict contents.
     ctemplate::TemplateDictionaryPeer peer(&dict);
     // Expect color:blue at the top level of this dictionary.
     EXPECT_STREQ("blue", peer.GetSectionValue("color"));
     // Fetch sub-dictionaries from the dict.
     vector<const ctemplate::TemplateDictionary*> shape_dicts;
     peer.GetSectionDictionaries("shape_section", &shape_dicts);
     EXPECT_EQ(3, shape_dicts.size());
     for (int i = 0; i < 3; ++i) {
       // Create another peer for each sub-dict, and assert that each sub-dict
       // contains the expected data.
       ctemplate::TemplateDictionaryPeer shape_peer(dicts[i]);
       EXPECT_STREQ("big", shape_peer.GetSectionValue("size"));
       EXPECT_STREQ("7", shape_peer.GetSectionValue("num_sides"));
     }
   }

Note that by using TemplateDictionaryPeer, you can unit test the code for filling a TemplateDictionary independent of the consuming Template.

The above tests your dictionary filling functions, but doesn't touch the template expansion. Naturally, you may also want to test the template itself. In this case, you will want to avoid using your program's dictionary filling functions, and will instead provide a custom dictionary in your test. There are a variety of properties you might want to test about the template, but here are a few sample tests:

   void TestTemplateHTMLEscapesColor() {
     // Populate a dictionary that lets us exercise the condition we're testing.
     // In this case, that the 'color' tag will be HTML escaped.
     ctemplate::TemplateDictionary dict("t1");
     dict.SetValue("color", "<blue>");
     // Expand the template with this dictionary.
     string result;
     ctemplate::ExpandTemplate(FLAGS_test_srcdir + "templates/my_template.html",
                               ctemplate::STRIP_WHITESPACE, &dict, &result);
     // Assert that the expansion has the appropriate text in it.
     EXPECT_THAT(result, HasSubstr("&lt;blue&gt;"));
   }

   void TestColorAppearsBeforeShape() {
     // This time, the condition under test is that the "color" element of
     // the dictionary appears before the "shape" element.
     // Create an appropriate dictionary.
     ctemplate::TemplateDictionary dict("t2"); // Note: use sufficiently unique
     dict.SetValue("color", "white_asdf");     // strings that they won't occur
     dict.SetValue("shape", "square_asdf");    // "bare" in the template.

     string result;
     ctemplate::ExpandTemplate(FLAGS_test_srcdir + "templates/my_template.html",
                               ctemplate::STRIP_WHITESPACE, &dict, &result);
     // Assert that color comes before shape.
     EXPECT_THAT(result, ContainsRegex("white_asdf.*square_asdf"));
   }

Security Considerations

Like all web applications, programs that use the Ctemplate System to create HTML documents can be vulnerable to Cross-Site-Scripting (XSS) attacks unless data inserted into a template is appropriately sanitized and/or escaped. Which specific form of escaping or sanitization is required depends on the context in which the template variable appears within a HTML document (such as, regular "inner text", within a <script> tag, or within an onClick handler).

If you are concerned with XSS, your are strongly encouraged to leverage the Auto Escape mode developed specifically to better defend your application against XSS. The Auto Escape mode follows the guidelines outlined below. Do note however that regardless of whether you use Auto Escape or not, escaping alone while generally required, is often not enough! You also may need to sanitize or validate the input, as for instance with URL attributes. For further information, refer to additional resources on Cross-Site-Scripting issues.

The remainder of this section provides a brief summary of techniques to prevent XSS vulnerabilities due to template variables in various HTML contexts.
  1. Regular text (outside of tags and other special situations).

    Use the auto-escape pragma to html-escape the variable.

  2. HTML tag attributes.

    In addition to the auto-escape pragma, ensure that the attribute is enclosed in double quotes in the template.

  3. URL attributes (eg., href/src).

    In addition to the auto-escape pragma, ensure that the attribute is enclosed in double quotes in the template.

  4. Beware of inserting variables containing data from untrusted sources into the context of a style tag or attribute.

    Certain CSS style-sheet constructs can result in the invocation of javascript. To prevent XSS, the variable must be carefully validated and sanitized.

  5. Populating javascript variables.

    In addition to the auto-escape pragma, ensure that the literal is enclosed in quotes in the template:

         <script>
           var msg_text  = '{{MESSAGE}}';
         </script>
         

    Literals of non-string types cannot be quoted and escaped. Instead, ensure that the variable's value is set such that it is guaranteed that the resulting string corresponds to a javascript literal of the expected type. For example, use

           dict->SetValueInt("NUM_ITEMS", num_items);
         

    to populate an integer javascript variable in the template fragment

         <script>
           var num_items = {{NUM_ITEMS}};
         </script>
         
  6. Populating javascript variables within event handlers such as onClick.

    Tag attributes whose values are evaluated as a javascript expression (such as on{Click,Load,etc} handlers) generally require HTML-Escape in addition to Javascript-Escape, since the attribute's value is HTML-unescaped by the browser before it is passed to the javascript interpreter.

    However, the javascript-escaping provided by auto-escape makes a subsequent HTML-Escape unnecessary. As such you can apply the same rules for variables within event handlers as you would for javascript variables in string literals:

           <button ...
                        onclick='GotoUrl("{{TARGET_URL}}");'>
         
  7. Consider potential non-template sources of XSS.

    There are a number of scenarios in which XSS can arise that are unrelated to the insertion of values into HTML templates, including,

    Please consult additional documentation on Cross-Site-Scripting for more detailed discussion of such issues.

Working Effectively with Templates

Registering Template Strings

Both dictionary keys and template filenames are strings. Instead of using raw strings, we encourage you to use a bit of machinery to help protect against various types of errors.

For dictionary keys, you can use the make_tpl_varnames_h tool to create static string variables to use instead of a string constant. This will protect against typos, as the make_tpl_varnames_h documentation describes. It also yields slightly more efficient code.

For template filenames that a program uses -- including sub-templates -- we suggest the following idiom:

   #include "example.tpl.varnames.h"   // defines 1 string per dictionary key
   RegisterTemplateFilename(EXAMPLE_FN, "example.tpl");   // defines template
   ...
   include_dict->SetFilename(EXAMPLE_FN);
   ...
   ctemplate::ExpandTemplate(EXAMPLE_FN, ctemplate::DO_NOT_STRIP, ...);
   ...

By registering the filename, you can query the template system to detect syntax errors, reload-status, and so forth.

Managing Templates

There are methods to change the global state of the template system, to examine templates, and to examine template dictionaries. See the reference guide for more information.



Craig Silverstein