escape_utils 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/benchmark/html_escape.rb +13 -13
- data/benchmark/html_unescape.rb +9 -9
- data/benchmark/javascript_escape.rb +9 -9
- data/benchmark/javascript_unescape.rb +6 -8
- data/benchmark/url_escape.rb +13 -13
- data/benchmark/url_unescape.rb +14 -14
- data/benchmark/xml_escape.rb +10 -10
- data/escape_utils.gemspec +5 -3
- data/ext/escape_utils/buffer.c +1 -1
- data/ext/escape_utils/escape_utils.c +22 -3
- data/ext/escape_utils/houdini.h +2 -0
- data/ext/escape_utils/houdini_html_u.c +1 -1
- data/ext/escape_utils/houdini_uri_e.c +11 -5
- data/ext/escape_utils/houdini_uri_u.c +15 -12
- data/lib/escape_utils/version.rb +1 -1
- data/test/html/escape_test.rb +12 -0
- data/test/uri/escape_test.rb +8 -0
- data/test/uri/unescape_test.rb +14 -3
- data/test/uri_component/escape_test.rb +68 -0
- data/test/uri_component/unescape_test.rb +71 -0
- data/test/url/escape_test.rb +9 -1
- data/test/url/unescape_test.rb +14 -3
- metadata +45 -27
- data/CHANGELOG.md +0 -75
- data/MIT-LICENSE +0 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a359a0da23b56ac37301e4ae73060dcfc4870d14
|
|
4
|
+
data.tar.gz: 2a3c9ed36204fc638605f012c3ca5a87ccc756b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f862189c73f7858184a61a0e2ae78b2d344ac162022bd41ec77eb18eba6ae52a62e188d29b2b7ed2931ae47a4d6a33b2f8d6ecf82ef85e46ce1457e016897403
|
|
7
|
+
data.tar.gz: 8f4a4643def62dfd8fdb27d9d631aa452bca3e63e1672a70bcf95594f98040ccee00276d6c0abd8e90c11126b7932b6e0efcce9e7d0b2881523b6faed62cad1b
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Brian Lopez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/benchmark/html_escape.rb
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
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
2
|
|
|
5
3
|
require 'rubygems'
|
|
6
|
-
require '
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'benchmark/ips'
|
|
7
6
|
|
|
8
7
|
require 'rack'
|
|
9
8
|
require 'erb'
|
|
@@ -16,53 +15,54 @@ module HamlBench
|
|
|
16
15
|
extend Haml::Helpers
|
|
17
16
|
end
|
|
18
17
|
|
|
19
|
-
times = 100
|
|
20
18
|
url = "http://en.wikipedia.org/wiki/Line_of_succession_to_the_British_throne"
|
|
21
19
|
html = `curl -s #{url}`
|
|
22
20
|
html = html.force_encoding('utf-8') if html.respond_to?(:force_encoding)
|
|
23
|
-
puts "Escaping #{html.bytesize} bytes of html
|
|
21
|
+
puts "Escaping #{html.bytesize} bytes of html from #{url}"
|
|
24
22
|
|
|
25
|
-
Benchmark.
|
|
26
|
-
x.report "Rack::Utils.escape_html" do
|
|
23
|
+
Benchmark.ips do |x|
|
|
24
|
+
x.report "Rack::Utils.escape_html" do |times|
|
|
27
25
|
times.times do
|
|
28
26
|
Rack::Utils.escape_html(html)
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
|
|
32
|
-
x.report "Haml::Helpers.html_escape" do
|
|
30
|
+
x.report "Haml::Helpers.html_escape" do |times|
|
|
33
31
|
times.times do
|
|
34
32
|
HamlBench.html_escape(html)
|
|
35
33
|
end
|
|
36
34
|
end
|
|
37
35
|
|
|
38
|
-
x.report "ERB::Util.html_escape" do
|
|
36
|
+
x.report "ERB::Util.html_escape" do |times|
|
|
39
37
|
times.times do
|
|
40
38
|
ERB::Util.html_escape(html)
|
|
41
39
|
end
|
|
42
40
|
end
|
|
43
41
|
|
|
44
|
-
x.report "CGI.escapeHTML" do
|
|
42
|
+
x.report "CGI.escapeHTML" do |times|
|
|
45
43
|
times.times do
|
|
46
44
|
CGI.escapeHTML(html)
|
|
47
45
|
end
|
|
48
46
|
end
|
|
49
47
|
|
|
50
|
-
x.report "String#gsub" do
|
|
48
|
+
x.report "String#gsub" do |times|
|
|
51
49
|
html_escape = { '&' => '&', '>' => '>', '<' => '<', '"' => '"', "'" => ''' }
|
|
52
50
|
times.times do
|
|
53
51
|
html.gsub(/[&"'><]/, html_escape)
|
|
54
52
|
end
|
|
55
53
|
end
|
|
56
54
|
|
|
57
|
-
x.report "fast_xs_extra#fast_xs_html" do
|
|
55
|
+
x.report "fast_xs_extra#fast_xs_html" do |times|
|
|
58
56
|
times.times do
|
|
59
57
|
html.fast_xs_html
|
|
60
58
|
end
|
|
61
59
|
end
|
|
62
60
|
|
|
63
|
-
x.report "EscapeUtils.escape_html" do
|
|
61
|
+
x.report "EscapeUtils.escape_html" do |times|
|
|
64
62
|
times.times do
|
|
65
63
|
EscapeUtils.escape_html(html)
|
|
66
64
|
end
|
|
67
65
|
end
|
|
66
|
+
|
|
67
|
+
x.compare!
|
|
68
68
|
end
|
data/benchmark/html_unescape.rb
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
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
2
|
|
|
5
3
|
require 'rubygems'
|
|
6
|
-
require '
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'benchmark/ips'
|
|
7
6
|
|
|
8
7
|
require 'cgi'
|
|
9
8
|
require 'haml'
|
|
@@ -13,23 +12,24 @@ module HamlBench
|
|
|
13
12
|
extend Haml::Helpers
|
|
14
13
|
end
|
|
15
14
|
|
|
16
|
-
times = 100
|
|
17
15
|
url = "http://en.wikipedia.org/wiki/Line_of_succession_to_the_British_throne"
|
|
18
16
|
html = `curl -s #{url}`
|
|
19
17
|
html = html.force_encoding('binary') if html.respond_to?(:force_encoding)
|
|
20
18
|
escaped_html = EscapeUtils.escape_html(html)
|
|
21
|
-
puts "Unescaping #{escaped_html.bytesize} bytes of escaped html
|
|
19
|
+
puts "Unescaping #{escaped_html.bytesize} bytes of escaped html, from #{url}"
|
|
22
20
|
|
|
23
|
-
Benchmark.
|
|
24
|
-
x.report "CGI.unescapeHTML" do
|
|
21
|
+
Benchmark.ips do |x|
|
|
22
|
+
x.report "CGI.unescapeHTML" do |times|
|
|
25
23
|
times.times do
|
|
26
24
|
CGI.unescapeHTML(escaped_html)
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
|
|
30
|
-
x.report "EscapeUtils.unescape_html" do
|
|
28
|
+
x.report "EscapeUtils.unescape_html" do |times|
|
|
31
29
|
times.times do
|
|
32
30
|
EscapeUtils.unescape_html(escaped_html)
|
|
33
31
|
end
|
|
34
32
|
end
|
|
35
|
-
|
|
33
|
+
|
|
34
|
+
x.compare!
|
|
35
|
+
end
|
|
@@ -1,9 +1,8 @@
|
|
|
1
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
2
|
|
|
5
3
|
require 'rubygems'
|
|
6
|
-
require '
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'benchmark/ips'
|
|
7
6
|
|
|
8
7
|
require 'action_view'
|
|
9
8
|
require 'escape_utils'
|
|
@@ -12,22 +11,23 @@ class ActionPackBench
|
|
|
12
11
|
extend ActionView::Helpers::JavaScriptHelper
|
|
13
12
|
end
|
|
14
13
|
|
|
15
|
-
times = 100
|
|
16
14
|
url = "http://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js.uncompressed.js"
|
|
17
15
|
javascript = `curl -s #{url}`
|
|
18
16
|
javascript = javascript.force_encoding('utf-8') if javascript.respond_to?(:force_encoding)
|
|
19
|
-
puts "Escaping #{javascript.bytesize} bytes of javascript
|
|
17
|
+
puts "Escaping #{javascript.bytesize} bytes of javascript, from #{url}"
|
|
20
18
|
|
|
21
|
-
Benchmark.
|
|
22
|
-
x.report "ActionView::Helpers::JavaScriptHelper#escape_javascript" do
|
|
19
|
+
Benchmark.ips do |x|
|
|
20
|
+
x.report "ActionView::Helpers::JavaScriptHelper#escape_javascript" do |times|
|
|
23
21
|
times.times do
|
|
24
22
|
ActionPackBench.escape_javascript(javascript)
|
|
25
23
|
end
|
|
26
24
|
end
|
|
27
25
|
|
|
28
|
-
x.report "EscapeUtils.escape_javascript" do
|
|
26
|
+
x.report "EscapeUtils.escape_javascript" do |times|
|
|
29
27
|
times.times do
|
|
30
28
|
EscapeUtils.escape_javascript(javascript)
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
|
-
|
|
31
|
+
|
|
32
|
+
x.compare!
|
|
33
|
+
end
|
|
@@ -1,23 +1,21 @@
|
|
|
1
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
2
|
|
|
5
3
|
require 'rubygems'
|
|
6
|
-
require '
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'benchmark/ips'
|
|
7
6
|
|
|
8
7
|
require 'escape_utils'
|
|
9
8
|
|
|
10
|
-
times = 100
|
|
11
9
|
url = "http://ajax.googleapis.com/ajax/libs/dojo/1.4.3/dojo/dojo.xd.js.uncompressed.js"
|
|
12
10
|
javascript = `curl -s #{url}`
|
|
13
11
|
javascript = javascript.force_encoding('utf-8') if javascript.respond_to?(:force_encoding)
|
|
14
12
|
escaped_javascript = EscapeUtils.escape_javascript(javascript)
|
|
15
|
-
puts "Escaping #{escaped_javascript.bytesize} bytes of javascript
|
|
13
|
+
puts "Escaping #{escaped_javascript.bytesize} bytes of javascript, from #{url}"
|
|
16
14
|
|
|
17
|
-
Benchmark.
|
|
18
|
-
x.report "EscapeUtils.escape_javascript" do
|
|
15
|
+
Benchmark.ips do |x|
|
|
16
|
+
x.report "EscapeUtils.escape_javascript" do |times|
|
|
19
17
|
times.times do
|
|
20
18
|
EscapeUtils.unescape_javascript(escaped_javascript)
|
|
21
19
|
end
|
|
22
20
|
end
|
|
23
|
-
end
|
|
21
|
+
end
|
data/benchmark/url_escape.rb
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
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
2
|
|
|
5
3
|
require 'rubygems'
|
|
6
|
-
require '
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'benchmark/ips'
|
|
7
6
|
|
|
8
7
|
require 'rack'
|
|
9
8
|
require 'erb'
|
|
@@ -12,45 +11,46 @@ require 'url_escape'
|
|
|
12
11
|
require 'fast_xs_extra'
|
|
13
12
|
require 'escape_utils'
|
|
14
13
|
|
|
15
|
-
times = 10_000
|
|
16
14
|
url = "https://www.yourmom.com/cgi-bin/session.cgi?sess_args=mYHcEA dh435dqUs0moGHeeAJTSLLbdbcbd9ef----,574b95600e9ab7d27eb0bf524ac68c27----"
|
|
17
15
|
url = url.force_encoding('us-ascii') if url.respond_to?(:force_encoding)
|
|
18
|
-
puts "Escaping a #{url.bytesize} byte URL
|
|
16
|
+
puts "Escaping a #{url.bytesize} byte URL times"
|
|
19
17
|
|
|
20
|
-
Benchmark.
|
|
21
|
-
x.report "ERB::Util.url_encode" do
|
|
18
|
+
Benchmark.ips do |x|
|
|
19
|
+
x.report "ERB::Util.url_encode" do |times|
|
|
22
20
|
times.times do
|
|
23
21
|
ERB::Util.url_encode(url)
|
|
24
22
|
end
|
|
25
23
|
end
|
|
26
24
|
|
|
27
|
-
x.report "Rack::Utils.escape" do
|
|
25
|
+
x.report "Rack::Utils.escape" do |times|
|
|
28
26
|
times.times do
|
|
29
27
|
Rack::Utils.escape(url)
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
30
|
|
|
33
|
-
x.report "CGI.escape" do
|
|
31
|
+
x.report "CGI.escape" do |times|
|
|
34
32
|
times.times do
|
|
35
33
|
CGI.escape(url)
|
|
36
34
|
end
|
|
37
35
|
end
|
|
38
36
|
|
|
39
|
-
x.report "URLEscape#escape" do
|
|
37
|
+
x.report "URLEscape#escape" do |times|
|
|
40
38
|
times.times do
|
|
41
39
|
URLEscape.escape(url)
|
|
42
40
|
end
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
x.report "fast_xs_extra#fast_xs_url" do
|
|
43
|
+
x.report "fast_xs_extra#fast_xs_url" do |times|
|
|
46
44
|
times.times do
|
|
47
45
|
url.fast_xs_url
|
|
48
46
|
end
|
|
49
47
|
end
|
|
50
48
|
|
|
51
|
-
x.report "EscapeUtils.escape_url" do
|
|
49
|
+
x.report "EscapeUtils.escape_url" do |times|
|
|
52
50
|
times.times do
|
|
53
51
|
EscapeUtils.escape_url(url)
|
|
54
52
|
end
|
|
55
53
|
end
|
|
56
|
-
|
|
54
|
+
|
|
55
|
+
x.compare!
|
|
56
|
+
end
|
data/benchmark/url_unescape.rb
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
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
2
|
|
|
5
3
|
require 'rubygems'
|
|
6
|
-
require '
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'benchmark/ips'
|
|
7
6
|
|
|
8
7
|
require 'rack'
|
|
9
8
|
require 'cgi'
|
|
@@ -11,40 +10,41 @@ require 'url_escape'
|
|
|
11
10
|
require 'fast_xs_extra'
|
|
12
11
|
require 'escape_utils'
|
|
13
12
|
|
|
14
|
-
times = 10_000
|
|
15
13
|
url = "https://www.yourmom.com/cgi-bin/session.cgi?sess_args=mYHcEA dh435dqUs0moGHeeAJTSLLbdbcbd9ef----,574b95600e9ab7d27eb0bf524ac68c27----"
|
|
16
14
|
url = url.force_encoding('us-ascii') if url.respond_to?(:force_encoding)
|
|
17
15
|
escaped_url = EscapeUtils.escape_url(url)
|
|
18
|
-
puts "Escaping a #{url.bytesize} byte URL
|
|
16
|
+
puts "Escaping a #{url.bytesize} byte URL"
|
|
19
17
|
|
|
20
|
-
Benchmark.
|
|
21
|
-
x.report "Rack::Utils.unescape" do
|
|
18
|
+
Benchmark.ips do |x|
|
|
19
|
+
x.report "Rack::Utils.unescape" do |times|
|
|
22
20
|
times.times do
|
|
23
21
|
Rack::Utils.unescape(escaped_url)
|
|
24
22
|
end
|
|
25
23
|
end
|
|
26
|
-
|
|
27
|
-
x.report "CGI.unescape" do
|
|
24
|
+
|
|
25
|
+
x.report "CGI.unescape" do |times|
|
|
28
26
|
times.times do
|
|
29
27
|
CGI.unescape(escaped_url)
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
|
-
|
|
33
|
-
x.report "URLEscape#unescape" do
|
|
30
|
+
|
|
31
|
+
x.report "URLEscape#unescape" do |times|
|
|
34
32
|
times.times do
|
|
35
33
|
URLEscape.unescape(escaped_url)
|
|
36
34
|
end
|
|
37
35
|
end
|
|
38
36
|
|
|
39
|
-
x.report "fast_xs_extra#fast_uxs_cgi" do
|
|
37
|
+
x.report "fast_xs_extra#fast_uxs_cgi" do |times|
|
|
40
38
|
times.times do
|
|
41
39
|
url.fast_uxs_cgi
|
|
42
40
|
end
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
x.report "EscapeUtils.unescape_url" do
|
|
43
|
+
x.report "EscapeUtils.unescape_url" do |times|
|
|
46
44
|
times.times do
|
|
47
45
|
EscapeUtils.unescape_url(escaped_url)
|
|
48
46
|
end
|
|
49
47
|
end
|
|
50
|
-
|
|
48
|
+
|
|
49
|
+
x.compare!
|
|
50
|
+
end
|
data/benchmark/xml_escape.rb
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
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
2
|
|
|
5
3
|
require 'rubygems'
|
|
6
|
-
require '
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'benchmark/ips'
|
|
7
6
|
|
|
8
|
-
require '
|
|
7
|
+
require 'fast_xs'
|
|
9
8
|
require 'escape_utils'
|
|
10
9
|
|
|
11
|
-
times = 100
|
|
12
10
|
url = "http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml"
|
|
13
11
|
xml = `curl -s #{url}`
|
|
14
12
|
xml = xml.force_encoding('binary') if xml.respond_to?(:force_encoding)
|
|
15
|
-
puts "Escaping #{xml.bytesize} bytes of xml
|
|
13
|
+
puts "Escaping #{xml.bytesize} bytes of xml, from #{url}"
|
|
16
14
|
|
|
17
|
-
Benchmark.
|
|
18
|
-
x.report "
|
|
15
|
+
Benchmark.ips do |x|
|
|
16
|
+
x.report "fast_xs" do |times|
|
|
19
17
|
times.times do
|
|
20
|
-
xml.
|
|
18
|
+
xml.fast_xs
|
|
21
19
|
end
|
|
22
20
|
end
|
|
23
21
|
|
|
24
|
-
x.report "EscapeUtils.escape_xml" do
|
|
22
|
+
x.report "EscapeUtils.escape_xml" do |times|
|
|
25
23
|
times.times do
|
|
26
24
|
EscapeUtils.escape_xml(xml)
|
|
27
25
|
end
|
|
28
26
|
end
|
|
27
|
+
|
|
28
|
+
x.compare!
|
|
29
29
|
end
|
data/escape_utils.gemspec
CHANGED
|
@@ -7,23 +7,25 @@ Gem::Specification.new do |s|
|
|
|
7
7
|
s.email = %q{seniorlopez@gmail.com}
|
|
8
8
|
s.extensions = ["ext/escape_utils/extconf.rb"]
|
|
9
9
|
s.files = `git ls-files`.split("\n")
|
|
10
|
-
s.homepage = %q{
|
|
10
|
+
s.homepage = %q{https://github.com/brianmario/escape_utils}
|
|
11
|
+
s.license = %q{MIT}
|
|
11
12
|
s.rdoc_options = ["--charset=UTF-8"]
|
|
12
13
|
s.require_paths = ["lib"]
|
|
13
14
|
s.rubygems_version = %q{1.4.2}
|
|
14
15
|
s.summary = %q{Faster string escaping routines for your web apps}
|
|
16
|
+
s.description = %q{Quickly perform HTML, URL, URI and Javascript escaping/unescaping}
|
|
15
17
|
s.test_files = `git ls-files test`.split("\n")
|
|
16
18
|
|
|
17
|
-
s.required_ruby_version = "
|
|
19
|
+
s.required_ruby_version = ">= 1.9.3"
|
|
18
20
|
|
|
19
21
|
# tests
|
|
20
22
|
s.add_development_dependency 'rake-compiler', ">= 0.7.5"
|
|
21
23
|
s.add_development_dependency 'minitest', ">= 5.0.0"
|
|
22
24
|
# benchmarks
|
|
25
|
+
s.add_development_dependency 'benchmark-ips'
|
|
23
26
|
s.add_development_dependency 'rack'
|
|
24
27
|
s.add_development_dependency 'haml'
|
|
25
28
|
s.add_development_dependency 'fast_xs'
|
|
26
29
|
s.add_development_dependency 'actionpack'
|
|
27
30
|
s.add_development_dependency 'url_escape'
|
|
28
31
|
end
|
|
29
|
-
|
data/ext/escape_utils/buffer.c
CHANGED
|
@@ -242,7 +242,7 @@ void gh_buf_attach(gh_buf *buf, char *ptr, size_t asize)
|
|
|
242
242
|
|
|
243
243
|
int gh_buf_cmp(const gh_buf *a, const gh_buf *b)
|
|
244
244
|
{
|
|
245
|
-
int result = memcmp(a->ptr, b->ptr, (a->size
|
|
245
|
+
int result = memcmp(a->ptr, b->ptr, MIN(a->size, b->size));
|
|
246
246
|
return (result != 0) ? result :
|
|
247
247
|
(a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0;
|
|
248
248
|
}
|
|
@@ -96,6 +96,11 @@ rb_eu__generic(VALUE str, houdini_cb do_escape)
|
|
|
96
96
|
/**
|
|
97
97
|
* HTML methods
|
|
98
98
|
*/
|
|
99
|
+
static VALUE new_html_safe_string(const char *ptr, size_t len)
|
|
100
|
+
{
|
|
101
|
+
return rb_str_new_with_class(rb_html_safe_string_template_object, ptr, len);
|
|
102
|
+
}
|
|
103
|
+
|
|
99
104
|
static VALUE rb_eu_escape_html_as_html_safe(VALUE self, VALUE str)
|
|
100
105
|
{
|
|
101
106
|
VALUE result;
|
|
@@ -106,11 +111,10 @@ static VALUE rb_eu_escape_html_as_html_safe(VALUE self, VALUE str)
|
|
|
106
111
|
check_utf8_encoding(str);
|
|
107
112
|
|
|
108
113
|
if (houdini_escape_html0(&buf, (const uint8_t *)RSTRING_PTR(str), RSTRING_LEN(str), secure)) {
|
|
109
|
-
result =
|
|
114
|
+
result = new_html_safe_string(buf.ptr, buf.size);
|
|
110
115
|
gh_buf_free(&buf);
|
|
111
116
|
} else {
|
|
112
|
-
result =
|
|
113
|
-
RSTRING_PTR(str), RSTRING_LEN(str));
|
|
117
|
+
result = new_html_safe_string(RSTRING_PTR(str), RSTRING_LEN(str));
|
|
114
118
|
}
|
|
115
119
|
|
|
116
120
|
rb_ivar_set(result, ID_at_html_safe, Qtrue);
|
|
@@ -198,6 +202,19 @@ static VALUE rb_eu_unescape_uri(VALUE self, VALUE str)
|
|
|
198
202
|
return rb_eu__generic(str, &houdini_unescape_uri);
|
|
199
203
|
}
|
|
200
204
|
|
|
205
|
+
/**
|
|
206
|
+
* URI component methods
|
|
207
|
+
*/
|
|
208
|
+
static VALUE rb_eu_escape_uri_component(VALUE self, VALUE str)
|
|
209
|
+
{
|
|
210
|
+
return rb_eu__generic(str, &houdini_escape_uri_component);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
static VALUE rb_eu_unescape_uri_component(VALUE self, VALUE str)
|
|
214
|
+
{
|
|
215
|
+
return rb_eu__generic(str, &houdini_unescape_uri_component);
|
|
216
|
+
}
|
|
217
|
+
|
|
201
218
|
|
|
202
219
|
/**
|
|
203
220
|
* Ruby Extension initializer
|
|
@@ -223,6 +240,8 @@ void Init_escape_utils()
|
|
|
223
240
|
rb_define_method(rb_mEscapeUtils, "unescape_url", rb_eu_unescape_url, 1);
|
|
224
241
|
rb_define_method(rb_mEscapeUtils, "escape_uri", rb_eu_escape_uri, 1);
|
|
225
242
|
rb_define_method(rb_mEscapeUtils, "unescape_uri", rb_eu_unescape_uri, 1);
|
|
243
|
+
rb_define_method(rb_mEscapeUtils, "escape_uri_component", rb_eu_escape_uri_component, 1);
|
|
244
|
+
rb_define_method(rb_mEscapeUtils, "unescape_uri_component", rb_eu_unescape_uri_component, 1);
|
|
226
245
|
|
|
227
246
|
rb_define_singleton_method(rb_mEscapeUtils, "html_secure=", rb_eu_set_html_secure, 1);
|
|
228
247
|
rb_define_singleton_method(rb_mEscapeUtils, "html_safe_string_class=", rb_eu_set_html_safe_string_class, 1);
|
data/ext/escape_utils/houdini.h
CHANGED
|
@@ -30,9 +30,11 @@ extern int houdini_escape_html0(gh_buf *ob, const uint8_t *src, size_t size, int
|
|
|
30
30
|
extern int houdini_unescape_html(gh_buf *ob, const uint8_t *src, size_t size);
|
|
31
31
|
extern int houdini_escape_xml(gh_buf *ob, const uint8_t *src, size_t size);
|
|
32
32
|
extern int houdini_escape_uri(gh_buf *ob, const uint8_t *src, size_t size);
|
|
33
|
+
extern int houdini_escape_uri_component(gh_buf *ob, const uint8_t *src, size_t size);
|
|
33
34
|
extern int houdini_escape_url(gh_buf *ob, const uint8_t *src, size_t size);
|
|
34
35
|
extern int houdini_escape_href(gh_buf *ob, const uint8_t *src, size_t size);
|
|
35
36
|
extern int houdini_unescape_uri(gh_buf *ob, const uint8_t *src, size_t size);
|
|
37
|
+
extern int houdini_unescape_uri_component(gh_buf *ob, const uint8_t *src, size_t size);
|
|
36
38
|
extern int houdini_unescape_url(gh_buf *ob, const uint8_t *src, size_t size);
|
|
37
39
|
extern int houdini_escape_js(gh_buf *ob, const uint8_t *src, size_t size);
|
|
38
40
|
extern int houdini_unescape_js(gh_buf *ob, const uint8_t *src, size_t size);
|
|
@@ -57,7 +57,7 @@ unescape_ent(gh_buf *ob, const uint8_t *src, size_t size)
|
|
|
57
57
|
codepoint = (codepoint * 16) + ((src[i] | 32) % 39 - 9);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
if (i < size && src[i] == ';') {
|
|
60
|
+
if (i < size && src[i] == ';' && codepoint) {
|
|
61
61
|
gh_buf_put_utf8(ob, codepoint);
|
|
62
62
|
return i + 1;
|
|
63
63
|
}
|
|
@@ -43,10 +43,10 @@ static const char URI_SAFE[] = {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
static int
|
|
46
|
-
escape(gh_buf *ob, const uint8_t *src, size_t size,
|
|
46
|
+
escape(gh_buf *ob, const uint8_t *src, size_t size,
|
|
47
|
+
const char *safe_table, bool escape_plus)
|
|
47
48
|
{
|
|
48
49
|
static const uint8_t hex_chars[] = "0123456789ABCDEF";
|
|
49
|
-
const char *safe_table = is_url ? URL_SAFE : URI_SAFE;
|
|
50
50
|
|
|
51
51
|
size_t i = 0, org;
|
|
52
52
|
uint8_t hex_str[3];
|
|
@@ -73,7 +73,7 @@ escape(gh_buf *ob, const uint8_t *src, size_t size, int is_url)
|
|
|
73
73
|
if (i >= size)
|
|
74
74
|
break;
|
|
75
75
|
|
|
76
|
-
if (src[i] == ' ' &&
|
|
76
|
+
if (src[i] == ' ' && escape_plus) {
|
|
77
77
|
gh_buf_putc(ob, '+');
|
|
78
78
|
} else {
|
|
79
79
|
hex_str[1] = hex_chars[(src[i] >> 4) & 0xF];
|
|
@@ -90,12 +90,18 @@ escape(gh_buf *ob, const uint8_t *src, size_t size, int is_url)
|
|
|
90
90
|
int
|
|
91
91
|
houdini_escape_uri(gh_buf *ob, const uint8_t *src, size_t size)
|
|
92
92
|
{
|
|
93
|
-
return escape(ob, src, size,
|
|
93
|
+
return escape(ob, src, size, URI_SAFE, false);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
int
|
|
97
|
+
houdini_escape_uri_component(gh_buf *ob, const uint8_t *src, size_t size)
|
|
98
|
+
{
|
|
99
|
+
return escape(ob, src, size, URL_SAFE, false);
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
int
|
|
97
103
|
houdini_escape_url(gh_buf *ob, const uint8_t *src, size_t size)
|
|
98
104
|
{
|
|
99
|
-
return escape(ob, src, size,
|
|
105
|
+
return escape(ob, src, size, URL_SAFE, true);
|
|
100
106
|
}
|
|
101
107
|
|
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
#define hex2c(c) ((c | 32) % 39 - 9)
|
|
8
8
|
|
|
9
9
|
static int
|
|
10
|
-
unescape(gh_buf *ob, const uint8_t *src, size_t size,
|
|
10
|
+
unescape(gh_buf *ob, const uint8_t *src, size_t size, bool unescape_plus)
|
|
11
11
|
{
|
|
12
12
|
size_t i = 0, org;
|
|
13
13
|
|
|
14
14
|
while (i < size) {
|
|
15
15
|
org = i;
|
|
16
|
-
while (i < size && src[i] != '%')
|
|
16
|
+
while (i < size && src[i] != '%' && src[i] != '+')
|
|
17
17
|
i++;
|
|
18
18
|
|
|
19
19
|
if (likely(i > org)) {
|
|
20
20
|
if (unlikely(org == 0)) {
|
|
21
|
-
if (i >= size
|
|
21
|
+
if (i >= size)
|
|
22
22
|
return 0;
|
|
23
23
|
|
|
24
24
|
gh_buf_grow(ob, HOUDINI_UNESCAPED_SIZE(size));
|
|
@@ -31,7 +31,10 @@ unescape(gh_buf *ob, const uint8_t *src, size_t size, int is_url)
|
|
|
31
31
|
if (i >= size)
|
|
32
32
|
break;
|
|
33
33
|
|
|
34
|
-
i
|
|
34
|
+
if (src[i++] == '+') {
|
|
35
|
+
gh_buf_putc(ob, unescape_plus ? ' ' : '+');
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
35
38
|
|
|
36
39
|
if (i + 1 < size && _isxdigit(src[i]) && _isxdigit(src[i + 1])) {
|
|
37
40
|
unsigned char new_char = (hex2c(src[i]) << 4) + hex2c(src[i + 1]);
|
|
@@ -42,24 +45,24 @@ unescape(gh_buf *ob, const uint8_t *src, size_t size, int is_url)
|
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
if (is_url) {
|
|
46
|
-
char *find = (char *)gh_buf_cstr(ob);
|
|
47
|
-
while ((find = strchr(find, '+')) != NULL)
|
|
48
|
-
*find = ' ';
|
|
49
|
-
}
|
|
50
|
-
|
|
51
48
|
return 1;
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
int
|
|
55
52
|
houdini_unescape_uri(gh_buf *ob, const uint8_t *src, size_t size)
|
|
56
53
|
{
|
|
57
|
-
return unescape(ob, src, size,
|
|
54
|
+
return unescape(ob, src, size, false);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
int
|
|
58
|
+
houdini_unescape_uri_component(gh_buf *ob, const uint8_t *src, size_t size)
|
|
59
|
+
{
|
|
60
|
+
return unescape(ob, src, size, false);
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
int
|
|
61
64
|
houdini_unescape_url(gh_buf *ob, const uint8_t *src, size_t size)
|
|
62
65
|
{
|
|
63
|
-
return unescape(ob, src, size,
|
|
66
|
+
return unescape(ob, src, size, true);
|
|
64
67
|
}
|
|
65
68
|
|
data/lib/escape_utils/version.rb
CHANGED
data/test/html/escape_test.rb
CHANGED
|
@@ -56,6 +56,18 @@ class HtmlEscapeTest < Minitest::Test
|
|
|
56
56
|
EscapeUtils.html_safe_string_class = klass_before
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
def test_returns_custom_string_class_when_string_requires_escaping
|
|
60
|
+
klass_before = EscapeUtils.html_safe_string_class
|
|
61
|
+
EscapeUtils.html_safe_string_class = MyCustomHtmlSafeString
|
|
62
|
+
|
|
63
|
+
str = EscapeUtils.escape_html_as_html_safe("<script>")
|
|
64
|
+
assert_equal "<script>", str
|
|
65
|
+
assert_equal MyCustomHtmlSafeString, str.class
|
|
66
|
+
assert_equal true, str.instance_variable_get(:@html_safe)
|
|
67
|
+
ensure
|
|
68
|
+
EscapeUtils.html_safe_string_class = klass_before
|
|
69
|
+
end
|
|
70
|
+
|
|
59
71
|
def test_html_safe_string_class_descends_string
|
|
60
72
|
assert_raises ArgumentError do
|
|
61
73
|
EscapeUtils.html_safe_string_class = Hash
|
data/test/uri/escape_test.rb
CHANGED
|
@@ -25,6 +25,14 @@ class UriEscapeTest < Minitest::Test
|
|
|
25
25
|
assert_equal '%E3%81%BE%E3%81%A4%20%E3%82%82%E3%81%A8', EscapeUtils.escape_uri(matz_name_sep)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
def test_uri_containing_pluses
|
|
29
|
+
assert_equal "a+plus", EscapeUtils.escape_uri("a+plus")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_uri_containing_slashes
|
|
33
|
+
assert_equal "a/slash", EscapeUtils.escape_uri("a/slash")
|
|
34
|
+
end
|
|
35
|
+
|
|
28
36
|
if RUBY_VERSION =~ /^1.9/
|
|
29
37
|
def test_input_must_be_utf8_or_ascii
|
|
30
38
|
str = "fo<o>bar"
|
data/test/uri/unescape_test.rb
CHANGED
|
@@ -30,18 +30,29 @@ class UriUnescapeTest < Minitest::Test
|
|
|
30
30
|
assert_equal matz_name_sep, EscapeUtils.unescape_uri('%E3%81%BE%E3%81%A4%20%E3%82%82%E3%81%A8')
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def test_uri_containing_pluses
|
|
34
|
+
assert_equal "a+plus", EscapeUtils.unescape_uri("a%2Bplus")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_escape_unescape_roundtrip
|
|
38
|
+
(0..127).each do |index|
|
|
39
|
+
char = index.chr
|
|
40
|
+
assert_equal char, EscapeUtils.unescape_uri(EscapeUtils.escape_uri(char))
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
33
44
|
if RUBY_VERSION =~ /^1.9/
|
|
34
45
|
def test_input_must_be_valid_utf8_or_ascii
|
|
35
46
|
escaped = EscapeUtils.escape_uri("fo<o>bar")
|
|
36
47
|
|
|
37
48
|
escaped.force_encoding 'ISO-8859-1'
|
|
38
49
|
assert_raises Encoding::CompatibilityError do
|
|
39
|
-
EscapeUtils.
|
|
50
|
+
EscapeUtils.unescape_uri(escaped)
|
|
40
51
|
end
|
|
41
52
|
|
|
42
53
|
escaped.force_encoding 'UTF-8'
|
|
43
54
|
begin
|
|
44
|
-
EscapeUtils.
|
|
55
|
+
EscapeUtils.unescape_uri(escaped)
|
|
45
56
|
rescue Encoding::CompatibilityError => e
|
|
46
57
|
assert_nil e, "#{e.class.name} raised, expected not to"
|
|
47
58
|
end
|
|
@@ -49,7 +60,7 @@ class UriUnescapeTest < Minitest::Test
|
|
|
49
60
|
|
|
50
61
|
def test_return_value_is_tagged_as_utf8
|
|
51
62
|
escaped = EscapeUtils.escape_uri("a space")
|
|
52
|
-
assert_equal Encoding.find('UTF-8'), EscapeUtils.
|
|
63
|
+
assert_equal Encoding.find('UTF-8'), EscapeUtils.unescape_uri(escaped).encoding
|
|
53
64
|
end
|
|
54
65
|
end
|
|
55
66
|
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require File.expand_path("../../helper", __FILE__)
|
|
2
|
+
require 'cgi'
|
|
3
|
+
|
|
4
|
+
class UriComponentEscapeTest < Minitest::Test
|
|
5
|
+
def test_basic_url
|
|
6
|
+
assert_equal "http%3A%2F%2Fwww.homerun.com%2F", EscapeUtils.escape_uri_component("http://www.homerun.com/")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_cgi_equivalence
|
|
10
|
+
(0..127).each do |i|
|
|
11
|
+
c = i.chr
|
|
12
|
+
# Escaping URI path components should match CGI parameter escaping, except
|
|
13
|
+
# spaces should be escaped as "%20" instead of "+"
|
|
14
|
+
assert_equal CGI.escape(c).sub("+", "%20"), EscapeUtils.escape_uri_component(c)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_uri_component_containing_tags
|
|
19
|
+
assert_equal "fo%3Co%3Ebar", EscapeUtils.escape_uri_component("fo<o>bar")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_uri_component_containing_tags_containing_spaces
|
|
23
|
+
assert_equal "a%20space", EscapeUtils.escape_uri_component("a space")
|
|
24
|
+
assert_equal "a%20%20%20sp%20ace%20", EscapeUtils.escape_uri_component("a sp ace ")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_uri_component_containing_mixed_characters
|
|
28
|
+
assert_equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C", EscapeUtils.escape_uri_component("q1!2\"'w$5&7/z8)?\\")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_multibyte_characters
|
|
32
|
+
matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8" # Matsumoto
|
|
33
|
+
assert_equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8', EscapeUtils.escape_uri_component(matz_name)
|
|
34
|
+
matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8" # Matsu moto
|
|
35
|
+
assert_equal '%E3%81%BE%E3%81%A4%20%E3%82%82%E3%81%A8', EscapeUtils.escape_uri_component(matz_name_sep)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_uri_component_containing_pluses
|
|
39
|
+
assert_equal "a%2Bplus", EscapeUtils.escape_uri_component("a+plus")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_uri_component_containing_slashes
|
|
43
|
+
assert_equal "a%2Fslash", EscapeUtils.escape_uri_component("a/slash")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
if RUBY_VERSION =~ /^1.9/
|
|
47
|
+
def test_input_must_be_utf8_or_ascii
|
|
48
|
+
str = "fo<o>bar"
|
|
49
|
+
|
|
50
|
+
str.force_encoding 'ISO-8859-1'
|
|
51
|
+
assert_raises Encoding::CompatibilityError do
|
|
52
|
+
EscapeUtils.escape_uri_component(str)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
str.force_encoding 'UTF-8'
|
|
56
|
+
begin
|
|
57
|
+
EscapeUtils.escape_uri_component(str)
|
|
58
|
+
rescue Encoding::CompatibilityError => e
|
|
59
|
+
assert_nil e, "#{e.class.name} raised, expected not to"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_return_value_is_tagged_as_utf8
|
|
64
|
+
str = "fo<o>bar"
|
|
65
|
+
assert_equal Encoding.find('UTF-8'), EscapeUtils.escape_uri_component(str).encoding
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require File.expand_path("../../helper", __FILE__)
|
|
2
|
+
|
|
3
|
+
class UriComponentUnescapeTest < Minitest::Test
|
|
4
|
+
def test_basic_url
|
|
5
|
+
assert_equal "http://www.homerun.com/", EscapeUtils.unescape_uri_component("http%3A%2F%2Fwww.homerun.com%2F")
|
|
6
|
+
assert_equal "http://www.homerun.com/", EscapeUtils.unescape_uri_component("http://www.homerun.com/")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def test_doesnt_unescape_an_incomplete_escape
|
|
10
|
+
assert_equal "%", EscapeUtils.unescape_uri_component("%")
|
|
11
|
+
assert_equal "http%", EscapeUtils.unescape_uri_component("http%")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_uri_component_containing_tags
|
|
15
|
+
assert_equal "fo<o>bar", EscapeUtils.unescape_uri_component("fo%3Co%3Ebar")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_uri_component_containing_spaces
|
|
19
|
+
assert_equal "a space", EscapeUtils.unescape_uri_component("a%20space")
|
|
20
|
+
assert_equal "a sp ace ", EscapeUtils.unescape_uri_component("a%20%20%20sp%20ace%20")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_uri_component_containing_pluses
|
|
24
|
+
assert_equal "a+plus", EscapeUtils.unescape_uri_component("a%2Bplus")
|
|
25
|
+
assert_equal "a+plus", EscapeUtils.unescape_uri_component("a+plus")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_escape_unescape_roundtrip
|
|
29
|
+
(0..127).each do |index|
|
|
30
|
+
char = index.chr
|
|
31
|
+
assert_equal char, EscapeUtils.unescape_uri_component(EscapeUtils.escape_uri_component(char))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_uri_component_containing_mixed_characters
|
|
36
|
+
assert_equal "q1!2\"'w$5&7/z8)?\\", EscapeUtils.unescape_uri_component("q1%212%22%27w%245%267%2Fz8%29%3F%5C")
|
|
37
|
+
assert_equal "q1!2\"'w$5&7/z8)?\\", EscapeUtils.unescape_uri_component("q1!2%22'w$5&7/z8)?%5C")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_multibyte_characters
|
|
41
|
+
matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8" # Matsumoto
|
|
42
|
+
matz_name.force_encoding('UTF-8') if matz_name.respond_to?(:force_encoding)
|
|
43
|
+
assert_equal matz_name, EscapeUtils.unescape_uri_component('%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8')
|
|
44
|
+
matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8" # Matsu moto
|
|
45
|
+
matz_name_sep.force_encoding('UTF-8') if matz_name_sep.respond_to?(:force_encoding)
|
|
46
|
+
assert_equal matz_name_sep, EscapeUtils.unescape_uri_component('%E3%81%BE%E3%81%A4%20%E3%82%82%E3%81%A8')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if RUBY_VERSION =~ /^1.9/
|
|
50
|
+
def test_input_must_be_valid_utf8_or_ascii
|
|
51
|
+
escaped = EscapeUtils.escape_uri_component("fo<o>bar")
|
|
52
|
+
|
|
53
|
+
escaped.force_encoding 'ISO-8859-1'
|
|
54
|
+
assert_raises Encoding::CompatibilityError do
|
|
55
|
+
EscapeUtils.unescape_uri_component(escaped)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
escaped.force_encoding 'UTF-8'
|
|
59
|
+
begin
|
|
60
|
+
EscapeUtils.unescape_uri_component(escaped)
|
|
61
|
+
rescue Encoding::CompatibilityError => e
|
|
62
|
+
assert_nil e, "#{e.class.name} raised, expected not to"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_return_value_is_tagged_as_utf8
|
|
67
|
+
escaped = EscapeUtils.escape_uri_component("fo<o>bar")
|
|
68
|
+
assert_equal Encoding.find('UTF-8'), EscapeUtils.unescape_uri_component(escaped).encoding
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
data/test/url/escape_test.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require File.expand_path("../../helper", __FILE__)
|
|
2
2
|
require 'cgi'
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class UrlEscapeTest < Minitest::Test
|
|
5
5
|
def test_basic_url
|
|
6
6
|
assert_equal "http%3A%2F%2Fwww.homerun.com%2F", EscapeUtils.escape_url("http://www.homerun.com/")
|
|
7
7
|
end
|
|
@@ -33,6 +33,14 @@ class UriEscapeTest < Minitest::Test
|
|
|
33
33
|
assert_equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8', EscapeUtils.escape_url(matz_name_sep)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def test_url_containing_pluses
|
|
37
|
+
assert_equal "a%2Bplus", EscapeUtils.escape_url("a+plus")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_url_containing_slashes
|
|
41
|
+
assert_equal "a%2Fslash", EscapeUtils.escape_url("a/slash")
|
|
42
|
+
end
|
|
43
|
+
|
|
36
44
|
if RUBY_VERSION =~ /^1.9/
|
|
37
45
|
def test_input_must_be_utf8_or_ascii
|
|
38
46
|
str = "fo<o>bar"
|
data/test/url/unescape_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require File.expand_path("../../helper", __FILE__)
|
|
2
2
|
|
|
3
|
-
class
|
|
3
|
+
class UrlUnescapeTest < Minitest::Test
|
|
4
4
|
def test_basic_url
|
|
5
5
|
assert_equal "http://www.homerun.com/", EscapeUtils.unescape_url("http%3A%2F%2Fwww.homerun.com%2F")
|
|
6
6
|
assert_equal "http://www.homerun.com/", EscapeUtils.unescape_url("http://www.homerun.com/")
|
|
@@ -35,9 +35,20 @@ class UriUnescapeTest < Minitest::Test
|
|
|
35
35
|
assert_equal matz_name_sep, EscapeUtils.unescape_url('%E3%81%BE%E3%81%A4%20%E3%82%82%E3%81%A8')
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
+
def test_url_containing_pluses
|
|
39
|
+
assert_equal "a+plus", EscapeUtils.unescape_url("a%2Bplus")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_escape_unescape_roundtrip
|
|
43
|
+
(0..127).each do |index|
|
|
44
|
+
char = index.chr
|
|
45
|
+
assert_equal char, EscapeUtils.unescape_url(EscapeUtils.escape_url(char))
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
38
49
|
if RUBY_VERSION =~ /^1.9/
|
|
39
50
|
def test_input_must_be_valid_utf8_or_ascii
|
|
40
|
-
escaped = EscapeUtils.
|
|
51
|
+
escaped = EscapeUtils.escape_url("fo<o>bar")
|
|
41
52
|
|
|
42
53
|
escaped.force_encoding 'ISO-8859-1'
|
|
43
54
|
assert_raises Encoding::CompatibilityError do
|
|
@@ -53,7 +64,7 @@ class UriUnescapeTest < Minitest::Test
|
|
|
53
64
|
end
|
|
54
65
|
|
|
55
66
|
def test_return_value_is_tagged_as_utf8
|
|
56
|
-
escaped = EscapeUtils.
|
|
67
|
+
escaped = EscapeUtils.escape_url("fo<o>bar")
|
|
57
68
|
assert_equal Encoding.find('UTF-8'), EscapeUtils.unescape_url(escaped).encoding
|
|
58
69
|
end
|
|
59
70
|
end
|
metadata
CHANGED
|
@@ -1,125 +1,138 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: escape_utils
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Lopez
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2015-03-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake-compiler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- -
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: 0.7.5
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- -
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: 0.7.5
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: minitest
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- -
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
33
|
version: 5.0.0
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- -
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 5.0.0
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: benchmark-ips
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: rack
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
44
58
|
requirements:
|
|
45
|
-
- -
|
|
59
|
+
- - ">="
|
|
46
60
|
- !ruby/object:Gem::Version
|
|
47
61
|
version: '0'
|
|
48
62
|
type: :development
|
|
49
63
|
prerelease: false
|
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
65
|
requirements:
|
|
52
|
-
- -
|
|
66
|
+
- - ">="
|
|
53
67
|
- !ruby/object:Gem::Version
|
|
54
68
|
version: '0'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: haml
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
58
72
|
requirements:
|
|
59
|
-
- -
|
|
73
|
+
- - ">="
|
|
60
74
|
- !ruby/object:Gem::Version
|
|
61
75
|
version: '0'
|
|
62
76
|
type: :development
|
|
63
77
|
prerelease: false
|
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
79
|
requirements:
|
|
66
|
-
- -
|
|
80
|
+
- - ">="
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
82
|
version: '0'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
84
|
name: fast_xs
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
|
72
86
|
requirements:
|
|
73
|
-
- -
|
|
87
|
+
- - ">="
|
|
74
88
|
- !ruby/object:Gem::Version
|
|
75
89
|
version: '0'
|
|
76
90
|
type: :development
|
|
77
91
|
prerelease: false
|
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
93
|
requirements:
|
|
80
|
-
- -
|
|
94
|
+
- - ">="
|
|
81
95
|
- !ruby/object:Gem::Version
|
|
82
96
|
version: '0'
|
|
83
97
|
- !ruby/object:Gem::Dependency
|
|
84
98
|
name: actionpack
|
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
|
86
100
|
requirements:
|
|
87
|
-
- -
|
|
101
|
+
- - ">="
|
|
88
102
|
- !ruby/object:Gem::Version
|
|
89
103
|
version: '0'
|
|
90
104
|
type: :development
|
|
91
105
|
prerelease: false
|
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
107
|
requirements:
|
|
94
|
-
- -
|
|
108
|
+
- - ">="
|
|
95
109
|
- !ruby/object:Gem::Version
|
|
96
110
|
version: '0'
|
|
97
111
|
- !ruby/object:Gem::Dependency
|
|
98
112
|
name: url_escape
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
100
114
|
requirements:
|
|
101
|
-
- -
|
|
115
|
+
- - ">="
|
|
102
116
|
- !ruby/object:Gem::Version
|
|
103
117
|
version: '0'
|
|
104
118
|
type: :development
|
|
105
119
|
prerelease: false
|
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
121
|
requirements:
|
|
108
|
-
- -
|
|
122
|
+
- - ">="
|
|
109
123
|
- !ruby/object:Gem::Version
|
|
110
124
|
version: '0'
|
|
111
|
-
description:
|
|
125
|
+
description: Quickly perform HTML, URL, URI and Javascript escaping/unescaping
|
|
112
126
|
email: seniorlopez@gmail.com
|
|
113
127
|
executables: []
|
|
114
128
|
extensions:
|
|
115
129
|
- ext/escape_utils/extconf.rb
|
|
116
130
|
extra_rdoc_files: []
|
|
117
131
|
files:
|
|
118
|
-
- .gitignore
|
|
119
|
-
- .travis.yml
|
|
120
|
-
- CHANGELOG.md
|
|
132
|
+
- ".gitignore"
|
|
133
|
+
- ".travis.yml"
|
|
121
134
|
- Gemfile
|
|
122
|
-
-
|
|
135
|
+
- LICENSE
|
|
123
136
|
- README.md
|
|
124
137
|
- Rakefile
|
|
125
138
|
- benchmark/html_escape.rb
|
|
@@ -168,30 +181,33 @@ files:
|
|
|
168
181
|
- test/query/unescape_test.rb
|
|
169
182
|
- test/uri/escape_test.rb
|
|
170
183
|
- test/uri/unescape_test.rb
|
|
184
|
+
- test/uri_component/escape_test.rb
|
|
185
|
+
- test/uri_component/unescape_test.rb
|
|
171
186
|
- test/url/escape_test.rb
|
|
172
187
|
- test/url/unescape_test.rb
|
|
173
188
|
- test/xml/escape_test.rb
|
|
174
|
-
homepage:
|
|
175
|
-
licenses:
|
|
189
|
+
homepage: https://github.com/brianmario/escape_utils
|
|
190
|
+
licenses:
|
|
191
|
+
- MIT
|
|
176
192
|
metadata: {}
|
|
177
193
|
post_install_message:
|
|
178
194
|
rdoc_options:
|
|
179
|
-
- --charset=UTF-8
|
|
195
|
+
- "--charset=UTF-8"
|
|
180
196
|
require_paths:
|
|
181
197
|
- lib
|
|
182
198
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
199
|
requirements:
|
|
184
|
-
- -
|
|
200
|
+
- - ">="
|
|
185
201
|
- !ruby/object:Gem::Version
|
|
186
202
|
version: 1.9.3
|
|
187
203
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
204
|
requirements:
|
|
189
|
-
- -
|
|
205
|
+
- - ">="
|
|
190
206
|
- !ruby/object:Gem::Version
|
|
191
207
|
version: '0'
|
|
192
208
|
requirements: []
|
|
193
209
|
rubyforge_project:
|
|
194
|
-
rubygems_version: 2.
|
|
210
|
+
rubygems_version: 2.2.2
|
|
195
211
|
signing_key:
|
|
196
212
|
specification_version: 4
|
|
197
213
|
summary: Faster string escaping routines for your web apps
|
|
@@ -206,6 +222,8 @@ test_files:
|
|
|
206
222
|
- test/query/unescape_test.rb
|
|
207
223
|
- test/uri/escape_test.rb
|
|
208
224
|
- test/uri/unescape_test.rb
|
|
225
|
+
- test/uri_component/escape_test.rb
|
|
226
|
+
- test/uri_component/unescape_test.rb
|
|
209
227
|
- test/url/escape_test.rb
|
|
210
228
|
- test/url/unescape_test.rb
|
|
211
229
|
- test/xml/escape_test.rb
|
data/CHANGELOG.md
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 0.3.2 (February 28th, 2013)
|
|
4
|
-
* fix rbx compatibility
|
|
5
|
-
* add EscapeUtils.html_safe_string_class
|
|
6
|
-
* add EscapeUtils.escape_html_as_html_safe
|
|
7
|
-
|
|
8
|
-
## 0.3.1 (February 26th, 2013)
|
|
9
|
-
* fixed compilation on Windows
|
|
10
|
-
|
|
11
|
-
## 0.3.0 (February 26th, 2013)
|
|
12
|
-
* add xml escaping support
|
|
13
|
-
* in Ruby 1.9 - escape_utils now requires the input string be UTF-8
|
|
14
|
-
* update upstream houdini to pull in some speed optimizations
|
|
15
|
-
* a couple of other perf tweaks
|
|
16
|
-
* switched to minitest
|
|
17
|
-
|
|
18
|
-
## 0.2.4 (September 7th, 2011)
|
|
19
|
-
* swap out custom escaping routines for houdini - https://github.com/tanoku/houdini
|
|
20
|
-
* add RSTRING_NOT_MODIFIED define for a Rubinius speedup
|
|
21
|
-
|
|
22
|
-
## 0.2.3 (March 9th, 2011)
|
|
23
|
-
* change encoding strategy to simply return strings in the encoding the input string was in, not taking into account Encoding.default_internal
|
|
24
|
-
|
|
25
|
-
## 0.2.2 (February 25th, 2011)
|
|
26
|
-
* minor fix for Rubinius compatibility
|
|
27
|
-
|
|
28
|
-
## 0.2.1 (February 21st, 2011)
|
|
29
|
-
* fix buffer over read in unescape_url and unescape_uri
|
|
30
|
-
|
|
31
|
-
## 0.2.0 (February 8th, 2011)
|
|
32
|
-
* fixed a couple of compilation warnings on 1.9.3
|
|
33
|
-
* moved to rspec2
|
|
34
|
-
* remove hard-conversion to utf-8 to preserve the string's original encoding
|
|
35
|
-
* moved to rake-compiler, Bundler
|
|
36
|
-
* pass through incompletely escaped data on unescaping
|
|
37
|
-
* added tilde to escape_{uri,url}specs (It's a difference between CGI.escape and URI.escape)
|
|
38
|
-
* escape_uri and escape_url now match their Ruby counterparts
|
|
39
|
-
** escape_uri is used where URI.escape is, and escape_url is used where CGI.escape is used.
|
|
40
|
-
* performance and memory usage optimizations
|
|
41
|
-
|
|
42
|
-
## 0.1.9 (October 15th, 2010)
|
|
43
|
-
* add a flag as an optional 2nd parameter to EscapeUtils.escape_html to disable/enable the escaping of the '/' character. Defaults to the new flag EscapeUtils.html_secure
|
|
44
|
-
|
|
45
|
-
## 0.1.8 (September 29th, 2010)
|
|
46
|
-
* fix URI escaping one last time ;)
|
|
47
|
-
|
|
48
|
-
## 0.1.7 (September 29th, 2010)
|
|
49
|
-
* fix URI escaping to act according to the RFC
|
|
50
|
-
* add specs for URL escaping
|
|
51
|
-
|
|
52
|
-
## 0.1.6 (September 6th, 2010)
|
|
53
|
-
* support for URI escaping added (thanks to @joshbuddy)
|
|
54
|
-
* bugfix to ensure we don't drop opening tags during escape_javascript (thanks to @nagybence)
|
|
55
|
-
|
|
56
|
-
## 0.1.5 (July 13th, 2010)
|
|
57
|
-
* add URL escaping and unescaping
|
|
58
|
-
* major refactor of HTML and Javascript escaping and unescaping logic for a decent speed up
|
|
59
|
-
* HTML escaping now takes html_safe? into account (for Rails/ActiveSupport users) - thanks yury!
|
|
60
|
-
|
|
61
|
-
## 0.1.4 (June 9th, 2010)
|
|
62
|
-
* ensure strings are passed in from monkey-patches
|
|
63
|
-
|
|
64
|
-
## 0.1.3 (June 9th, 2010)
|
|
65
|
-
* cleaned some code up, removing duplication
|
|
66
|
-
* moved to a more flexible character encoding scheme using Encoding.defaut_internal for 1.9 users
|
|
67
|
-
|
|
68
|
-
## 0.1.2 (June 8th, 2010)
|
|
69
|
-
* forgot to add the ActionView monkey patch for JS escaping ;)
|
|
70
|
-
|
|
71
|
-
## 0.1.1 (June 8th, 2010)
|
|
72
|
-
* added javascript escaping
|
|
73
|
-
|
|
74
|
-
## 0.1.0 (June 8th, 2010)
|
|
75
|
-
* initial release
|
data/MIT-LICENSE
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2010-2013 Brian Lopez - http://github.com/brianmario
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
-
a copy of this software and associated documentation files (the
|
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
-
the following conditions:
|
|
10
|
-
|
|
11
|
-
The above copyright notice and this permission notice shall be
|
|
12
|
-
included in all copies or substantial portions of the Software.
|
|
13
|
-
|
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|