therubyracer 0.12.0 → 0.12.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of therubyracer might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +6 -3
- data/Changelog.md +11 -0
- data/Gemfile +3 -1
- data/README.md +52 -6
- data/ext/v8/rr.h +1 -0
- data/ext/v8/script.cc +36 -1
- data/lib/therubyracer.rb +1 -0
- data/lib/v8/context.rb +15 -2
- data/lib/v8/error.rb +6 -3
- data/lib/v8/version.rb +1 -1
- data/spec/threading_spec.rb +13 -1
- data/spec/v8/error_spec.rb +9 -7
- data/therubyracer.gemspec +1 -0
- metadata +7 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9cfa70f9de350c1e76e6794ae66d1f7dd2026462
|
4
|
+
data.tar.gz: 21a5105a79939e804bfdf22d8a0e4108d614841c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cef15fc729596d2d9d0af7e5c5e467ff68e9db40faf66e200af4a7c555494d265a5415119243e440c955738b9bd22e50558fbf4eb69ea1df46ff1a597df267c3
|
7
|
+
data.tar.gz: 2bf28f39134268f84dc4bf029d0a9ef060670342c1fd7699e97c21debd4317c2ca14271a99b179a23e506955f557f0568c45d2880a058f891afb39f862549ca0
|
data/.travis.yml
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
cache: bundler
|
1
2
|
rvm:
|
3
|
+
- 2.1.0
|
2
4
|
- 2.0.0
|
3
|
-
- 1.9.2
|
4
5
|
- 1.9.3
|
6
|
+
- 1.9.2
|
5
7
|
- 1.8.7
|
6
|
-
- rbx-
|
7
|
-
- rbx-19mode
|
8
|
+
- rbx-2.2.3
|
8
9
|
notifications:
|
9
10
|
recipients:
|
10
11
|
- cowboyd@thefrontside.net
|
12
|
+
before_install:
|
13
|
+
- gem update --system 2.1.11
|
11
14
|
script: bundle exec rake compile spec
|
data/Changelog.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.12.1 2014/02/03
|
4
|
+
|
5
|
+
* add `timeout` option to `V8::Context` to forcibly abort long running scripts (thanks to @SamSaffron)
|
6
|
+
* allow canonical require via `require "therubyracer"` instead of oddball `require "v8"`(thanks @gaffneyc)
|
7
|
+
|
8
|
+
## 0.12.0 2013/08/20
|
9
|
+
|
10
|
+
* upgrade v8 to 3.16.4 (thanks to @ignisf)
|
11
|
+
* enable native (and functional) weakref implementation for MRI > 2.0
|
12
|
+
* expose low level interface for `V8::C::HeapStatistics#total_physical_size`
|
13
|
+
|
3
14
|
## 0.11.1 2013/01/04
|
4
15
|
|
5
16
|
* reintroduce the dependency on libv8
|
data/Gemfile
CHANGED
@@ -2,8 +2,10 @@ source 'http://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
gem "rubysl", :platforms => :rbx
|
5
6
|
gem 'redjs', :git => 'https://github.com/cowboyd/redjs.git'
|
6
7
|
gem "rake"
|
7
8
|
gem "rspec", "~> 2.0"
|
8
9
|
gem "rake-compiler"
|
9
|
-
gem
|
10
|
+
gem "gem-compiler", :platforms => :mri
|
11
|
+
|
data/README.md
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
# therubyracer
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/therubyracer.png)](http://badge.fury.io/rb/therubyracer)
|
4
|
+
[![Build Status](https://travis-ci.org/cowboyd/therubyracer.png?branch=master)](https://travis-ci.org/cowboyd/therubyracer)
|
5
|
+
[![Dependency Status](https://gemnasium.com/cowboyd/therubyracer.png)](https://gemnasium.com/cowboyd/therubyracer)
|
6
|
+
|
7
|
+
|
8
|
+
* GitHub Project: [http://github.com/cowboyd/therubyracer](http://github.com/cowboyd/therubyracer)
|
9
|
+
* Mailing List: [http://groups.google.com/group/therubyracer](http://groups.google.com/group/therubyracer)
|
10
|
+
* IRC / Chat: [irc://irc.freenode.net/therubyracer](http://groups.google.com/group/therubyracer)
|
11
|
+
* Documentation: [GitHub Wiki](https://github.com/cowboyd/therubyracer/wiki) and [RubyDoc](http://rubydoc.info/gems/therubyracer)
|
7
12
|
|
8
13
|
### DESCRIPTION
|
9
14
|
|
@@ -24,13 +29,28 @@ then in your Ruby code
|
|
24
29
|
|
25
30
|
require 'v8'
|
26
31
|
# or if using bundler (as with Rails), add the following to your Gemfile
|
27
|
-
gem "therubyracer"
|
32
|
+
gem "therubyracer"
|
28
33
|
|
29
34
|
evaluate some simple JavaScript
|
30
35
|
|
31
36
|
cxt = V8::Context.new
|
32
37
|
cxt.eval('7 * 6') #=> 42
|
33
38
|
|
39
|
+
access values inside your JavaScript context from Ruby
|
40
|
+
|
41
|
+
cxt.eval 'var val = {num: 5, fun: function isTruthy(arg) { return !!arg }}'
|
42
|
+
val = cxt[:val] #=> V8::Object
|
43
|
+
cxt[:val] == cxt.scope.val #=> true
|
44
|
+
val.num #=> 5
|
45
|
+
val.isTruthy(1) #=> true
|
46
|
+
|
47
|
+
this includes references to JavaScript functions
|
48
|
+
|
49
|
+
truthy = val[:isTruthy] #=> V8::Function
|
50
|
+
truthy.call(' ') #=> true
|
51
|
+
truthy.call(0) #=> false
|
52
|
+
|
53
|
+
|
34
54
|
embed values into the scope of your context
|
35
55
|
|
36
56
|
cxt['foo'] = "bar"
|
@@ -125,6 +145,32 @@ behavior you'd like.
|
|
125
145
|
|
126
146
|
More documentation can be found on the [GitHub wiki](https://github.com/cowboyd/therubyracer/wiki)
|
127
147
|
|
148
|
+
### Protecting Your CPU cycles
|
149
|
+
|
150
|
+
When running untrusted JavaScript code, you not only have to protect
|
151
|
+
which functions it has access to, but also how much of your CPU it can
|
152
|
+
consume. Take this simple, yet thoroughly malicious script:
|
153
|
+
|
154
|
+
```javascript
|
155
|
+
while (true) {}
|
156
|
+
```
|
157
|
+
|
158
|
+
It will loop forever and never return control to the calling Ruby
|
159
|
+
thread. To protect against such JavaScript code that either
|
160
|
+
deliberately or accidentally runs longer that it should, you can
|
161
|
+
set an explicit timeout on your context. If the code runs longer that
|
162
|
+
the allowed timeout, then it will throw an exception. Note that this
|
163
|
+
exception could be raised at any point in the execution of the
|
164
|
+
JavaScript.
|
165
|
+
|
166
|
+
To specify the timeout (in milliseconds), pass in the `timeout` option
|
167
|
+
to the constructor.
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
cxt = V8::Context.new timeout: 700
|
171
|
+
cxt.eval "while (true);" #= exception after 700ms!
|
172
|
+
```
|
173
|
+
|
128
174
|
### PREREQUISITES
|
129
175
|
|
130
176
|
The Ruby Racer requires the V8 Javascript engine, but it offloads the
|
@@ -173,4 +219,4 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
173
219
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
174
220
|
|
175
221
|
[1]: https://github.com/cowboyd/libv8
|
176
|
-
[2]: http://code.google.com/p/v8/wiki/BuildingWithGYP
|
222
|
+
[2]: http://code.google.com/p/v8/wiki/BuildingWithGYP
|
data/ext/v8/rr.h
CHANGED
@@ -372,6 +372,7 @@ public:
|
|
372
372
|
static void Init();
|
373
373
|
static VALUE New(int argc, VALUE argv[], VALUE self);
|
374
374
|
static VALUE Run(VALUE self);
|
375
|
+
static VALUE RunWithTimeout(VALUE self, VALUE timeout);
|
375
376
|
|
376
377
|
inline Script(VALUE value) : Ref<v8::Script>(value) {}
|
377
378
|
inline Script(v8::Handle<v8::Script> script) : Ref<v8::Script>(script) {}
|
data/ext/v8/script.cc
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#include "rr.h"
|
2
|
+
#include "pthread.h"
|
3
|
+
#include "unistd.h"
|
2
4
|
|
3
5
|
namespace rr {
|
4
6
|
|
@@ -6,6 +8,7 @@ void Script::Init() {
|
|
6
8
|
ClassBuilder("Script").
|
7
9
|
defineSingletonMethod("New", &New).
|
8
10
|
defineMethod("Run", &Run).
|
11
|
+
defineMethod("RunWithTimeout", &RunWithTimeout).
|
9
12
|
store(&Class);
|
10
13
|
ClassBuilder("ScriptOrigin").
|
11
14
|
defineSingletonMethod("new", &ScriptOrigin::initialize).
|
@@ -69,6 +72,38 @@ VALUE Script::Run(VALUE self) {
|
|
69
72
|
return Value(Script(self)->Run());
|
70
73
|
}
|
71
74
|
|
75
|
+
typedef struct {
|
76
|
+
v8::Isolate *isolate;
|
77
|
+
long timeout;
|
78
|
+
} timeout_data;
|
79
|
+
|
80
|
+
void* breaker(void *d) {
|
81
|
+
timeout_data* data = (timeout_data*)d;
|
82
|
+
usleep(data->timeout*1000);
|
83
|
+
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
84
|
+
v8::V8::TerminateExecution(data->isolate);
|
85
|
+
return NULL;
|
86
|
+
}
|
87
|
+
|
88
|
+
VALUE Script::RunWithTimeout(VALUE self, VALUE timeout) {
|
89
|
+
pthread_t breaker_thread;
|
90
|
+
timeout_data data;
|
91
|
+
VALUE rval;
|
92
|
+
void *res;
|
93
|
+
|
94
|
+
data.isolate = v8::Isolate::GetCurrent();
|
95
|
+
data.timeout = NUM2LONG(timeout);
|
96
|
+
|
97
|
+
pthread_create(&breaker_thread, NULL, breaker, &data);
|
98
|
+
|
99
|
+
rval = Value(Script(self)->Run());
|
100
|
+
|
101
|
+
pthread_cancel(breaker_thread);
|
102
|
+
pthread_join(breaker_thread, &res);
|
103
|
+
|
104
|
+
return rval;
|
105
|
+
}
|
106
|
+
|
72
107
|
template <> void Pointer<v8::ScriptData>::unwrap(VALUE value) {
|
73
108
|
Data_Get_Struct(value, class v8::ScriptData, pointer);
|
74
109
|
}
|
@@ -77,4 +112,4 @@ template <> void Pointer<v8::ScriptOrigin>::unwrap(VALUE value) {
|
|
77
112
|
Data_Get_Struct(value, class v8::ScriptOrigin, pointer);
|
78
113
|
}
|
79
114
|
|
80
|
-
} //namespace rr
|
115
|
+
} //namespace rr
|
data/lib/therubyracer.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "v8"
|
data/lib/v8/context.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'stringio'
|
2
3
|
module V8
|
3
4
|
# All JavaScript must be executed in a context. This context consists of a global scope containing the
|
@@ -39,6 +40,10 @@ module V8
|
|
39
40
|
# @return [V8::C::Context] the underlying C++ object
|
40
41
|
attr_reader :native
|
41
42
|
|
43
|
+
# @!attribute [r] timeout
|
44
|
+
# @return [Number] maximum execution time in milliseconds for scripts executed in this context
|
45
|
+
attr_reader :timeout
|
46
|
+
|
42
47
|
# Creates a new context.
|
43
48
|
#
|
44
49
|
# If passed the `:with` option, that object will be used as
|
@@ -50,12 +55,16 @@ module V8
|
|
50
55
|
# cxt['hello'] #=> 'Hi'
|
51
56
|
# end
|
52
57
|
#
|
58
|
+
# If passed the `:timeout` option, every eval will timeout once
|
59
|
+
# N milliseconds elapse
|
60
|
+
#
|
53
61
|
# @param [Hash<Symbol, Object>] options initial context configuration
|
54
62
|
# * :with scope serves as the global scope of the new context
|
55
63
|
# @yield [V8::Context] the newly created context
|
56
64
|
def initialize(options = {})
|
57
65
|
@conversion = Conversion.new
|
58
66
|
@access = Access.new
|
67
|
+
@timeout = options[:timeout]
|
59
68
|
if global = options[:with]
|
60
69
|
Context.new.enter do
|
61
70
|
global_template = global.class.to_template.InstanceTemplate()
|
@@ -84,7 +93,11 @@ module V8
|
|
84
93
|
end
|
85
94
|
enter do
|
86
95
|
script = try { V8::C::Script::New(source.to_s, filename.to_s) }
|
87
|
-
|
96
|
+
if @timeout
|
97
|
+
to_ruby try {script.RunWithTimeout(@timeout)}
|
98
|
+
else
|
99
|
+
to_ruby try {script.Run()}
|
100
|
+
end
|
88
101
|
end
|
89
102
|
end
|
90
103
|
|
@@ -242,4 +255,4 @@ module V8
|
|
242
255
|
Context.current = current
|
243
256
|
end
|
244
257
|
end
|
245
|
-
end
|
258
|
+
end
|
data/lib/v8/error.rb
CHANGED
@@ -139,11 +139,14 @@ module V8
|
|
139
139
|
# @return [V8::Error] the error generated by this try/catch
|
140
140
|
def self.Error(trycatch)
|
141
141
|
exception = trycatch.Exception()
|
142
|
+
|
142
143
|
value = exception.to_ruby
|
143
144
|
cause = nil
|
144
|
-
|
145
|
+
message = trycatch.Message()
|
146
|
+
javascript_backtrace = V8::StackTrace.new(message.GetStackTrace()) if message
|
147
|
+
|
145
148
|
message = if !exception.kind_of?(V8::C::Value)
|
146
|
-
exception.to_s
|
149
|
+
exception.to_s==""?"Script Timed Out":exception.to_s
|
147
150
|
elsif exception.IsNativeError()
|
148
151
|
if cause = exception.GetHiddenValue("rr::Cause")
|
149
152
|
cause = cause.Value()
|
@@ -163,4 +166,4 @@ module V8
|
|
163
166
|
V8::Error.new(message, value, javascript_backtrace, cause)
|
164
167
|
end
|
165
168
|
const_set :JSError, Error
|
166
|
-
end
|
169
|
+
end
|
data/lib/v8/version.rb
CHANGED
data/spec/threading_spec.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
describe "Timeouts" do
|
4
|
+
it "allows for timeout on context" do
|
5
|
+
ctx = V8::Context.new(:timeout => 10)
|
6
|
+
lambda {ctx.eval("while(true){}")}.should(raise_error)
|
7
|
+
|
8
|
+
# context should not be bust after it exploded once
|
9
|
+
ctx["x"] = 1;
|
10
|
+
ctx.eval("x=2;")
|
11
|
+
ctx["x"].should == 2
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
3
15
|
describe "using v8 from multiple threads", :threads => true do
|
4
16
|
|
5
17
|
it "creates contexts from within threads" do
|
@@ -49,4 +61,4 @@ describe "using v8 from multiple threads", :threads => true do
|
|
49
61
|
V8::C::Locker::StopPreemption()
|
50
62
|
end
|
51
63
|
end
|
52
|
-
end
|
64
|
+
end
|
data/spec/v8/error_spec.rb
CHANGED
@@ -64,11 +64,12 @@ describe V8::Error do
|
|
64
64
|
describe "backtrace" do
|
65
65
|
it "is mixed with ruby and javascript" do
|
66
66
|
throw! do |e|
|
67
|
-
e.backtrace.
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
backtrace = e.backtrace.reject { |l| /kernel\// =~ l }
|
68
|
+
backtrace.first.should eql "at three.js:1:7"
|
69
|
+
backtrace[1].should match(/error_spec.rb/)
|
70
|
+
backtrace[2].should eql "at two.js:1:1"
|
71
|
+
backtrace[3].should match(/error_spec.rb/)
|
72
|
+
backtrace[4].should eql "at one.js:1:1"
|
72
73
|
end
|
73
74
|
end
|
74
75
|
|
@@ -114,8 +115,9 @@ INVALID
|
|
114
115
|
lambda {
|
115
116
|
@cxt.eval('boom()', "boom.js")
|
116
117
|
}.should(raise_error {|e|
|
117
|
-
e.backtrace.
|
118
|
-
|
118
|
+
backtrace = e.backtrace.reject { |l| /kernel\// =~ l }
|
119
|
+
backtrace.first.should =~ /error_spec\.rb/
|
120
|
+
backtrace[1].should =~ /boom.js/
|
119
121
|
})
|
120
122
|
end
|
121
123
|
end
|
data/therubyracer.gemspec
CHANGED
metadata
CHANGED
@@ -1,35 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: therubyracer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Lowell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
-
|
12
|
-
-----BEGIN CERTIFICATE-----
|
13
|
-
MIIDPjCCAiagAwIBAgIBADANBgkqhkiG9w0BAQUFADBFMRAwDgYDVQQDDAdjb3di
|
14
|
-
b3lkMRwwGgYKCZImiZPyLGQBGRYMdGhlZnJvbnRzaWRlMRMwEQYKCZImiZPyLGQB
|
15
|
-
GRYDbmV0MB4XDTEzMDEzMDIxMDYwNFoXDTE0MDEzMDIxMDYwNFowRTEQMA4GA1UE
|
16
|
-
AwwHY293Ym95ZDEcMBoGCgmSJomT8ixkARkWDHRoZWZyb250c2lkZTETMBEGCgmS
|
17
|
-
JomT8ixkARkWA25ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO45
|
18
|
-
CUxpETDGYXjCCy2dMg/aIrdrTqBqQW5ZrzhHxF9EkcdmWFr0z/qMz0JSpZ3pF11Z
|
19
|
-
KYaj5PaQQpjZfLPwbuiGGkuSWi+UAac//V18xo6S4lzRBjO+gpzG9f2AOzt9b+SR
|
20
|
-
Uc8UhO7QBZ5edUDxMxw9QstD+U0YBAlzsPJbHuUOqdtxXmNQCds3ZnqTgZaIpdUy
|
21
|
-
CSejtrukSmlthxFzwgMezYQhcYxmkl+Q475JUodnI6Pjc6nja/Or8Y6cEWiLgeUa
|
22
|
-
a+efcPGLDEbwJC7TGRrvk8yassMByBEJ3XueTMzeqWFd+665ptciojYo6BvIAR0N
|
23
|
-
iLwks0x567FZyS8SqTcCAwEAAaM5MDcwCQYDVR0TBAIwADAdBgNVHQ4EFgQUxVgR
|
24
|
-
5TUqf7Hd24ICb3g4FNbM7oYwCwYDVR0PBAQDAgSwMA0GCSqGSIb3DQEBBQUAA4IB
|
25
|
-
AQDdJj+NzZhiYXA56z0wzRUA/Fcf6CYqKB+RFRlPssDEcHTor5SnwdWgQof/gNLi
|
26
|
-
Qel1Om4zO0Shcp89jxaUqtvEdYVhmyfc0vycHmemKttNBT734yMrEJtF8Hhy+Dnz
|
27
|
-
9CzixXLvgGaRH+mf3M0+l+zIDJJr2L+39L8cyTSSRnp/srfI8aSmJKhGshudBKoC
|
28
|
-
Ty6Gi071pwoJXvdMaE/6iPy7bUzlndYdHyYuWSKaO9N47HqQ62oEnBraglw6ghoi
|
29
|
-
UgImJlChAzCoDP9zi9tdm6jAr7ttF25R9PPYr11ILb7dYe3qUzlNlM6zJx/nb31b
|
30
|
-
IhdyRVup4qLcqYSTPsm6u7VA
|
31
|
-
-----END CERTIFICATE-----
|
32
|
-
date: 2013-08-20 00:00:00.000000000 Z
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-03 00:00:00.000000000 Z
|
33
12
|
dependencies:
|
34
13
|
- !ruby/object:Gem::Dependency
|
35
14
|
name: ref
|
@@ -105,6 +84,7 @@ files:
|
|
105
84
|
- ext/v8/trycatch.cc
|
106
85
|
- ext/v8/v8.cc
|
107
86
|
- ext/v8/value.cc
|
87
|
+
- lib/therubyracer.rb
|
108
88
|
- lib/v8.rb
|
109
89
|
- lib/v8/access.rb
|
110
90
|
- lib/v8/access/indices.rb
|
@@ -158,7 +138,8 @@ files:
|
|
158
138
|
- thefrontside.png
|
159
139
|
- therubyracer.gemspec
|
160
140
|
homepage: http://github.com/cowboyd/therubyracer
|
161
|
-
licenses:
|
141
|
+
licenses:
|
142
|
+
- MIT
|
162
143
|
metadata: {}
|
163
144
|
post_install_message:
|
164
145
|
rdoc_options: []
|
@@ -177,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
177
158
|
version: '0'
|
178
159
|
requirements: []
|
179
160
|
rubyforge_project:
|
180
|
-
rubygems_version: 2.0.
|
161
|
+
rubygems_version: 2.0.3
|
181
162
|
signing_key:
|
182
163
|
specification_version: 4
|
183
164
|
summary: Embed the V8 JavaScript interpreter into Ruby
|