escape_utils 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  Makefile
2
2
  *.o
3
- *.bundle
3
+ *.bundle
4
+ pkg/*
5
+ doc/*
@@ -1,4 +1,7 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1 (June 8th, 2010)
4
+ * added javascript escaping
5
+
3
6
  ## 0.1.0 (June 8th, 2010)
4
7
  * initial release
@@ -2,7 +2,7 @@
2
2
 
3
3
  Being as though we're all html escaping everything these days, why not make it faster?
4
4
 
5
- At the moment escape_utils supports escaping and unescaping of HTML, but I wanna add URL encoding soon
5
+ At the moment escape_utils supports escaping and unescaping of HTML, and Javascript but I wanna add URL encoding soon
6
6
 
7
7
  It has monkey-patches for Rack::Utils, CGI, ERB::Util and Haml
8
8
 
@@ -23,6 +23,11 @@ It has monkey-patches for Rack::Utils, CGI, ERB::Util and Haml
23
23
  escaped_html = EscapeUtils.escape_html(html)
24
24
  html = EscapeUtils.unescape_html(escaped_html)
25
25
 
26
+ === Escaping Javascript
27
+
28
+ javascript = `curl -s http://code.jquery.com/jquery-1.4.2.js`
29
+ escaped_javascript = EscapeUtils.escape_javascript(javascript)
30
+
26
31
  === Monkey Patches
27
32
 
28
33
  require 'escape_utils/rack' # to patch Rack::Utils
@@ -33,11 +38,11 @@ It has monkey-patches for Rack::Utils, CGI, ERB::Util and Haml
33
38
  == Benchmarks
34
39
 
35
40
  In my testing, escaping is around 10-20x faster than the pure ruby implementations in wide use today.
36
- While unescaping is around 24x faster than CGI.unescapeHTML - also pure ruby.
41
+ While unescaping is around 20-40x faster than CGI.unescapeHTML - also pure ruby.
37
42
 
38
43
  This output is from my laptop using the benchmark scripts in the benchmarks folder.
39
44
 
40
- === Escaping
45
+ === HTML Escaping
41
46
 
42
47
  Rack::Utils.escape_html
43
48
  0.560000 0.040000 0.600000 ( 0.589475)
@@ -50,9 +55,16 @@ This output is from my laptop using the benchmark scripts in the benchmarks fold
50
55
  EscapeUtils.escape_html
51
56
  0.050000 0.010000 0.060000 ( 0.054799)
52
57
 
53
- === Unescaping
58
+ === HTML Unescaping
54
59
 
55
60
  CGI.unescapeHTML
56
61
  1.140000 0.010000 1.150000 ( 1.148470)
57
62
  EscapeUtils.unescape_html
58
- 0.040000 0.000000 0.040000 ( 0.046166)
63
+ 0.040000 0.000000 0.040000 ( 0.046166)
64
+
65
+ === Javascript Escaping
66
+
67
+ ActionView::Helpers::JavaScriptHelper#escape_javascript
68
+ 2.000000 0.020000 2.020000 ( 2.023047)
69
+ EscapeUtils.escape_javascript
70
+ 0.110000 0.010000 0.120000 ( 0.121761)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
File without changes
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/..')
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+
5
+ require 'rubygems'
6
+ require 'benchmark'
7
+
8
+ require 'action_view'
9
+ require 'escape_utils'
10
+
11
+ class ActionPackBench
12
+ extend ActionView::Helpers::JavaScriptHelper
13
+ end
14
+
15
+ times = 100
16
+ url = "http://code.jquery.com/jquery-1.4.2.js"
17
+ javascript = `curl -s #{url}`
18
+ puts "Escaping #{javascript.bytesize} bytes of javascript from #{url}"
19
+
20
+ puts ActionPackBench.escape_javascript(javascript).eql?(EscapeUtils.escape_javascript(javascript))
21
+
22
+ Benchmark.bmbm do |x|
23
+ x.report do
24
+ puts "ActionView::Helpers::JavaScriptHelper#escape_javascript"
25
+ times.times do
26
+ ActionPackBench.escape_javascript(javascript)
27
+ end
28
+ end
29
+
30
+ x.report do
31
+ puts "EscapeUtils.escape_javascript"
32
+ times.times do
33
+ EscapeUtils.escape_javascript(javascript)
34
+ end
35
+ end
36
+ end
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{escape_utils}
8
- s.version = "0.1.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brian Lopez"]
@@ -22,8 +22,9 @@ Gem::Specification.new do |s|
22
22
  "README.rdoc",
23
23
  "Rakefile",
24
24
  "VERSION",
25
- "benchmark/escape.rb",
26
- "benchmark/unescape.rb",
25
+ "benchmark/html_escape.rb",
26
+ "benchmark/html_unescape.rb",
27
+ "benchmark/javascript_escape.rb",
27
28
  "escape_utils.gemspec",
28
29
  "ext/escape_utils.c",
29
30
  "ext/extconf.rb",
@@ -34,6 +35,7 @@ Gem::Specification.new do |s|
34
35
  "lib/escape_utils/rack.rb",
35
36
  "spec/html/escape_spec.rb",
36
37
  "spec/html/unescape_spec.rb",
38
+ "spec/javascript/escape_spec.rb",
37
39
  "spec/rcov.opts",
38
40
  "spec/spec.opts",
39
41
  "spec/spec_helper.rb"
@@ -46,6 +48,7 @@ Gem::Specification.new do |s|
46
48
  s.test_files = [
47
49
  "spec/html/escape_spec.rb",
48
50
  "spec/html/unescape_spec.rb",
51
+ "spec/javascript/escape_spec.rb",
49
52
  "spec/spec_helper.rb"
50
53
  ]
51
54
 
@@ -72,7 +72,39 @@ static size_t unescape_html(unsigned char *out, const unsigned char *in, size_t
72
72
  return total + (i-offset);
73
73
  }
74
74
 
75
+ static size_t escape_javascript(unsigned char *out, const unsigned char *in, size_t in_len) {
76
+ size_t i = 0, offset = 0, total = 0;
77
+
78
+ for(;i<in_len;i++) {
79
+ switch(in[i]) {
80
+ case '\\': APPEND_BUFFER("\\\\", 2, 1);
81
+ case '<':
82
+ if (i+1 <= in_len && in[i+1] == '/') {
83
+ APPEND_BUFFER("<\\/", 3, 2);
84
+ }
85
+ break;
86
+ case '\r':
87
+ if (i+1 <= in_len && in[i+1] == '\n') {
88
+ APPEND_BUFFER("\\n", 2, 1);
89
+ } else {
90
+ APPEND_BUFFER("\\n", 2, 1);
91
+ }
92
+ break;
93
+ case '\n': APPEND_BUFFER("\\n", 2, 1);
94
+ case '\"': APPEND_BUFFER("\\\"", 2, 1);
95
+ case '\'': APPEND_BUFFER("\\'", 2, 1);
96
+ }
97
+ }
98
+
99
+ // append the rest of the buffer
100
+ memcpy(&out[total], &in[offset], i-offset);
101
+
102
+ return total + (i-offset);
103
+ }
104
+
75
105
  static VALUE rb_escape_html(VALUE self, VALUE str) {
106
+ Check_Type(str, T_STRING);
107
+
76
108
  VALUE rb_output_buf;
77
109
  unsigned char *inBuf = (unsigned char*)RSTRING_PTR(str);
78
110
  size_t len = RSTRING_LEN(str), new_len = 0;
@@ -94,6 +126,8 @@ static VALUE rb_escape_html(VALUE self, VALUE str) {
94
126
  }
95
127
 
96
128
  static VALUE rb_unescape_html(VALUE self, VALUE str) {
129
+ Check_Type(str, T_STRING);
130
+
97
131
  VALUE rb_output_buf;
98
132
  unsigned char *inBuf = (unsigned char*)RSTRING_PTR(str);
99
133
  size_t len = RSTRING_LEN(str), new_len = 0;
@@ -114,6 +148,33 @@ static VALUE rb_unescape_html(VALUE self, VALUE str) {
114
148
  return rb_output_buf;
115
149
  }
116
150
 
151
+ static VALUE rb_escape_javascript(VALUE self, VALUE str) {
152
+ if (str == Qnil) {
153
+ return rb_str_new2("");
154
+ }
155
+
156
+ Check_Type(str, T_STRING);
157
+
158
+ VALUE rb_output_buf;
159
+ unsigned char *inBuf = (unsigned char*)RSTRING_PTR(str);
160
+ size_t len = RSTRING_LEN(str), new_len = 0;
161
+
162
+ // this is the max size the string could be
163
+ // TODO: we should try to be more intelligent about this
164
+ unsigned char *outBuf = (unsigned char *)malloc(sizeof(unsigned char *)*(len*2));
165
+
166
+ // perform our escape, returning the new string's length
167
+ new_len = escape_javascript(outBuf, inBuf, len);
168
+
169
+ // create our new ruby string
170
+ rb_output_buf = rb_str_new((char *)outBuf, new_len);
171
+
172
+ // free the temporary C string
173
+ free(outBuf);
174
+
175
+ return rb_output_buf;
176
+ }
177
+
117
178
  /* Ruby Extension initializer */
