diff options
Diffstat (limited to 'src/common/escape.cc')
-rw-r--r-- | src/common/escape.cc | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/src/common/escape.cc b/src/common/escape.cc new file mode 100644 index 000000000..67d68326c --- /dev/null +++ b/src/common/escape.cc @@ -0,0 +1,286 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2011 New Dream Network + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "common/escape.h" + +#include <stdio.h> +#include <string.h> +#include <iomanip> +#include <boost/optional.hpp> + +/* + * Some functions for escaping RGW responses + */ + +/* Static string length */ +#define SSTRL(x) ((sizeof(x)/sizeof(x[0])) - 1) + +#define LESS_THAN_XESCAPE "<" +#define AMPERSAND_XESCAPE "&" +#define GREATER_THAN_XESCAPE ">" +#define SGL_QUOTE_XESCAPE "'" +#define DBL_QUOTE_XESCAPE """ + +size_t escape_xml_attr_len(const char *buf) +{ + const char *b; + size_t ret = 0; + for (b = buf; *b; ++b) { + unsigned char c = *b; + switch (c) { + case '<': + ret += SSTRL(LESS_THAN_XESCAPE); + break; + case '&': + ret += SSTRL(AMPERSAND_XESCAPE); + break; + case '>': + ret += SSTRL(GREATER_THAN_XESCAPE); + break; + case '\'': + ret += SSTRL(SGL_QUOTE_XESCAPE); + break; + case '"': + ret += SSTRL(DBL_QUOTE_XESCAPE); + break; + default: + // Escape control characters. + if (((c < 0x20) && (c != 0x09) && (c != 0x0a)) || + (c == 0x7f)) { + ret += 6; + } + else { + ret++; + } + } + } + // leave room for null terminator + ret++; + return ret; +} + +void escape_xml_attr(const char *buf, char *out) +{ + char *o = out; + const char *b; + for (b = buf; *b; ++b) { + unsigned char c = *b; + switch (c) { + case '<': + memcpy(o, LESS_THAN_XESCAPE, SSTRL(LESS_THAN_XESCAPE)); + o += SSTRL(LESS_THAN_XESCAPE); + break; + case '&': + memcpy(o, AMPERSAND_XESCAPE, SSTRL(AMPERSAND_XESCAPE)); + o += SSTRL(AMPERSAND_XESCAPE); + break; + case '>': + memcpy(o, GREATER_THAN_XESCAPE, SSTRL(GREATER_THAN_XESCAPE)); + o += SSTRL(GREATER_THAN_XESCAPE); + break; + case '\'': + memcpy(o, SGL_QUOTE_XESCAPE, SSTRL(SGL_QUOTE_XESCAPE)); + o += SSTRL(SGL_QUOTE_XESCAPE); + break; + case '"': + memcpy(o, DBL_QUOTE_XESCAPE, SSTRL(DBL_QUOTE_XESCAPE)); + o += SSTRL(DBL_QUOTE_XESCAPE); + break; + default: + // Escape control characters. + if (((c < 0x20) && (c != 0x09) && (c != 0x0a)) || + (c == 0x7f)) { + snprintf(o, 7, "&#x%02x;", c); + o += 6; + } + else { + *o++ = c; + } + break; + } + } + // null terminator + *o = '\0'; +} + +// applies hex formatting on construction, restores on destruction +struct hex_formatter { + std::ostream& out; + const char old_fill; + const std::ostream::fmtflags old_flags; + + explicit hex_formatter(std::ostream& out) + : out(out), + old_fill(out.fill('0')), + old_flags(out.setf(out.hex, out.basefield)) + {} + ~hex_formatter() { + out.fill(old_fill); + out.flags(old_flags); + } +}; + +std::ostream& operator<<(std::ostream& out, const xml_stream_escaper& e) +{ + boost::optional<hex_formatter> fmt; + + for (unsigned char c : e.str) { + switch (c) { + case '<': + out << LESS_THAN_XESCAPE; + break; + case '&': + out << AMPERSAND_XESCAPE; + break; + case '>': + out << GREATER_THAN_XESCAPE; + break; + case '\'': + out << SGL_QUOTE_XESCAPE; + break; + case '"': + out << DBL_QUOTE_XESCAPE; + break; + default: + // Escape control characters. + if (((c < 0x20) && (c != 0x09) && (c != 0x0a)) || (c == 0x7f)) { + if (!fmt) { + fmt.emplace(out); // enable hex formatting + } + out << "&#x" << std::setw(2) << static_cast<unsigned int>(c) << ';'; + } else { + out << c; + } + break; + } + } + return out; +} + +#define DBL_QUOTE_JESCAPE "\\\"" +#define BACKSLASH_JESCAPE "\\\\" +#define TAB_JESCAPE "\\t" +#define NEWLINE_JESCAPE "\\n" + +size_t escape_json_attr_len(const char *buf, size_t src_len) +{ + const char *b; + size_t i, ret = 0; + for (i = 0, b = buf; i < src_len; ++i, ++b) { + unsigned char c = *b; + switch (c) { + case '"': + ret += SSTRL(DBL_QUOTE_JESCAPE); + break; + case '\\': + ret += SSTRL(BACKSLASH_JESCAPE); + break; + case '\t': + ret += SSTRL(TAB_JESCAPE); + break; + case '\n': + ret += SSTRL(NEWLINE_JESCAPE); + break; + default: + // Escape control characters. + if ((c < 0x20) || (c == 0x7f)) { + ret += 6; + } + else { + ret++; + } + } + } + // leave room for null terminator + ret++; + return ret; +} + +void escape_json_attr(const char *buf, size_t src_len, char *out) +{ + char *o = out; + const char *b; + size_t i; + for (i = 0, b = buf; i < src_len; ++i, ++b) { + unsigned char c = *b; + switch (c) { + case '"': + // cppcheck-suppress invalidFunctionArg + memcpy(o, DBL_QUOTE_JESCAPE, SSTRL(DBL_QUOTE_JESCAPE)); + o += SSTRL(DBL_QUOTE_JESCAPE); + break; + case '\\': + // cppcheck-suppress invalidFunctionArg + memcpy(o, BACKSLASH_JESCAPE, SSTRL(BACKSLASH_JESCAPE)); + o += SSTRL(BACKSLASH_JESCAPE); + break; + case '\t': + // cppcheck-suppress invalidFunctionArg + memcpy(o, TAB_JESCAPE, SSTRL(TAB_JESCAPE)); + o += SSTRL(TAB_JESCAPE); + break; + case '\n': + // cppcheck-suppress invalidFunctionArg + memcpy(o, NEWLINE_JESCAPE, SSTRL(NEWLINE_JESCAPE)); + o += SSTRL(NEWLINE_JESCAPE); + break; + default: + // Escape control characters. + if ((c < 0x20) || (c == 0x7f)) { + snprintf(o, 7, "\\u%04x", c); + o += 6; + } + else { + *o++ = c; + } + break; + } + } + // null terminator + *o = '\0'; +} + +std::ostream& operator<<(std::ostream& out, const json_stream_escaper& e) +{ + boost::optional<hex_formatter> fmt; + + for (unsigned char c : e.str) { + switch (c) { + case '"': + out << DBL_QUOTE_JESCAPE; + break; + case '\\': + out << BACKSLASH_JESCAPE; + break; + case '\t': + out << TAB_JESCAPE; + break; + case '\n': + out << NEWLINE_JESCAPE; + break; + default: + // Escape control characters. + if ((c < 0x20) || (c == 0x7f)) { + if (!fmt) { + fmt.emplace(out); // enable hex formatting + } + out << "\\u" << std::setw(4) << static_cast<unsigned int>(c); + } else { + out << c; + } + break; + } + } + return out; +} |