-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,5 @@ | |
/spec/reports/ | ||
/tmp/ | ||
Gemfile.lock | ||
*.so | ||
*.gem |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#include "ruby.h" | ||
#include "ruby/encoding.h" | ||
|
||
static VALUE rb_cERB, rb_mEscape; | ||
|
||
#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('\'', "'"), | ||
HTML_ESCAPE('&', "&"), | ||
HTML_ESCAPE('"', """), | ||
HTML_ESCAPE('<', "<"), | ||
HTML_ESCAPE('>', ">"), | ||
#undef HTML_ESCAPE | ||
}; | ||
|
||
static inline void | ||
preserve_original_state(VALUE orig, VALUE dest) | ||
{ | ||
rb_enc_associate(dest, rb_enc_get(orig)); | ||
} | ||
|
||
static inline long | ||
escaped_length(VALUE str) | ||
{ | ||
const long len = RSTRING_LEN(str); | ||
if (len >= LONG_MAX / HTML_ESCAPE_MAX_LEN) { | ||
ruby_malloc_size_overflow(len, HTML_ESCAPE_MAX_LEN); | ||
} | ||
return len * HTML_ESCAPE_MAX_LEN; | ||
} | ||
|
||
static VALUE | ||
optimized_escape_html(VALUE str) | ||
{ | ||
VALUE vbuf; | ||
char *buf = ALLOCV_N(char, vbuf, escaped_length(str)); | ||
const char *cstr = RSTRING_PTR(str); | ||
const char *end = cstr + RSTRING_LEN(str); | ||
|
||
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; | ||
} | ||
} | ||
|
||
VALUE escaped; | ||
if (RSTRING_LEN(str) < (dest - buf)) { | ||
escaped = rb_str_new(buf, dest - buf); | ||
preserve_original_state(str, escaped); | ||
} | ||
else { | ||
escaped = rb_str_dup(str); | ||
} | ||
ALLOCV_END(vbuf); | ||
return escaped; | ||
} | ||
|
||
static VALUE | ||
cgiesc_escape_html(VALUE self, VALUE str) | ||
{ | ||
StringValue(str); | ||
|
||
if (rb_enc_str_asciicompat_p(str)) { | ||
return optimized_escape_html(str); | ||
} | ||
else { | ||
return rb_call_super(1, &str); | ||
} | ||
} | ||
|
||
static VALUE | ||
erb_escape_html(VALUE self, VALUE str) | ||
{ | ||
str = rb_funcall(str, rb_intern("to_s"), 0); | ||
return cgiesc_escape_html(self, str); | ||
} | ||
|
||
void | ||
Init_erb(void) | ||
{ | ||
rb_cERB = rb_define_class("ERB", rb_cObject); | ||
rb_mEscape = rb_define_module_under(rb_cERB, "Escape"); | ||
rb_define_method(rb_mEscape, "html_escape", erb_escape_html, 1); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
require 'mkmf' | ||
create_makefile 'erb' |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -986,7 +986,6 @@ def def_class(superklass=Object, methodname='result') | |
class ERB | ||
# A utility module for conversion routines, often handy in HTML generation. | ||
module Util | ||
public | ||
# | ||
# A utility method for escaping HTML tag characters in _s_. | ||
# | ||
|
@@ -1002,6 +1001,17 @@ module Util | |
def html_escape(s) | ||
CGI.escapeHTML(s.to_s) | ||
end | ||
end | ||
|
||
begin | ||
require 'erb.so' | ||
rescue LoadError | ||
else | ||
private_constant :Escape | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
k0kubun
Author
Member
|
||
Util.prepend(Escape) | ||
end | ||
|
||
module Util | ||
alias h html_escape | ||
module_function :h | ||
module_function :html_escape | ||
|
Could you consider not making this a private constant? I would like to use it if available in Erubi and maybe Roda?