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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6488a4b018aa3bcbf2dd9ebdf8bb47a7cece0b5e
4
- data.tar.gz: 9e16c6452241525ff12b8c1231421434cb0d2d06
3
+ metadata.gz: 9cfa70f9de350c1e76e6794ae66d1f7dd2026462
4
+ data.tar.gz: 21a5105a79939e804bfdf22d8a0e4108d614841c
5
5
  SHA512:
6
- metadata.gz: fca9709c4f134600b6ba8e41370b799a258e7a5e61573eff5cef661a77ef87b4595e62ea60195331fbbdb59ad3b1d12d66a8b7d5bcb574208d385a3a33a3bec3
7
- data.tar.gz: acdb5e300dac4818351afce6383da68ef4c73d5bc7de56b700df2752dc777e6dfe30adecb5ab12f4829aaf558f210b288cfadd4c8021670feb556672fd39c0ed
6
+ metadata.gz: cef15fc729596d2d9d0af7e5c5e467ff68e9db40faf66e200af4a7c555494d265a5415119243e440c955738b9bd22e50558fbf4eb69ea1df46ff1a597df267c3
7
+ data.tar.gz: 2bf28f39134268f84dc4bf029d0a9ef060670342c1fd7699e97c21debd4317c2ca14271a99b179a23e506955f557f0568c45d2880a058f891afb39f862549ca0
@@ -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-18mode
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
@@ -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 'gem-compiler' unless Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
10
+ gem "gem-compiler", :platforms => :mri
11
+
data/README.md CHANGED
@@ -1,9 +1,14 @@
1
1
  # therubyracer
2
2
 
3
- * [http://github.com/cowboyd/therubyracer](http://github.com/cowboyd/therubyracer)
4
- * [http://groups.google.com/group/therubyracer](http://groups.google.com/group/therubyracer)
5
- * [irc://irc.freenode.net/therubyracer](http://groups.google.com/group/therubyracer)
6
- * [Documentation](https://github.com/cowboyd/therubyracer/wiki)
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", :require => 'v8'
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
@@ -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) {}
@@ -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
@@ -0,0 +1 @@
1
+ require "v8"
@@ -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
- to_ruby try {script.Run()}
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
@@ -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
- javascript_backtrace = V8::StackTrace.new(trycatch.Message().GetStackTrace())
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
@@ -1,3 +1,3 @@
1
1
  module V8
2
- VERSION = "0.12.0"
2
+ VERSION = "0.12.1"
3
3
  end
@@ -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
@@ -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.first.should == "at three.js:1:7"
68
- e.backtrace[1].should =~ /error_spec.rb/
69
- e.backtrace[2].should == "at two.js:1:1"
70
- e.backtrace[3].should =~ /error_spec.rb/
71
- e.backtrace[4].should == "at one.js:1:1"
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.first.should =~ /error_spec\.rb/
118
- e.backtrace[1].should =~ /boom.js/
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
@@ -15,6 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.extensions = ["ext/v8/extconf.rb"]
16
16
  gem.require_paths = ["lib", "ext"]
17
17
  gem.version = V8::VERSION
18
+ gem.license = 'MIT'
18
19
 
19
20
  gem.add_dependency 'ref'
20
21
  gem.add_dependency 'libv8', '~> 3.16.14.0'
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.0
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.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