summaryrefslogtreecommitdiff
path: root/ext/cgi/escape
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2019-06-05 11:00:54 +0900
committerTakashi Kokubun <takashikkbn@gmail.com>2019-06-05 11:00:54 +0900
commit71b14affc6b699f38aabe73125380cab57799e34 (patch)
treecd3058b97f95780b592ae43ae173523eb5bb4919 /ext/cgi/escape
parent804a7907a8974cf2f820a7cdce9133843b0fa7db (diff)
Revert "Optimize CGI.escapeHTML by reducing buffer extension"
This reverts commit 8d81e59aa7a62652caf85f9c8db371703668c149. `ALLOCA_N` does not check stack overflow unlike ALLOCV. I'll fix it and re-commit it again.
Diffstat (limited to 'ext/cgi/escape')
-rw-r--r--ext/cgi/escape/escape.c82
1 files changed, 49 insertions, 33 deletions
diff --git a/ext/cgi/escape/escape.c b/ext/cgi/escape/escape.c
index 9b64c3541e..ced1b182eb 100644
--- a/ext/cgi/escape/escape.c
+++ b/ext/cgi/escape/escape.c
@@ -11,20 +11,27 @@ RUBY_EXTERN const signed char ruby_digit36_to_number_table[];
static VALUE rb_cCGI, rb_mUtil, rb_mEscape;
static ID id_accept_charset;
-#define HTML_ESCAPE_MAX_LEN 6
-
-static const struct {
- uint8_t len;
- char str[HTML_ESCAPE_MAX_LEN+1];
-} html_escape_table[UCHAR_MAX+1] = {
-#define HTML_ESCAPE(c, str) [c] = {rb_strlen_lit(str), str}
- HTML_ESCAPE('\'', "&#39;"),
- HTML_ESCAPE('&', "&amp;"),
- HTML_ESCAPE('"', "&quot;"),
- HTML_ESCAPE('<', "&lt;"),
- HTML_ESCAPE('>', "&gt;"),
-#undef HTML_ESCAPE
-};
+static void
+html_escaped_cat(VALUE str, char c)
+{
+ switch (c) {
+ case '\'':
+ rb_str_cat_cstr(str, "&#39;");
+ break;
+ case '&':
+ rb_str_cat_cstr(str, "&amp;");
+ break;
+ case '"':
+ rb_str_cat_cstr(str, "&quot;");
+ break;
+ case '<':
+ rb_str_cat_cstr(str, "&lt;");
+ break;
+ case '>':
+ rb_str_cat_cstr(str, "&gt;");
+ break;
+ }
+}
static inline void
preserve_original_state(VALUE orig, VALUE dest)
@@ -37,27 +44,36 @@ preserve_original_state(VALUE orig, VALUE dest)
static VALUE
optimized_escape_html(VALUE str)
{
- const char *cstr = RSTRING_PTR(str);
- const char *end = cstr + RSTRING_LEN(str);
- char *buf = ALLOCA_N(char, RSTRING_LEN(str) * HTML_ESCAPE_MAX_LEN);
-
- char *dest = buf;
- while (cstr < end) {
- const unsigned char c = *cstr++;
- uint8_t len = html_escape_table[c].len;
- if (len) {
- memcpy(dest, html_escape_table[c].str, len);
- dest += len;
- }
- else {
- *dest++ = c;
- }
+ long i, len, beg = 0;
+ VALUE dest = 0;
+ const char *cstr;
+
+ len = RSTRING_LEN(str);
+ cstr = RSTRING_PTR(str);
+
+ for (i = 0; i < len; i++) {
+ switch (cstr[i]) {
+ case '\'':
+ case '&':
+ case '"':
+ case '<':
+ case '>':
+ if (!dest) {
+ dest = rb_str_buf_new(len);
+ }
+
+ rb_str_cat(dest, cstr + beg, i - beg);
+ beg = i + 1;
+
+ html_escaped_cat(dest, cstr[i]);
+ break;
+ }
}
- if (RSTRING_LEN(str) < (dest - buf)) {
- VALUE escaped = rb_str_new(buf, dest - buf);
- preserve_original_state(str, escaped);
- return escaped;
+ if (dest) {
+ rb_str_cat(dest, cstr + beg, len - beg);
+ preserve_original_state(str, dest);
+ return dest;
}
else {
return rb_str_dup(str);