Hi all,
I would like to describe my concerns on current exception handling below.
How it is handled currently:
def a
some_method_that_doesnt_exist
end
begin
cxt['a'] = method :a
cxt.eval('a')
rescue V8::JSError => e
if e.in_ruby?
puts "some ruby error'
else
puts "some JS error'
end
end
Doesn't look so good, right?
First proposal is to split V8::JSError into V8::JSError::Ruby and
V8::JSError:JS, thus we can rescue them individually or together, using
their common ancestor. (described in
https://github.com/cowboyd/therubyracer/issues/200)
My second concern is that there's no sane way to understand what kind of
exception we got from ruby:
require 'v8'
class Ex < StandardError
end
class A
def c
puts "raising"
raise Ex.new "i'm a specific ruby exception"
end
end
c = V8::Context.new
c['a'] = A.new
begin
c.eval('a.c')
rescue Ex => e
puts "rescued ex: #{e}"
rescue V8::JSError => e2
puts "rescued js: #{e2.inspect}"
puts e2.in_ruby?
rescue StandardError => e3
puts "rescued se: #{e3}"
end
Guess, which one is rescued?
V8::JSError, and `in_ruby?` is returning true.
If we are passing a wrapper for Net::HTTP to JS code, how do we distinguish
between Net::HTTPBadResponse and NoMethodError?
In first case there's an error with networking, and it is recoverable in JS
code (try another host, report, log et c.).
The second case is quite different and means there's an error in evaluated
JS.
How do we distinguish these two?
Let's move to my third concern.
JS is known to be a safe sandbox. If JS is trying to do something
malicious, we should be notified.
require 'v8'
class MaliciousScript < Exception
end
class A
def a path
raise MaliciousScript.new "hey, the script is trying to `rm -rf /`!" if path =~ /\//
end
end
c = V8::Context.new
c['a'] = A.new
begin
c.eval 'a.a("my")'
puts "ok"
c.eval <<-EOF
try {
a.a("/")
} catch(e){
// Hey let's hack those bastards!
}
EOF
puts "No exception!"
rescue MaliciousScript => e
puts "rescued maliciuos script: #{e}"
rescue V8::JSError => e2
puts "rescued js: #{e2.inspect}"
puts e2.in_ruby?
rescue Exception => e3
puts "rescued se: #{e3}"
end
Guess what?
ok
No exception!
My proposals here abridged:
1. Split V8::JSError into two, JS specific and Ruby specific
2. Let Ruby catch ruby specific exceptions in a straightforward way
3. Restrict JS from catching exceptions it's not intended to catch
Please let me know what you think.
PS Just for the case you may have questions regarding what i'm doing. I'm
working on a platform which allows users to host and execute JS, and it's
Ruby controlled/based. I provide an API to JS, and would like to do so in a
controlled way.
PPS Should I crosspost/move this to javascript-and-friends? Not sure if
it's common to therubyrhino or execjs.
BR, Phil