blob: b453e18a95b5691161c93101e5892fd0e6f6e95f [file] [log] [blame]
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: csilvers@google.com (Craig Silverstein)
//
// These are used by template.cc and when registering new modifiers.
// (Or more exactly, registering new modifier/value pairs.)
// They are not intended for any other users.
//
// If you do find yourself needing to use them directly, please email
// template-users.
//
// Known outside-template users of this class:
// template/bidi/bidi_modifiers_test.cc
//
// These routines are implemented in template_modifiers.cc.
#ifndef TEMPLATE_TEMPLATE_MODIFIERS_INTERNAL_H_
#define TEMPLATE_TEMPLATE_MODIFIERS_INTERNAL_H_
#include <config.h>
#include <sys/types.h> // for size_t
#include <string.h> // for strchr
#include <string>
#include <vector>
#include <ctemplate/template_modifiers.h> // for null_modifier
// Annoying stuff for windows -- make sure clients (in this case
// unittests) can import the class definitions and variables.
#ifndef CTEMPLATE_DLL_DECL
# ifdef _MSC_VER
# define CTEMPLATE_DLL_DECL __declspec(dllimport)
# else
# define CTEMPLATE_DLL_DECL /* should be the empty string for non-windows */
# endif
#endif
using std::string;
using std::vector;
namespace ctemplate_htmlparser {
class HtmlParser;
}
namespace ctemplate {
class TemplateModifier;
// A Modifier belongs to an XssClass which determines whether
// it is an XSS safe addition to a modifier chain or not. This
// is used by the Auto-Escape mode when determining how to handle
// extra modifiers provided in template. For example, :j is a safe
// addition to :h because they are both in the same class (XSS_WEB_STANDARD).
//
// XssClass is not exposed in any API and cannot be set in custom
// modifiers, it is for internal use only (for Auto-Escape). We currently
// have only three classes.
//
// XSS_UNUSED: not used.
// XSS_WEB_STANDARD: All the curent built-in escaping modifiers.
// XSS_UNIQUE: Set for all custom modifiers added via AddModifier()
// and may need to be escaped.
// XSS_SAFE: Set for all custom modifiers added via AddXssSafeModifier()
// that are considered to produce safe output and hence
// do not need further escaping. Also includes the :none modifier.
enum XssClass {
XSS_UNUSED,
XSS_WEB_STANDARD,
XSS_UNIQUE,
XSS_SAFE,
};
// TODO(csilvers): collapse this into the TemplateModifier class?
struct ModifierInfo {
// longname should end in an '=' iff the modifier takes a value
// (same as in getopt(3)).
// To specialize -- add a modifier that applies only when we see the name
// with a particular value -- specify longname like so: "longname=value".
// (See example in the comment-doc below, for AddModifier.)
// sn can be '\0' if there is no associated shortname.
// m should be NULL *only if* default-registering a user-defined longname
// that the user neglected to register themselves. In this case, we
// use the null modifier as the actual modifier.
// xss_class indicates an equivalence class this modifier is
// in, such that any other modifier in the class could be applied
// after this modifier without affecting its XSS-safety. If in
// doubt, say XSS_UNIQUE, which is the most conservative choice.
ModifierInfo(string ln, char sn, XssClass xc, const TemplateModifier* m)
: long_name(ln), short_name(sn),
modval_required(strchr(ln.c_str(), '=') != NULL),
is_registered(m != NULL), xss_class(xc),
modifier(m ? m : &null_modifier) { }
string long_name;
char short_name;
bool modval_required; // true iff ln has an '=' in it
bool is_registered; // true for built-in and AddModifier mods
XssClass xss_class;
const TemplateModifier* modifier;
};
// An escaping directive is completely defined by the escaping function to use
// (ModifierInfo.modifier) as well as the optional value it may require. This
// structure is a small wrapper on ModifierInfo to convey that needed value.
// Note: The given value pointer must be valid for the life of the struct.
// Also, value is not null-terminated.
struct ModifierAndValue {
ModifierAndValue(const ModifierInfo* mod_info, const char* val,
size_t val_len)
: modifier_info(mod_info), value(val), value_len(val_len) { }
const ModifierInfo* modifier_info;
const char* value;
size_t value_len;
};
// Returns whether or not candidate can be safely (w.r.t XSS)
// used in lieu of our ModifierInfo. This is true iff:
// 1. Both have the same modifier function OR
// 2. Candidate's modifier function is in our ModifierInfo's
// list (vector) of safe alternative modifier functions.
// Note that this function is not commutative therefore
// IsSafeXSSAlternative(a, b) may not be equal to IsSafeXSSAlternative(b, a).
extern CTEMPLATE_DLL_DECL
bool IsSafeXSSAlternative(const ModifierInfo& our,
const ModifierInfo& candidate);
// modname is the name of the modifier (shortname or longname).
// value is the modifier-value (empty string if there is no modval).
// Returns a pointer into g_modifiers, or NULL if not found.
extern CTEMPLATE_DLL_DECL
const ModifierInfo* FindModifier(const char* modname, size_t modname_len,
const char* modval, size_t modval_len);
// Convenience function to dump the (zero or more) modifiers (and values)
// in the format:
// :<modifier1>[=<val1>]<seperator>[:<modifier2>][=<val2>]...
// If the modifier does not have a short_name, we print its long_name instead.
// The separator may be an empty string.
extern CTEMPLATE_DLL_DECL
string PrettyPrintModifiers(
const vector<const ModifierAndValue*>& modvals,
const string& separator);
extern CTEMPLATE_DLL_DECL
string PrettyPrintOneModifier(const ModifierAndValue& modval);
// Returns the appropriate escaping directives to escape content in an
// HTML or Javascript context. HTML and Javascript contexts exercise
// the same parser APIs and hence are combined here.
// If an error occurs, we return NULL and append and error to error_msg.
// The htmlparser and error_msg arguments must be non-NULL.
// Currently, on success, we always return a vector of length 1, meaning
// we never need to chain escaping directives. However, this is subject
// to change.
extern CTEMPLATE_DLL_DECL
vector<const ModifierAndValue*> GetModifierForHtmlJs(
ctemplate_htmlparser::HtmlParser* htmlparser, string* error_msg);
// Returns the appropriate escaping directives to escape content
// in a CSS context.
// Currently always returns cleanse_css and hence does not require the
// parser nor can it fail. This will change once the parser is able to
// distinguish between different CSS contexts, in particular CSS properties
// that take URLs, which require a different escaping function (non-existent).
extern CTEMPLATE_DLL_DECL
vector<const ModifierAndValue*> GetModifierForCss(
ctemplate_htmlparser::HtmlParser* htmlparser, string* error_msg);
// Returns the appropriate escaping directives to escape content
// in an XML context.
// Currently always returns xml_escape and hence does not require the
// parser nor can it fail. This may change once the parser can parse XML.
extern CTEMPLATE_DLL_DECL
vector<const ModifierAndValue*> GetModifierForXml(
ctemplate_htmlparser::HtmlParser* htmlparser, string* error_msg);
// Returns the appropriate escaping directives to escape content
// in a JSON context.
// Currently always returns javascript_escape and hence does not require the
// parser nor can it fail. This may change once the parser can parse
// and distinguish different contexts within JSON.
extern CTEMPLATE_DLL_DECL
vector<const ModifierAndValue*> GetModifierForJson(
ctemplate_htmlparser::HtmlParser* htmlparser, string* error_msg);
// Return the default escaping directives to escape content for the given
// context. These methods are useful when the caller does not have
// access to a parser or when the parsed failed to parse.
// GetDefaultModifierForHtml
// GetDefaultModifierForJs
// GetDefaultModifierForCss
// GetDefaultModifierForXxml
// GetDefaultModifierForJson
// These functions are different from the GetModifierForXXX functions
// in that they do not take a parser and cannot fail. They simply
// return the most common escaping directive for the context they refer to.
//
// Some of these contexts (currently HTML and Javascript) have more than
// one escaping directive associated with them and so we usually rely on
// the current state of the parser to determine which directive to chose.
// However, in some cases, the parser may fail to parse a given input
// and so we may want to select the most likely escaping directive that
// applies to the given context. Hence we use these functions instead of
// the corresponding GetModifierForXXX ones.
extern CTEMPLATE_DLL_DECL
std::vector<const ModifierAndValue*> GetDefaultModifierForHtml();
extern CTEMPLATE_DLL_DECL
std::vector<const ModifierAndValue*> GetDefaultModifierForJs();
extern CTEMPLATE_DLL_DECL
std::vector<const ModifierAndValue*> GetDefaultModifierForCss();
extern CTEMPLATE_DLL_DECL
std::vector<const ModifierAndValue*> GetDefaultModifierForXml();
extern CTEMPLATE_DLL_DECL
std::vector<const ModifierAndValue*> GetDefaultModifierForJson();
}
#endif // TEMPLATE_TEMPLATE_MODIFIERS_INTERNAL_H_