118
179
  void Init_escape_utils_ext() {
119
180
  VALUE mEscape = rb_define_module("EscapeUtils");
@@ -121,4 +182,6 @@ void Init_escape_utils_ext() {
121
182
  rb_define_module_function(mEscape, "escape_html", rb_escape_html, 1);
122
183
  rb_define_method(mEscape, "unescape_html", rb_unescape_html, 1);
123
184
  rb_define_module_function(mEscape, "unescape_html", rb_unescape_html, 1);
185
+ rb_define_method(mEscape, "escape_javascript", rb_escape_javascript, 1);
186
+ rb_define_module_function(mEscape, "escape_javascript", rb_escape_javascript, 1);
124
187
  }
@@ -4,5 +4,5 @@ require 'escape_utils_ext'
4
4
 
5
5
  EscapeUtils.send(:extend, EscapeUtils)
6
6
  module EscapeUtils
7
- VERSION = "0.0.1"
7
+ VERSION = "0.1.1"
8
8
  end
@@ -1,26 +1,24 @@
1
1
  # encoding: UTF-8
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
3
 
4
- describe EscapeUtils do
4
+ describe EscapeUtils, "escape_html" do
5
5
  it "should respond to escape_html" do
6
6
  EscapeUtils.should respond_to(:escape_html)
7
7
  end
8
8
 
9
- context "escape_html" do
10
- it "should escape a basic html tag" do
11
- EscapeUtils.escape_html("<some_tag/>").should eql("&lt;some_tag/&gt;")
12
- end
9
+ it "should escape a basic html tag" do
10
+ EscapeUtils.escape_html("<some_tag/>").should eql("&lt;some_tag/&gt;")
11
+ end
13
12
 
14
- it "should escape double-quotes" do
15
- EscapeUtils.escape_html("<some_tag some_attr=\"some value\"/>").should eql("&lt;some_tag some_attr=&quot;some value&quot;/&gt;")
16
- end
13
+ it "should escape double-quotes" do
14
+ EscapeUtils.escape_html("<some_tag some_attr=\"some value\"/>").should eql("&lt;some_tag some_attr=&quot;some value&quot;/&gt;")
15
+ end
17
16
 
18
- it "should escape single-quotes" do
19
- EscapeUtils.escape_html("<some_tag some_attr='some value'/>").should eql("&lt;some_tag some_attr=&#39;some value&#39;/&gt;")
20
- end
17
+ it "should escape single-quotes" do
18
+ EscapeUtils.escape_html("<some_tag some_attr='some value'/>").should eql("&lt;some_tag some_attr=&#39;some value&#39;/&gt;")
19
+ end
21
20
 
22
- it "should escape the & character" do
23
- EscapeUtils.escape_html("<b>Bourbon & Branch</b>").should eql("&lt;b&gt;Bourbon &amp; Branch&lt;/b&gt;")
24
- end
21
+ it "should escape the & character" do
22
+ EscapeUtils.escape_html("<b>Bourbon & Branch</b>").should eql("&lt;b&gt;Bourbon &amp; Branch&lt;/b&gt;")
25
23
  end
26
24
  end
@@ -1,26 +1,24 @@
1
1
  # encoding: UTF-8
2
2
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
3
 
4
- describe EscapeUtils do
4
+ describe EscapeUtils, "unescape_html" do
5
5
  it "should respond to unescape_html" do
6
6
  EscapeUtils.should respond_to(:unescape_html)
7
7
  end
8
8
 
9
- context "unescape_html" do
10
- it "should unescape a basic html tag" do
11
- EscapeUtils.unescape_html("&lt;some_tag/&gt;").should eql("<some_tag/>")
12
- end
9
+ it "should unescape a basic html tag" do
10
+ EscapeUtils.unescape_html("&lt;some_tag/&gt;").should eql("<some_tag/>")
11
+ end
13
12
 
14
- it "should unescape double-quotes" do
15
- EscapeUtils.unescape_html("&lt;some_tag some_attr=&quot;some value&quot;/&gt;").should eql("<some_tag some_attr=\"some value\"/>")
16
- end
13
+ it "should unescape double-quotes" do
14
+ EscapeUtils.unescape_html("&lt;some_tag some_attr=&quot;some value&quot;/&gt;").should eql("<some_tag some_attr=\"some value\"/>")
15
+ end
17
16
 
18
- it "should unescape single-quotes" do
19
- EscapeUtils.unescape_html("&lt;some_tag some_attr=&#39;some value&#39;/&gt;").should eql("<some_tag some_attr='some value'/>")
20
- end
17
+ it "should unescape single-quotes" do
18
+ EscapeUtils.unescape_html("&lt;some_tag some_attr=&#39;some value&#39;/&gt;").should eql("<some_tag some_attr='some value'/>")
19
+ end
21
20
 
22
- it "should unescape the & character" do
23
- EscapeUtils.unescape_html("&lt;b&gt;Bourbon &amp; Branch&lt;/b&gt;").should eql("<b>Bourbon & Branch</b>")
24
- end
21
+ it "should unescape the & character" do
22
+ EscapeUtils.unescape_html("&lt;b&gt;Bourbon &amp; Branch&lt;/b&gt;").should eql("<b>Bourbon & Branch</b>")
25
23
  end
26
24
  end
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+
4
+ describe EscapeUtils, "escape_javascript" do
5
+ it "should respond to escape_javascript" do
6
+ EscapeUtils.should respond_to(:escape_javascript)
7
+ end
8
+
9
+ # these are from the ActionView tests
10
+ it "should return an empty string if passed nil" do
11
+ EscapeUtils.escape_javascript(nil).should eql("")
12
+ end
13
+
14
+ it "should escape quotes and newlines" do
15
+ EscapeUtils.escape_javascript(%(This "thing" is really\n netos')).should eql(%(This \\"thing\\" is really\\n netos\\'))
16
+ end
17
+
18
+ it "should escape backslashes" do
19
+ EscapeUtils.escape_javascript(%(backslash\\test)).should eql(%(backslash\\\\test))
20
+ end
21
+
22
+ it "should escape closed html tags" do
23
+ EscapeUtils.escape_javascript(%(dont </close> tags)).should eql(%(dont <\\/close> tags))
24
+ end
25
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 0
9
- version: 0.1.0
8
+ - 1
9
+ version: 0.1.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Lopez
@@ -33,8 +33,9 @@ files:
33
33
  - README.rdoc
34
34
  - Rakefile
35
35
  - VERSION
36
- - benchmark/escape.rb
37
- - benchmark/unescape.rb
36
+ - benchmark/html_escape.rb
37
+ - benchmark/html_unescape.rb
38
+ - benchmark/javascript_escape.rb
38
39
  - escape_utils.gemspec
39
40
  - ext/escape_utils.c
40
41
  - ext/extconf.rb
@@ -45,6 +46,7 @@ files:
45
46
  - lib/escape_utils/rack.rb
46
47
  - spec/html/escape_spec.rb
47
48
  - spec/html/unescape_spec.rb
49
+ - spec/javascript/escape_spec.rb
48
50
  - spec/rcov.opts
49
51
  - spec/spec.opts
50
52
  - spec/spec_helper.rb
@@ -82,4 +84,5 @@ summary: Faster string escaping routines for your web apps
82
84
  test_files:
83
85
  - spec/html/escape_spec.rb
84
86
  - spec/html/unescape_spec.rb
87
+ - spec/javascript/escape_spec.rb
85
88
  - spec/spec_helper.rb