web-console 2.3.0 → 3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +41 -3
- data/MIT-LICENSE +1 -1
- data/README.markdown +14 -41
- data/lib/web_console/exception_mapper.rb +33 -0
- data/lib/web_console/extensions.rb +38 -16
- data/lib/web_console/integration/cruby.rb +18 -35
- data/lib/web_console/integration/rubinius.rb +22 -50
- data/lib/web_console/integration.rb +27 -2
- data/lib/web_console/middleware.rb +9 -10
- data/lib/web_console/railtie.rb +4 -7
- data/lib/web_console/request.rb +3 -3
- data/lib/web_console/session.rb +18 -13
- data/lib/web_console/templates/console.js.erb +1 -1
- data/lib/web_console/templates/layouts/javascript.erb +1 -1
- data/lib/web_console/testing/fake_middleware.rb +2 -6
- data/lib/web_console/version.rb +1 -1
- data/lib/web_console/view.rb +10 -1
- data/lib/web_console/whiny_request.rb +3 -3
- data/lib/web_console.rb +21 -16
- metadata +14 -49
- data/lib/web_console/helper.rb +0 -22
- data/lib/web_console/integration/jruby.rb +0 -111
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: caf063e0c1a30832d5fa0b6ce776514809889448
|
4
|
+
data.tar.gz: 0ea92426f743c1463500a0367b8d490501b80e20
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc7485fccd26fc2af5a0110215df7baf09188f6ee94d2cb02a6da71c649bb22f84070ff4f7dd0d1c34ba355ff962ac590f1cf8520b04bc4db91ef5256e8b7b49
|
7
|
+
data.tar.gz: f8e6b128bfc10fba1c76d95287a0316d028281acac1853b451f024a99c23b6c2d26a6ad3cb1fa4b87395aaabd4c446f2dc3a9d1f792ceff2e86b34c1b7e92e76
|
data/CHANGELOG.markdown
CHANGED
@@ -2,14 +2,51 @@
|
|
2
2
|
|
3
3
|
## master (unreleased)
|
4
4
|
|
5
|
+
## 3.3.1
|
6
|
+
|
7
|
+
Drop support for Rails `4.2.0`.
|
8
|
+
|
9
|
+
## 3.3.0
|
10
|
+
|
11
|
+
* [203](https://github.com/rails/web-console/pull/203) Map bindings to traces based on the trace __FILE__ and __LINE__ ([@gsamokovarov])
|
12
|
+
|
13
|
+
## 3.2.1
|
14
|
+
|
15
|
+
* [#202](https://github.com/rails/web-console/pull/202) Use first binding when there is no application binding ([@sh19910711])
|
16
|
+
|
17
|
+
## 3.2.0
|
18
|
+
|
19
|
+
* [#198](https://github.com/rails/web-console/pull/198) Pick the first application trace binding on errors ([@sh19910711])
|
20
|
+
* [#189](https://github.com/rails/web-console/pull/189) Silence ActionView rendering information ([@gsamokovarov])
|
21
|
+
|
22
|
+
## 3.1.1
|
23
|
+
|
24
|
+
* [#185](https://github.com/rails/web-console/pull/185) Fix `rails console` startup ([@gsamokovarov])
|
25
|
+
|
26
|
+
## 3.1.0
|
27
|
+
|
28
|
+
* [#182](https://github.com/rails/web-console/pull/182) Let `#console` live in `Kernel` ([@schneems])
|
29
|
+
* [#181](https://github.com/rails/web-console/pull/181) Log internal Web Console errors ([@gsamokovarov])
|
30
|
+
* [#180](https://github.com/rails/web-console/pull/180) Autoload Web Console constants for faster Rails boot time ([@herminiotorres])
|
31
|
+
|
32
|
+
## 3.0.0
|
33
|
+
|
34
|
+
* [#173](https://github.com/rails/web-console/pull/173) Revert "Change config.development_only default until 4.2.4 is released" ([@gsamokovarov])
|
35
|
+
* [#171](https://github.com/rails/web-console/pull/171) Fixed blocked IP logging ([@gsamokovarov])
|
36
|
+
* [#162](https://github.com/rails/web-console/pull/162) Render the console inside the body tag ([@gsamokovarov])
|
37
|
+
* [#165](https://github.com/rails/web-console/pull/165) Revamped integrations for CRuby and Rubinius ([@gsamokovarov])
|
38
|
+
|
5
39
|
## 2.3.0
|
6
40
|
|
7
|
-
|
8
|
-
|
41
|
+
This is mainly a Rails 5 compatibility release. If you have the chance, please
|
42
|
+
go to 3.1.0 instead.
|
43
|
+
|
44
|
+
* [#181](https://github.com/rails/web-console/pull/181) Log internal Web Console errors (@schneems)
|
45
|
+
* [#150](https://github.com/rails/web-console/pull/150) Revert #150. (@gsamokovarov)
|
9
46
|
|
10
47
|
## 2.2.1
|
11
48
|
|
12
|
-
* [#150](https://github.com/rails/web-console/pull/150) Change config.development_only default until 4.2.4 is released
|
49
|
+
* [#150](https://github.com/rails/web-console/pull/150) Change config.development_only default until 4.2.4 is released ([@gsamokovarov])
|
13
50
|
|
14
51
|
## 2.2.0
|
15
52
|
|
@@ -53,4 +90,5 @@
|
|
53
90
|
[@parterburn]: https://github.com/parterburn
|
54
91
|
[@sh19910711]: https://github.com/sh19910711
|
55
92
|
[@frenesim]: https://github.com/frenesim
|
93
|
+
[@herminiotorres]: https://github.com/herminiotorres
|
56
94
|
[@schneems]: https://github.com/schneems
|
data/MIT-LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright 2014 Charlie Somerville, Genadi Samokovarov, Guillermo Iguaran and Ryan Dao
|
1
|
+
Copyright 2014-2016 Charlie Somerville, Genadi Samokovarov, Guillermo Iguaran and Ryan Dao
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
data/README.markdown
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
<p align=right>
|
2
2
|
Documentation for:
|
3
|
-
<a href=https://github.com/rails/web-console/tree/
|
4
|
-
<a href=https://github.com/rails/web-console/tree/v2.1
|
5
|
-
<a href=https://github.com/rails/web-console/tree/
|
6
|
-
<a href=https://github.com/rails/web-console/tree/v2.1.2>v2.1.2</a>
|
7
|
-
<a href=https://github.com/rails/web-console/tree/v2.1.3>v2.1.3</a>
|
3
|
+
<a href=https://github.com/rails/web-console/tree/v1.0.4>v1.0.4</a>
|
4
|
+
<a href=https://github.com/rails/web-console/tree/v2.2.1>v2.2.1</a>
|
5
|
+
<a href=https://github.com/rails/web-console/tree/v3.0.0>v3.0.0</a>
|
8
6
|
</p>
|
9
7
|
|
10
8
|
# Web Console [![Build Status](https://travis-ci.org/rails/web-console.svg?branch=master)](https://travis-ci.org/rails/web-console)
|
@@ -28,7 +26,7 @@ application, add the following to your `Gemfile`.
|
|
28
26
|
|
29
27
|
```ruby
|
30
28
|
group :development do
|
31
|
-
gem 'web-console'
|
29
|
+
gem 'web-console'
|
32
30
|
end
|
33
31
|
```
|
34
32
|
|
@@ -37,35 +35,9 @@ restart your server for the _Web Console_ to kick in.
|
|
37
35
|
|
38
36
|
## Runtime
|
39
37
|
|
40
|
-
_Web Console_ uses [John Mair]'s [binding_of_caller] to spawn a console in a
|
41
|
-
specific binding. This comes at the price of limited Ruby runtime support.
|
42
|
-
|
43
38
|
### CRuby
|
44
39
|
|
45
|
-
CRuby
|
46
|
-
|
47
|
-
### JRuby
|
48
|
-
|
49
|
-
JRuby needs to run in interpreted mode. You can enable it by:
|
50
|
-
|
51
|
-
```bash
|
52
|
-
export JRUBY_OPTS=-J-Djruby.compile.mode=OFF
|
53
|
-
|
54
|
-
# If you run JRuby 1.7.12 and above, you can use:
|
55
|
-
export JRUBY_OPTS=--dev
|
56
|
-
```
|
57
|
-
|
58
|
-
An unstable version of [binding_of_caller] is needed as the latest stable one
|
59
|
-
won't compile on _JRuby_. To install it, put the following in your application
|
60
|
-
`Gemfile`:
|
61
|
-
|
62
|
-
```ruby
|
63
|
-
group :development do
|
64
|
-
gem 'binding_of_caller', '0.7.3.pre1'
|
65
|
-
end
|
66
|
-
```
|
67
|
-
|
68
|
-
Only _JRuby_ 1.7, is supported (no JRuby 9K support at the moment).
|
40
|
+
CRuby 2.2 and above is required.
|
69
41
|
|
70
42
|
### Rubinius
|
71
43
|
|
@@ -75,7 +47,7 @@ Internal errors like `ZeroDevisionError` aren't caught.
|
|
75
47
|
|
76
48
|
The web console allows you to create an interactive Ruby session in your
|
77
49
|
browser. Those sessions are launched automatically in case on an error, but
|
78
|
-
they can also be launched manually in
|
50
|
+
they can also be launched manually in any page.
|
79
51
|
|
80
52
|
For example, calling `console` in a view will display a console in the current
|
81
53
|
page in the context of the view binding.
|
@@ -96,8 +68,10 @@ class PostsController < ApplicationController
|
|
96
68
|
end
|
97
69
|
```
|
98
70
|
|
99
|
-
|
100
|
-
|
71
|
+
The method is defined in `Kernel` and you can invoke it any application code.
|
72
|
+
|
73
|
+
Only one `console` invocation is allowed once per request. If you happen to
|
74
|
+
have multiple ones, a `WebConsole::DoubleRenderError` will be raised.
|
101
75
|
|
102
76
|
## Configuration
|
103
77
|
|
@@ -215,17 +189,16 @@ Make sure you configuration lives in `config/environments/development.rb`.
|
|
215
189
|
|
216
190
|
## Credits
|
217
191
|
|
218
|
-
* Shoutout to [Charlie Somerville] for [better_errors]
|
219
|
-
* Kudos to [John Mair] for [
|
192
|
+
* Shoutout to [Charlie Somerville] for [better_errors].
|
193
|
+
* Kudos to [John Mair] for [debug_inspector].
|
220
194
|
* Thanks to [Charles Oliver Nutter] for all the _JRuby_ feedback.
|
221
|
-
* Hugs and kisses to all of our [contributors]
|
195
|
+
* Hugs and kisses to all of our [contributors]!
|
222
196
|
|
223
197
|
[better_errors]: https://github.com/charliesome/better_errors
|
224
|
-
[
|
198
|
+
[debug_inspector]: https://github.com/banister/debug_inspector
|
225
199
|
[Charlie Somerville]: https://github.com/charliesome
|
226
200
|
[John Mair]: https://github.com/banister
|
227
201
|
[Charles Oliver Nutter]: https://github.com/headius
|
228
202
|
[templates]: https://github.com/rails/web-console/tree/master/lib/web_console/templates
|
229
|
-
[this]: https://github.com/rails/web-console/blob/master/lib/web_console/integration/cruby.rb#L20-L32
|
230
203
|
[rvt]: https://github.com/gsamokovarov/rvt
|
231
204
|
[contributors]: https://github.com/rails/web-console/graphs/contributors
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module WebConsole
|
2
|
+
class ExceptionMapper
|
3
|
+
def initialize(exception)
|
4
|
+
@backtrace = exception.backtrace
|
5
|
+
@bindings = exception.bindings
|
6
|
+
end
|
7
|
+
|
8
|
+
def first
|
9
|
+
guess_the_first_application_binding || @bindings.first
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](index)
|
13
|
+
guess_binding_for_index(index) || @bindings[index]
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def guess_binding_for_index(index)
|
19
|
+
file, line = @backtrace[index].to_s.split(':')
|
20
|
+
line = line.to_i
|
21
|
+
|
22
|
+
@bindings.find do |binding|
|
23
|
+
binding.eval('__FILE__') == file && binding.eval('__LINE__') == line
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def guess_the_first_application_binding
|
28
|
+
@bindings.find do |binding|
|
29
|
+
binding.eval('__FILE__').to_s.start_with?(Rails.root.to_s)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,23 +1,45 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
render_exception_without_web_console(request, exception).tap do
|
4
|
-
# Retain superficial Rails 5 compatibility.
|
5
|
-
env = Hash === request ? request : request.env
|
1
|
+
module Kernel
|
2
|
+
module_function
|
6
3
|
|
7
|
-
|
4
|
+
# Instructs Web Console to render a console in the specified binding.
|
5
|
+
#
|
6
|
+
# If +bidning+ isn't explicitly given it will default to the binding of the
|
7
|
+
# previous frame. E.g. the one that invoked +console+.
|
8
|
+
#
|
9
|
+
# Raises DoubleRenderError if a double +console+ invocation per request is
|
10
|
+
# detected.
|
11
|
+
def console(binding = WebConsole.caller_bindings.first)
|
12
|
+
raise WebConsole::DoubleRenderError if Thread.current[:__web_console_binding]
|
8
13
|
|
9
|
-
|
10
|
-
env['web_console.exception'] = error
|
14
|
+
Thread.current[:__web_console_binding] = binding
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
# Make sure nothing is rendered from the view helper. Otherwise
|
17
|
+
# you're gonna see unexpected #<Binding:0x007fee4302b078> in the
|
18
|
+
# templates.
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module ActionDispatch
|
24
|
+
class DebugExceptions
|
25
|
+
def render_exception_with_web_console(request, exception)
|
26
|
+
render_exception_without_web_console(request, exception).tap do
|
27
|
+
backtrace_cleaner = request.get_header('action_dispatch.backtrace_cleaner')
|
28
|
+
error = ExceptionWrapper.new(backtrace_cleaner, exception).exception
|
29
|
+
|
30
|
+
# Get the original exception if ExceptionWrapper decides to follow it.
|
31
|
+
Thread.current[:__web_console_exception] = error
|
32
|
+
|
33
|
+
# ActionView::Template::Error bypass ExceptionWrapper original
|
34
|
+
# exception following. The backtrace in the view is generated from
|
35
|
+
# reaching out to original_exception in the view.
|
36
|
+
if error.is_a?(ActionView::Template::Error)
|
37
|
+
Thread.current[:__web_console_exception] = error.cause
|
38
|
+
end
|
17
39
|
end
|
18
40
|
end
|
19
|
-
end
|
20
41
|
|
21
|
-
|
22
|
-
|
42
|
+
alias_method :render_exception_without_web_console, :render_exception
|
43
|
+
alias_method :render_exception, :render_exception_with_web_console
|
44
|
+
end
|
23
45
|
end
|
@@ -1,40 +1,23 @@
|
|
1
|
-
|
2
|
-
begin
|
3
|
-
# We share the same exception binding extraction mechanism as better_errors,
|
4
|
-
# so try to use it if it is already available. It also solves problems like
|
5
|
-
# charliesome/better_errors#272, caused by an infinite recursion.
|
6
|
-
require 'better_errors'
|
1
|
+
require 'debug_inspector'
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
rescue LoadError
|
13
|
-
# The bindings in which the exception originated in.
|
14
|
-
def bindings
|
15
|
-
@bindings || []
|
16
|
-
end
|
17
|
-
|
18
|
-
# CRuby calls #set_backtrace every time it raises an exception. Overriding
|
19
|
-
# it to assign the #bindings.
|
20
|
-
def set_backtrace_with_binding_of_caller(*args)
|
21
|
-
# Thanks to @charliesome who wrote this bit for better_errors.
|
22
|
-
unless Thread.current[:__web_console_exception_lock]
|
23
|
-
Thread.current[:__web_console_exception_lock] = true
|
24
|
-
begin
|
25
|
-
# Raising an exception here will cause all of the rubies to go into a
|
26
|
-
# stack overflow. Some rubies may even segfault. See
|
27
|
-
# https://bugs.ruby-lang.org/issues/10164 for details.
|
28
|
-
@bindings = binding.callers.drop(1)
|
29
|
-
ensure
|
30
|
-
Thread.current[:__web_console_exception_lock] = false
|
31
|
-
end
|
32
|
-
end
|
3
|
+
def WebConsole.caller_bindings
|
4
|
+
bindings = RubyVM::DebugInspector.open do |context|
|
5
|
+
context.backtrace_locations.each_index.map { |i| context.frame_binding(i) }
|
6
|
+
end
|
33
7
|
|
34
|
-
|
35
|
-
|
8
|
+
# For C functions, we can't extract a binding. In this case,
|
9
|
+
# DebugInspector#frame_binding would have returned us nil. That's why we need
|
10
|
+
# to compact the bindings.
|
11
|
+
#
|
12
|
+
# Dropping two bindings, removes the current Ruby one in this exact method,
|
13
|
+
# and the one in the caller method. The caller method binding can be obtained
|
14
|
+
# by Kernel#binding, if needed.
|
15
|
+
bindings.compact.drop(2)
|
16
|
+
end
|
36
17
|
|
37
|
-
|
38
|
-
|
18
|
+
TracePoint.trace(:raise) do |context|
|
19
|
+
exc = context.raised_exception
|
20
|
+
if exc.bindings.empty?
|
21
|
+
exc.instance_variable_set(:@bindings, WebConsole.caller_bindings)
|
39
22
|
end
|
40
23
|
end
|
@@ -1,62 +1,34 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Filters internal Rubinius locations.
|
4
|
-
#
|
5
|
-
# There are a couple of reasons why we wanna filter out the locations.
|
6
|
-
#
|
7
|
-
# * ::Kernel.raise, is implemented in Ruby for Rubinius. We don't wanna
|
8
|
-
# have the frame for it to align with the CRuby and JRuby implementations.
|
9
|
-
#
|
10
|
-
# * For internal methods location variables can be nil. We can't create a
|
11
|
-
# bindings for them.
|
12
|
-
#
|
13
|
-
# * Bindings from the current file are considered internal and ignored.
|
14
|
-
#
|
15
|
-
# We do that all that so we can align the bindings with the backtraces
|
16
|
-
# entries.
|
17
|
-
class InternalLocationFilter
|
18
|
-
def initialize(locations)
|
19
|
-
@locations = locations
|
20
|
-
end
|
1
|
+
def WebConsole.caller_bindings
|
2
|
+
locations = ::Rubinius::VM.backtrace(1, true)
|
21
3
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
# Gets the current bindings for all available Ruby frames.
|
32
|
-
#
|
33
|
-
# Filters the internal Rubinius and WebConsole frames.
|
34
|
-
def self.current_bindings
|
35
|
-
locations = ::Rubinius::VM.backtrace(1, true)
|
36
|
-
|
37
|
-
InternalLocationFilter.new(locations).filter.map do |location|
|
38
|
-
Binding.setup(
|
39
|
-
location.variables,
|
40
|
-
location.variables.method,
|
41
|
-
location.constant_scope,
|
42
|
-
location.variables.self,
|
43
|
-
location
|
44
|
-
)
|
45
|
-
end
|
46
|
-
end
|
4
|
+
# Kernel.raise, is implemented in Ruby for Rubinius. We don't wanna have
|
5
|
+
# the frame for it to align with the CRuby and JRuby implementations.
|
6
|
+
#
|
7
|
+
# For internal methods location variables can be nil. We can't create a
|
8
|
+
# bindings for them.
|
9
|
+
locations.reject! do |location|
|
10
|
+
location.file.start_with?('kernel/delta/kernel.rb') || location.variables.nil?
|
47
11
|
end
|
48
|
-
end
|
49
12
|
|
50
|
-
|
51
|
-
|
52
|
-
|
13
|
+
bindings = locations.map do |location|
|
14
|
+
Binding.setup(
|
15
|
+
location.variables,
|
16
|
+
location.variables.method,
|
17
|
+
location.constant_scope,
|
18
|
+
location.variables.self,
|
19
|
+
location
|
20
|
+
)
|
53
21
|
end
|
22
|
+
|
23
|
+
# Drop the binding of the direct caller. That one can be created by
|
24
|
+
# Kernel#binding.
|
25
|
+
bindings.drop(1)
|
54
26
|
end
|
55
27
|
|
56
28
|
::Rubinius.singleton_class.class_eval do
|
57
29
|
def raise_exception_with_current_bindings(exc)
|
58
30
|
if exc.bindings.empty?
|
59
|
-
exc.instance_variable_set(:@bindings, WebConsole
|
31
|
+
exc.instance_variable_set(:@bindings, WebConsole.caller_bindings)
|
60
32
|
end
|
61
33
|
|
62
34
|
raise_exception_without_current_bindings(exc)
|
@@ -1,8 +1,33 @@
|
|
1
|
+
class Exception
|
2
|
+
# Returns an array of the exception backtrace locations bindings.
|
3
|
+
#
|
4
|
+
# The list won't map to the traces in #backtrace 1 to 1, because we can't
|
5
|
+
# build bindings for every trace (C functions, for example).
|
6
|
+
#
|
7
|
+
# Every integration should set the instance variable.
|
8
|
+
def bindings
|
9
|
+
defined?(@bindings) ? @bindings : []
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
1
13
|
case RUBY_ENGINE
|
2
14
|
when 'rbx'
|
3
15
|
require 'web_console/integration/rubinius'
|
4
|
-
when 'jruby'
|
5
|
-
require 'web_console/integration/jruby'
|
6
16
|
when 'ruby'
|
7
17
|
require 'web_console/integration/cruby'
|
18
|
+
else
|
19
|
+
# Prevent a `method redefined; discarding old caller_bindings` warning.
|
20
|
+
|
21
|
+
module WebConsole
|
22
|
+
# Returns the Ruby bindings of Kernel#callers locations.
|
23
|
+
#
|
24
|
+
# The list of bindings here doesn't map 1 to 1 with Kernel#callers, as we
|
25
|
+
# can't build Ruby bindings for C functions or the equivalent native
|
26
|
+
# implementations in JRuby and Rubinius.
|
27
|
+
#
|
28
|
+
# This method needs to be overridden by every integration.
|
29
|
+
def self.caller_bindings
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
end
|
8
33
|
end
|
@@ -17,7 +17,7 @@ module WebConsole
|
|
17
17
|
def call(env)
|
18
18
|
app_exception = catch :app_exception do
|
19
19
|
request = create_regular_or_whiny_request(env)
|
20
|
-
return
|
20
|
+
return call_app(env) unless request.from_whitelisted_ip?
|
21
21
|
|
22
22
|
if id = id_for_repl_session_update(request)
|
23
23
|
return update_repl_session(id, request)
|
@@ -25,15 +25,9 @@ module WebConsole
|
|
25
25
|
return change_stack_trace(id, request)
|
26
26
|
end
|
27
27
|
|
28
|
-
status, headers, body =
|
28
|
+
status, headers, body = call_app(env)
|
29
29
|
|
30
|
-
if
|
31
|
-
session = Session.from_exception(exception)
|
32
|
-
elsif binding = env['web_console.binding']
|
33
|
-
session = Session.from_binding(binding)
|
34
|
-
end
|
35
|
-
|
36
|
-
if session && acceptable_content_type?(headers)
|
30
|
+
if session = Session.from(Thread.current) and acceptable_content_type?(headers)
|
37
31
|
response = Response.new(body, status, headers)
|
38
32
|
template = Template.new(env, session)
|
39
33
|
|
@@ -49,13 +43,18 @@ module WebConsole
|
|
49
43
|
WebConsole.logger.error("\n#{e.class}: #{e}\n\tfrom #{e.backtrace.join("\n\tfrom ")}")
|
50
44
|
raise e
|
51
45
|
ensure
|
46
|
+
# Clean up the fiber locals after the session creation. Object#console
|
47
|
+
# uses those to communicate the current binding or exception to the middleware.
|
48
|
+
Thread.current[:__web_console_exception] = nil
|
49
|
+
Thread.current[:__web_console_binding] = nil
|
50
|
+
|
52
51
|
raise app_exception if Exception === app_exception
|
53
52
|
end
|
54
53
|
|
55
54
|
private
|
56
55
|
|
57
56
|
def acceptable_content_type?(headers)
|
58
|
-
Mime::Type.parse(headers['Content-Type']).first == Mime
|
57
|
+
Mime::Type.parse(headers['Content-Type']).first == Mime[:html]
|
59
58
|
end
|
60
59
|
|
61
60
|
def json_response(opts = {})
|
data/lib/web_console/railtie.rb
CHANGED
@@ -6,21 +6,18 @@ module WebConsole
|
|
6
6
|
config.web_console.whitelisted_ips = %w( 127.0.0.1 ::1 )
|
7
7
|
|
8
8
|
initializer 'web_console.initialize' do
|
9
|
+
require 'web_console/integration'
|
9
10
|
require 'web_console/extensions'
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
ActiveSupport.on_load(:action_controller) do
|
16
|
-
ActionController::Base.send(:include, Helper)
|
12
|
+
if logger = ::Rails.logger
|
13
|
+
WebConsole.logger = logger
|
17
14
|
end
|
18
15
|
end
|
19
16
|
|
20
17
|
initializer 'web_console.development_only' do
|
21
18
|
unless (config.web_console.development_only == false) || Rails.env.development?
|
22
19
|
abort <<-END.strip_heredoc
|
23
|
-
Web Console is activated in the #{Rails.env} environment
|
20
|
+
Web Console is activated in the #{Rails.env} environment. This is
|
24
21
|
usually a mistake. To ensure it's only activated in development
|
25
22
|
mode, move it to the development group of your Gemfile:
|
26
23
|
|
data/lib/web_console/request.rb
CHANGED
@@ -5,14 +5,14 @@ module WebConsole
|
|
5
5
|
cattr_accessor :whitelisted_ips
|
6
6
|
@@whitelisted_ips = Whitelist.new
|
7
7
|
|
8
|
-
# Define a vendor MIME type. We can call it using Mime
|
8
|
+
# Define a vendor MIME type. We can call it using Mime[:web_console_v2].
|
9
9
|
Mime::Type.register 'application/vnd.web-console.v2', :web_console_v2
|
10
10
|
|
11
11
|
# Returns whether a request came from a whitelisted IP.
|
12
12
|
#
|
13
13
|
# For a request to hit Web Console features, it needs to come from a white
|
14
14
|
# listed IP.
|
15
|
-
def
|
15
|
+
def from_whitelisted_ip?
|
16
16
|
whitelisted_ips.include?(strict_remote_ip)
|
17
17
|
end
|
18
18
|
|
@@ -23,7 +23,7 @@ module WebConsole
|
|
23
23
|
|
24
24
|
# Returns whether the request is acceptable.
|
25
25
|
def acceptable?
|
26
|
-
xhr? && accepts.any? { |mime| Mime
|
26
|
+
xhr? && accepts.any? { |mime| Mime[:web_console_v2] == mime }
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
data/lib/web_console/session.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module WebConsole
|
2
|
-
# A session lets you persist
|
3
|
-
#
|
2
|
+
# A session lets you persist an +Evaluator+ instance in memory associated
|
3
|
+
# with multiple bindings.
|
4
4
|
#
|
5
5
|
# Each newly created session is persisted into memory and you can find it
|
6
|
-
# later its +id+.
|
6
|
+
# later by its +id+.
|
7
7
|
#
|
8
8
|
# A session may be associated with multiple bindings. This is used by the
|
9
9
|
# error pages only, as currently, this is the only client that needs to do
|
@@ -21,14 +21,19 @@ module WebConsole
|
|
21
21
|
inmemory_storage[id]
|
22
22
|
end
|
23
23
|
|
24
|
-
# Create a Session from an exception.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
#
|
30
|
-
|
31
|
-
|
24
|
+
# Create a Session from an binding or exception in a storage.
|
25
|
+
#
|
26
|
+
# The storage is expected to respond to #[]. The binding is expected in
|
27
|
+
# :__web_console_binding and the exception in :__web_console_exception.
|
28
|
+
#
|
29
|
+
# Can return nil, if no binding or exception have been preserved in the
|
30
|
+
# storage.
|
31
|
+
def from(storage)
|
32
|
+
if exc = storage[:__web_console_exception]
|
33
|
+
new(ExceptionMapper.new(exc))
|
34
|
+
elsif binding = storage[:__web_console_binding]
|
35
|
+
new([binding])
|
36
|
+
end
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
@@ -37,8 +42,8 @@ module WebConsole
|
|
37
42
|
|
38
43
|
def initialize(bindings)
|
39
44
|
@id = SecureRandom.hex(16)
|
40
|
-
@bindings =
|
41
|
-
@evaluator = Evaluator.new(
|
45
|
+
@bindings = bindings
|
46
|
+
@evaluator = Evaluator.new(bindings.first)
|
42
47
|
|
43
48
|
store_into_memory
|
44
49
|
end
|
@@ -488,7 +488,7 @@ REPLConsole.request = function request(method, url, params, callback) {
|
|
488
488
|
xhr.open(method, url, true);
|
489
489
|
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
490
490
|
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
|
491
|
-
xhr.setRequestHeader("Accept", "<%= Mime
|
491
|
+
xhr.setRequestHeader("Accept", "<%= Mime[:web_console_v2] %>");
|
492
492
|
xhr.send(params);
|
493
493
|
|
494
494
|
xhr.onreadystatechange = function() {
|
@@ -1,11 +1,7 @@
|
|
1
1
|
require 'action_view'
|
2
|
-
require '
|
3
|
-
require 'active_support/core_ext/string/access'
|
4
|
-
require 'json'
|
5
|
-
require 'web_console/whitelist'
|
6
|
-
require 'web_console/request'
|
7
|
-
require 'web_console/view'
|
2
|
+
require 'web_console'
|
8
3
|
require 'web_console/testing/helper'
|
4
|
+
Mime = { web_console_v2: 'fake' }
|
9
5
|
|
10
6
|
module WebConsole
|
11
7
|
module Testing
|
data/lib/web_console/version.rb
CHANGED
data/lib/web_console/view.rb
CHANGED
@@ -5,7 +5,7 @@ module WebConsole
|
|
5
5
|
# The error pages are special, because they are the only pages that
|
6
6
|
# currently require multiple bindings. We get those from exceptions.
|
7
7
|
def only_on_error_page(*args)
|
8
|
-
yield if
|
8
|
+
yield if Thread.current[:__web_console_exception].present?
|
9
9
|
end
|
10
10
|
|
11
11
|
# Render JavaScript inside a script tag and a closure.
|
@@ -14,6 +14,7 @@ module WebConsole
|
|
14
14
|
# script tag and enclosed in a closure, so you don't have to worry for
|
15
15
|
# leaking globals, unless you explicitly want to.
|
16
16
|
def render_javascript(template)
|
17
|
+
assign(template: template)
|
17
18
|
render(template: template, layout: 'layouts/javascript')
|
18
19
|
end
|
19
20
|
|
@@ -25,6 +26,14 @@ module WebConsole
|
|
25
26
|
render(template: template, layout: 'layouts/inlined_string')
|
26
27
|
end
|
27
28
|
|
29
|
+
# Custom ActionView::Base#render wrapper which silences all the log
|
30
|
+
# printings.
|
31
|
+
#
|
32
|
+
# Helps to keep the Rails logs clean during errors.
|
33
|
+
def render(*)
|
34
|
+
WebConsole.logger.silence { super }
|
35
|
+
end
|
36
|
+
|
28
37
|
# Override method for ActionView::Helpers::TranslationHelper#t.
|
29
38
|
#
|
30
39
|
# This method escapes the original return value for JavaScript, since the
|
@@ -4,9 +4,9 @@ module WebConsole
|
|
4
4
|
# If any calls to +from_whitelisted_ip?+ and +acceptable_content_type?+
|
5
5
|
# return false, an info log message will be displayed in users' logs.
|
6
6
|
class WhinyRequest < SimpleDelegator
|
7
|
-
def
|
8
|
-
whine_unless request.
|
9
|
-
"Cannot render console from #{request.
|
7
|
+
def from_whitelisted_ip?
|
8
|
+
whine_unless request.from_whitelisted_ip? do
|
9
|
+
"Cannot render console from #{request.strict_remote_ip}! " \
|
10
10
|
"Allowed networks: #{request.whitelisted_ips}"
|
11
11
|
end
|
12
12
|
end
|
data/lib/web_console.rb
CHANGED
@@ -1,25 +1,30 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'active_support/dependencies/autoload'
|
3
2
|
require 'active_support/lazy_load_hooks'
|
4
3
|
require 'active_support/logger'
|
5
4
|
|
6
|
-
require 'web_console/integration'
|
7
|
-
require 'web_console/railtie'
|
8
|
-
require 'web_console/errors'
|
9
|
-
require 'web_console/helper'
|
10
|
-
require 'web_console/evaluator'
|
11
|
-
require 'web_console/session'
|
12
|
-
require 'web_console/template'
|
13
|
-
require 'web_console/middleware'
|
14
|
-
require 'web_console/whitelist'
|
15
|
-
require 'web_console/request'
|
16
|
-
require 'web_console/response'
|
17
|
-
require 'web_console/view'
|
18
|
-
require 'web_console/whiny_request'
|
19
|
-
|
20
5
|
module WebConsole
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :View
|
9
|
+
autoload :Evaluator
|
10
|
+
autoload :ExceptionMapper
|
11
|
+
autoload :Session
|
12
|
+
autoload :Response
|
13
|
+
autoload :Request
|
14
|
+
autoload :WhinyRequest
|
15
|
+
autoload :Whitelist
|
16
|
+
autoload :Template
|
17
|
+
autoload :Middleware
|
18
|
+
|
19
|
+
autoload_at 'web_console/errors' do
|
20
|
+
autoload :Error
|
21
|
+
autoload :DoubleRenderError
|
22
|
+
end
|
23
|
+
|
21
24
|
mattr_accessor :logger
|
22
25
|
@@logger = ActiveSupport::Logger.new($stderr)
|
23
26
|
|
24
27
|
ActiveSupport.run_load_hooks(:web_console, self)
|
25
28
|
end
|
29
|
+
|
30
|
+
require 'web_console/railtie'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web-console
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charlie Somerville
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2016-
|
14
|
+
date: 2016-07-05 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: railties
|
@@ -19,90 +19,56 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '5.0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '5.0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: activemodel
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
34
|
- - ">="
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: '
|
36
|
+
version: '5.0'
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
43
|
+
version: '5.0'
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
|
-
name:
|
45
|
+
name: actionview
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
48
|
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
51
|
-
- - "<"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '4.0'
|
50
|
+
version: '5.0'
|
54
51
|
type: :runtime
|
55
52
|
prerelease: false
|
56
53
|
version_requirements: !ruby/object:Gem::Requirement
|
57
54
|
requirements:
|
58
55
|
- - ">="
|
59
56
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
61
|
-
- - "<"
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
version: '4.0'
|
57
|
+
version: '5.0'
|
64
58
|
- !ruby/object:Gem::Dependency
|
65
|
-
name:
|
59
|
+
name: debug_inspector
|
66
60
|
requirement: !ruby/object:Gem::Requirement
|
67
61
|
requirements:
|
68
62
|
- - ">="
|
69
63
|
- !ruby/object:Gem::Version
|
70
|
-
version: 0
|
64
|
+
version: '0'
|
71
65
|
type: :runtime
|
72
66
|
prerelease: false
|
73
67
|
version_requirements: !ruby/object:Gem::Requirement
|
74
68
|
requirements:
|
75
69
|
- - ">="
|
76
70
|
- !ruby/object:Gem::Version
|
77
|
-
version: 0
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: actionmailer
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
81
|
-
requirements:
|
82
|
-
- - ">="
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
version: '4.0'
|
85
|
-
type: :development
|
86
|
-
prerelease: false
|
87
|
-
version_requirements: !ruby/object:Gem::Requirement
|
88
|
-
requirements:
|
89
|
-
- - ">="
|
90
|
-
- !ruby/object:Gem::Version
|
91
|
-
version: '4.0'
|
92
|
-
- !ruby/object:Gem::Dependency
|
93
|
-
name: activerecord
|
94
|
-
requirement: !ruby/object:Gem::Requirement
|
95
|
-
requirements:
|
96
|
-
- - ">="
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
version: '4.0'
|
99
|
-
type: :development
|
100
|
-
prerelease: false
|
101
|
-
version_requirements: !ruby/object:Gem::Requirement
|
102
|
-
requirements:
|
103
|
-
- - ">="
|
104
|
-
- !ruby/object:Gem::Version
|
105
|
-
version: '4.0'
|
71
|
+
version: '0'
|
106
72
|
description:
|
107
73
|
email:
|
108
74
|
- charlie@charliesomerville.com
|
@@ -121,11 +87,10 @@ files:
|
|
121
87
|
- lib/web_console.rb
|
122
88
|
- lib/web_console/errors.rb
|
123
89
|
- lib/web_console/evaluator.rb
|
90
|
+
- lib/web_console/exception_mapper.rb
|
124
91
|
- lib/web_console/extensions.rb
|
125
|
-
- lib/web_console/helper.rb
|
126
92
|
- lib/web_console/integration.rb
|
127
93
|
- lib/web_console/integration/cruby.rb
|
128
|
-
- lib/web_console/integration/jruby.rb
|
129
94
|
- lib/web_console/integration/rubinius.rb
|
130
95
|
- lib/web_console/locales/en.yml
|
131
96
|
- lib/web_console/middleware.rb
|
@@ -165,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
165
130
|
requirements:
|
166
131
|
- - ">="
|
167
132
|
- !ruby/object:Gem::Version
|
168
|
-
version:
|
133
|
+
version: 2.2.2
|
169
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
135
|
requirements:
|
171
136
|
- - ">="
|
data/lib/web_console/helper.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
module WebConsole
|
2
|
-
module Helper
|
3
|
-
# Communicates with the middleware to render a console in a +binding+.
|
4
|
-
#
|
5
|
-
# If +bidning+ isn't explicitly given, Binding#of_caller will be used to
|
6
|
-
# get the binding of the previous frame. E.g. the one that invoked
|
7
|
-
# +console+.
|
8
|
-
#
|
9
|
-
# Raises DoubleRenderError if a double +console+ invocation per request is
|
10
|
-
# detected.
|
11
|
-
def console(binding = nil)
|
12
|
-
raise DoubleRenderError if request.env['web_console.binding']
|
13
|
-
|
14
|
-
request.env['web_console.binding'] = binding || ::Kernel.binding.of_caller(1)
|
15
|
-
|
16
|
-
# Make sure nothing is rendered from the view helper. Otherwise
|
17
|
-
# you're gonna see unexpected #<Binding:0x007fee4302b078> in the
|
18
|
-
# templates.
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,111 +0,0 @@
|
|
1
|
-
require 'English'
|
2
|
-
require 'active_support/core_ext/string/strip'
|
3
|
-
|
4
|
-
java_import org.jruby.RubyInstanceConfig
|
5
|
-
|
6
|
-
module WebConsole
|
7
|
-
module JRuby
|
8
|
-
class << self
|
9
|
-
# Returns whether JRuby is ran in interpreted mode.
|
10
|
-
def interpreted_mode?
|
11
|
-
compile_mode = ::JRuby.runtime.instance_config.compile_mode
|
12
|
-
interpreted_mode = RubyInstanceConfig::CompileMode::OFF
|
13
|
-
|
14
|
-
compile_mode == interpreted_mode
|
15
|
-
end
|
16
|
-
|
17
|
-
# A proc to be used in Kernel#set_trace_func.
|
18
|
-
#
|
19
|
-
# It sets Exception#bindings for an error with all the bindings the
|
20
|
-
# current ThreadContext contains.
|
21
|
-
def set_exception_bindings_trace_func
|
22
|
-
proc do |event, file, line, id, binding, classname|
|
23
|
-
case event
|
24
|
-
when 'raise'
|
25
|
-
if $ERROR_INFO.bindings.empty?
|
26
|
-
# binding_of_caller will generate an improperly built binding at
|
27
|
-
# caller[1]. Every call to a non existent method, constant or a
|
28
|
-
# local variable will result in a Java NullPointerException.
|
29
|
-
#
|
30
|
-
# The binding that Kernel#set_trace_func is giving us is properly
|
31
|
-
# built, so we can use in place of the broken one.
|
32
|
-
bindings = ::Kernel.binding.callers.drop(2).unshift(binding)
|
33
|
-
$ERROR_INFO.instance_variable_set(:@bindings, bindings)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# A fake binding for JRuby in non interpreted mode.
|
41
|
-
#
|
42
|
-
# It won't actually evaluate any code, rather it will tell the user how to
|
43
|
-
# enable interpreted mode.
|
44
|
-
class FakeJRubyBinding
|
45
|
-
TURN_ON_INTERPRETED_MODE_TEXT = <<-END.strip_heredoc
|
46
|
-
JRuby needs to run in interpreted mode for introspection support.
|
47
|
-
|
48
|
-
To turn on interpreted mode, put -J-Djruby.compile.mode=OFF in the
|
49
|
-
JRUBY_OPTS environment variable.
|
50
|
-
END
|
51
|
-
|
52
|
-
def TURN_ON_INTERPRETED_MODE_TEXT.inspect
|
53
|
-
self
|
54
|
-
end
|
55
|
-
|
56
|
-
TURN_ON_INTERPRETED_MODE_TEXT.freeze
|
57
|
-
|
58
|
-
def eval(*)
|
59
|
-
TURN_ON_INTERPRETED_MODE_TEXT
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# A fake array of FakeJRubyBinding objects.
|
64
|
-
#
|
65
|
-
# It is used in Exception#bindings to make sure that when users switch
|
66
|
-
# bindings on the UI, they get a FakeJRubyBinding notifying them what to do
|
67
|
-
# if they want introspection.
|
68
|
-
class FakeJRubyBindingsArray < Array
|
69
|
-
def [](*)
|
70
|
-
FakeJRubyBinding.new
|
71
|
-
end
|
72
|
-
|
73
|
-
# For Kernel#Array and other implicit conversion API. JRuby expects it to
|
74
|
-
# return an object that is_a? an Array. This is the reasoning of
|
75
|
-
# FakeJRubyBindingsArray being a subclass of Array.
|
76
|
-
def to_ary
|
77
|
-
self
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
if WebConsole::JRuby.interpreted_mode?
|
84
|
-
::Exception.class_eval do
|
85
|
-
def bindings
|
86
|
-
@bindings || []
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Kernel#set_trace_func will complain about not being able to capture all the
|
91
|
-
# events without the JRuby --debug flag.
|
92
|
-
silence_warnings do
|
93
|
-
set_trace_func WebConsole::JRuby.set_exception_bindings_trace_func
|
94
|
-
end
|
95
|
-
else
|
96
|
-
::Exception.class_eval do
|
97
|
-
def bindings
|
98
|
-
WebConsole::JRuby::FakeJRubyBindingsArray.new
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
::Binding.class_eval do
|
103
|
-
def of_caller(*)
|
104
|
-
WebConsole::JRuby::FakeJRubyBinding.new
|
105
|
-
end
|
106
|
-
|
107
|
-
def callers
|
108
|
-
WebConsole::JRuby::FakeJRubyBindingsArray.new
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|