Skip to content

Instantly share code, notes, and snippets.

@seanwalbran
Created July 19, 2012 13:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seanwalbran/50ec9ab8ae1e223f3b75 to your computer and use it in GitHub Desktop.
Save seanwalbran/50ec9ab8ae1e223f3b75 to your computer and use it in GitHub Desktop.
native vs regex html_escape

Checking this: https://github.com/rails/rails/commit/63cd9432265a32d222353b535d60333c2a6a5125

test.rb:

def h_via_encode(s)
  s = s.to_s
  if s.html_safe?
    s
  else
    s.encode(s.encoding, :xml => :attr)[1...-1].html_safe
  end  
end

HTML_ESCAPE = { '&' => '&amp;',  '>' => '&gt;',   '<' => '&lt;', '"' => '&quot;' }

def h_via_gsub(s)
  s = s.to_s
  if s.html_safe?
    s
  else
    silence_warnings { s.gsub(/[&"><]/n) { |special| HTML_ESCAPE[special] }.html_safe }
  end  
end

def time_and_space(iter = 10000, &block)
  ObjectSpace.garbage_collect
  s=GC.malloc_allocated_size if GC.respond_to?(:malloc_allocated_size)
  c=GC.count 
  t = Benchmark.realtime do
    iter.to_i.times do
      yield
    end
  end  
  m = (GC.malloc_allocated_size - s).to_f/(1024.0*1024.0) if GC.respond_to?(:malloc_allocated_size)
  m ||= -1.0
  g = GC.count - c
  "#{ '%.3f' % t} sec  #{'%.3f' % m} MB  #{g} collections  #{iter} iterations" 
end 

base_with_specials    = '<script>alert("foo & bar & baz");</script>'
base_without_specials = 'Laborum next level organic nihil cardigan.'  
test_strings = { 
  'with_special_1' => base_with_specials,
  'no_special_1' => base_without_specials,
  'with_special_10' => base_with_specials * 10,
  'no_special_10' => base_without_specials * 10,
  'with_special_100' => base_with_specials * 100,
  'no_special_100' => base_without_specials * 100
} ; nil
test_strings.each_pair do |name, string|
  puts "\n#{name} length: #{string.length}"
  [100, 1000, 10000].each do |iter|
    puts "via_encode: " << time_and_space(iter) { h_via_encode(string) }
    puts "via_gsub:   " << time_and_space(iter) { h_via_gsub(string) }
  end
end ; nil

Context: osx lion, MBP:

$ rvm install ruby-1.9.3-p125 -n basic
$ rvm install ruby-1.9.3-p125 -n gcdata --patch gcdata

~/projects/rails $ git checkout 3-1-stable

$ rvm use ruby-1.9.3-p125-basic@rails --create
$ bundle install

$ echo "load '../test.rb'" | tools/console 
Switch to inspect mode.
load '../test.rb'

with_special_1 length: 42
via_encode: 0.001 sec  -1.000 MB  0 collections  100 iterations
via_gsub:   0.001 sec  -1.000 MB  0 collections  100 iterations
via_encode: 0.021 sec  -1.000 MB  1 collections  1000 iterations
via_gsub:   0.010 sec  -1.000 MB  0 collections  1000 iterations
via_encode: 0.211 sec  -1.000 MB  11 collections  10000 iterations
via_gsub:   0.106 sec  -1.000 MB  0 collections  10000 iterations

no_special_1 length: 42
via_encode: 0.001 sec  -1.000 MB  0 collections  100 iterations
via_gsub:   0.000 sec  -1.000 MB  0 collections  100 iterations
via_encode: 0.019 sec  -1.000 MB  1 collections  1000 iterations
via_gsub:   0.003 sec  -1.000 MB  0 collections  1000 iterations
via_encode: 0.195 sec  -1.000 MB  11 collections  10000 iterations
via_gsub:   0.029 sec  -1.000 MB  0 collections  10000 iterations

with_special_10 length: 420
via_encode: 0.007 sec  -1.000 MB  0 collections  100 iterations
via_gsub:   0.005 sec  -1.000 MB  0 collections  100 iterations
via_encode: 0.074 sec  -1.000 MB  1 collections  1000 iterations
via_gsub:   0.054 sec  -1.000 MB  0 collections  1000 iterations
via_encode: 0.756 sec  -1.000 MB  13 collections  10000 iterations
via_gsub:   0.583 sec  -1.000 MB  6 collections  10000 iterations

no_special_10 length: 420
via_encode: 0.006 sec  -1.000 MB  0 collections  100 iterations
via_gsub:   0.000 sec  -1.000 MB  0 collections  100 iterations
via_encode: 0.057 sec  -1.000 MB  0 collections  1000 iterations
via_gsub:   0.003 sec  -1.000 MB  0 collections  1000 iterations
via_encode: 0.576 sec  -1.000 MB  1 collections  10000 iterations
via_gsub:   0.034 sec  -1.000 MB  0 collections  10000 iterations

with_special_100 length: 4200
via_encode: 0.061 sec  -1.000 MB  0 collections  100 iterations
via_gsub:   0.049 sec  -1.000 MB  0 collections  100 iterations
via_encode: 0.597 sec  -1.000 MB  0 collections  1000 iterations
via_gsub:   0.495 sec  -1.000 MB  4 collections  1000 iterations
via_encode: 5.980 sec  -1.000 MB  4 collections  10000 iterations
via_gsub:   5.021 sec  -1.000 MB  41 collections  10000 iterations

no_special_100 length: 4200
via_encode: 0.053 sec  -1.000 MB  0 collections  100 iterations
via_gsub:   0.001 sec  -1.000 MB  0 collections  100 iterations
via_encode: 0.517 sec  -1.000 MB  0 collections  1000 iterations
via_gsub:   0.008 sec  -1.000 MB  0 collections  1000 iterations
via_encode: 5.039 sec  -1.000 MB  2 collections  10000 iterations
via_gsub:   0.081 sec  -1.000 MB  0 collections  10000 iterations
true

With gcdata:

~/projects/rails $ rvm use ruby-1.9.3-p125-gcdata@rails --create; bundle install; echo "load '../test.rb'" | tools/console
...
Seans-MacBook-Pro:~/projects/rails $ echo "load '../test.rb'" | tools/console
Switch to inspect mode.
load '../test.rb'

with_special_1 length: 42
via_encode: 0.001 sec  0.872 MB  0 collections  100 iterations
via_gsub:   0.001 sec  0.039 MB  0 collections  100 iterations
via_encode: 0.014 sec  8.722 MB  0 collections  1000 iterations
via_gsub:   0.011 sec  0.390 MB  0 collections  1000 iterations
via_encode: 0.151 sec  87.223 MB  1 collections  10000 iterations
via_gsub:   0.102 sec  3.901 MB  0 collections  10000 iterations

no_special_1 length: 42
via_encode: 0.001 sec  0.870 MB  0 collections  100 iterations
via_gsub:   0.000 sec  0.018 MB  0 collections  100 iterations
via_encode: 0.012 sec  8.694 MB  0 collections  1000 iterations
via_gsub:   0.003 sec  0.176 MB  0 collections  1000 iterations
via_encode: 0.133 sec  86.937 MB  1 collections  10000 iterations
via_gsub:   0.029 sec  1.755 MB  0 collections  10000 iterations

with_special_10 length: 420
via_encode: 0.007 sec  0.970 MB  0 collections  100 iterations
via_gsub:   0.006 sec  0.070 MB  0 collections  100 iterations
via_encode: 0.065 sec  9.701 MB  0 collections  1000 iterations
via_gsub:   0.055 sec  0.697 MB  0 collections  1000 iterations
via_encode: 0.659 sec  97.008 MB  1 collections  10000 iterations
via_gsub:   0.587 sec  6.972 MB  4 collections  10000 iterations

no_special_10 length: 420
via_encode: 0.006 sec  0.942 MB  0 collections  100 iterations
via_gsub:   0.000 sec  0.018 MB  0 collections  100 iterations
via_encode: 0.057 sec  9.415 MB  0 collections  1000 iterations
via_gsub:   0.003 sec  0.176 MB  0 collections  1000 iterations
via_encode: 0.571 sec  94.147 MB  1 collections  10000 iterations
via_gsub:   0.035 sec  1.755 MB  0 collections  10000 iterations

with_special_100 length: 4200
via_encode: 0.060 sec  1.949 MB  0 collections  100 iterations
via_gsub:   0.050 sec  0.430 MB  0 collections  100 iterations
via_encode: 0.587 sec  19.486 MB  0 collections  1000 iterations
via_gsub:   0.520 sec  4.302 MB  4 collections  1000 iterations
via_encode: 5.874 sec  194.855 MB  4 collections  10000 iterations
via_gsub:   5.172 sec  43.020 MB  41 collections  10000 iterations

no_special_100 length: 4200
via_encode: 0.050 sec  1.663 MB  0 collections  100 iterations
via_gsub:   0.001 sec  0.018 MB  0 collections  100 iterations
via_encode: 0.490 sec  16.625 MB  0 collections  1000 iterations
via_gsub:   0.008 sec  0.176 MB  0 collections  1000 iterations
via_encode: 4.982 sec  166.245 MB  2 collections  10000 iterations
via_gsub:   0.084 sec  1.755 MB  0 collections  10000 iterations
true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment