Revert "Optimize CGI.escapeHTML by reducing buffer extension"

This reverts commit 8d81e59aa7.

`ALLOCA_N` does not check stack overflow unlike ALLOCV. I'll fix it and
re-commit it again.
This commit is contained in:
Takashi Kokubun 2019-06-05 11:00:54 +09:00
Родитель 804a7907a8
Коммит 71b14affc6
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 6FFC433B12EE23DD
2 изменённых файлов: 48 добавлений и 72 удалений

Просмотреть файл

@ -1,40 +0,0 @@
prelude: require 'cgi/escape'
benchmark:
- name: escape_html_blank
prelude: str = ""
script: CGI.escapeHTML(str)
loop_count: 20000000
- name: escape_html_short_none
prelude: str = "abcde"
script: CGI.escapeHTML(str)
loop_count: 20000000
- name: escape_html_short_one
prelude: str = "abcd<"
script: CGI.escapeHTML(str)
loop_count: 20000000
- name: escape_html_short_all
prelude: str = "'&\"<>"
script: CGI.escapeHTML(str)
loop_count: 5000000
- name: escape_html_long_none
prelude: str = "abcde" * 300
script: CGI.escapeHTML(str)
loop_count: 1000000
- name: escape_html_long_all
prelude: str = "'&\"<>" * 10
script: CGI.escapeHTML(str)
loop_count: 1000000
- name: escape_html_real
prelude: | # http://example.com/
str = <<~HTML
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is established to be used for illustrative examples in documents. You may use this
domain in examples without prior coordination or asking for permission.</p>
<p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
HTML
script: CGI.escapeHTML(str)
loop_count: 1000000

Просмотреть файл

@ -11,20 +11,27 @@ RUBY_EXTERN const signed char ruby_digit36_to_number_table[];
static VALUE rb_cCGI, rb_mUtil, rb_mEscape; static VALUE rb_cCGI, rb_mUtil, rb_mEscape;
static ID id_accept_charset; static ID id_accept_charset;
#define HTML_ESCAPE_MAX_LEN 6 static void
html_escaped_cat(VALUE str, char c)
static const struct { {
uint8_t len; switch (c) {
char str[HTML_ESCAPE_MAX_LEN+1]; case '\'':
} html_escape_table[UCHAR_MAX+1] = { rb_str_cat_cstr(str, "&#39;");
#define HTML_ESCAPE(c, str) [c] = {rb_strlen_lit(str), str} break;
HTML_ESCAPE('\'', "&#39;"), case '&':
HTML_ESCAPE('&', "&amp;"), rb_str_cat_cstr(str, "&amp;");
HTML_ESCAPE('"', "&quot;"), break;
HTML_ESCAPE('<', "&lt;"), case '"':
HTML_ESCAPE('>', "&gt;"), rb_str_cat_cstr(str, "&quot;");
#undef HTML_ESCAPE break;
}; case '<':
rb_str_cat_cstr(str, "&lt;");
break;
case '>':
rb_str_cat_cstr(str, "&gt;");
break;
}
}
static inline void static inline void
preserve_original_state(VALUE orig, VALUE dest) preserve_original_state(VALUE orig, VALUE dest)
@ -37,27 +44,36 @@ preserve_original_state(VALUE orig, VALUE dest)
static VALUE static VALUE
optimized_escape_html(VALUE str) optimized_escape_html(VALUE str)
{ {
const char *cstr = RSTRING_PTR(str); long i, len, beg = 0;
const char *end = cstr + RSTRING_LEN(str); VALUE dest = 0;
char *buf = ALLOCA_N(char, RSTRING_LEN(str) * HTML_ESCAPE_MAX_LEN); const char *cstr;
char *dest = buf; len = RSTRING_LEN(str);
while (cstr < end) { cstr = RSTRING_PTR(str);
const unsigned char c = *cstr++;
uint8_t len = html_escape_table[c].len; for (i = 0; i < len; i++) {
if (len) { switch (cstr[i]) {
memcpy(dest, html_escape_table[c].str, len); case '\'':
dest += len; case '&':
} case '"':
else { case '<':
*dest++ = c; 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)) { if (dest) {
VALUE escaped = rb_str_new(buf, dest - buf); rb_str_cat(dest, cstr + beg, len - beg);
preserve_original_state(str, escaped); preserve_original_state(str, dest);
return escaped; return dest;
} }
else { else {
return rb_str_dup(str); return rb_str_dup(str);