better_errors 2.5.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 832f46e8977908b469e6b527edbaf770541b66dfafcc3f8c1b292c0c6c25838c
4
- data.tar.gz: 4584adc6e2870f40a5bd3eb0d7f18b693380e6a1c04716217f00c9190766f3e7
3
+ metadata.gz: 10f7411145be495cf17cbebdf087e1bb21fe8c6fc8c07397fa406e7fc1f9f917
4
+ data.tar.gz: 3b14b75eaa97285c3ad5f685671348694aa7174cc43e52826e49e21a2f139b0d
5
5
  SHA512:
6
- metadata.gz: 844ecf262fdeee48a8165e201a189fcd7812db7bf437bf8e5e11ba80f63edeaa841015fcbc21a11b291e9705c8751fa382eba94e86b90d350828c662fffdbf0b
7
- data.tar.gz: 82ff2fbb24fcbd5dafefe1776125da521cf5813461bca58700060d9be41aa7c138fe95d98b3056289aab5976adc48b83b7dc204521500fc85fe6ee8eb141d09b
6
+ metadata.gz: 141e1056c402ed7b0aa0965278018096ca1d2bc4032072692c1f146ad09d6848d87792d665ecc6dcb41322594e91d9a5e27955edc560bb665a2995f150c0be4e
7
+ data.tar.gz: 03a94aa9fdcd0340b1fdf913a52978437692587efabe196ebb119087712086cc304289ec1c684ab4efbdece115a4bd1298b57bf58699a0d672f76f6aa196793b
@@ -1,9 +1,5 @@
1
- sudo: false
2
1
  language: ruby
3
2
  cache: bundler
4
- before_install:
5
- - gem update --system
6
- - gem update bundler
7
3
  notifications:
8
4
  webhooks:
9
5
  # With COVERALLS_PARALLEL, coverage information sent to coveralls will not be processed until
@@ -12,23 +8,28 @@ notifications:
12
8
  - secure: "YnHYbTq51ySistjvOxsuNhyg4GLuUffEJstTYeGYXiBF7HG5h43IVYo8KNuLzwkgsOYBcNo+YMdQX7qCqJffSbhsr1FZRSzBmjFFxcyD4hu+ukM2theZ4mePVAZiePscYvQPRNY4hIb4d3egStJEytkalDhB3sOebF57tIaCssg="
13
9
  rvm:
14
10
  - 2.2.10
15
- - 2.3.7
16
- - 2.4.4
17
- - 2.5.1
11
+ - 2.3.8
12
+ - 2.4.9
13
+ - 2.5.7
14
+ - 2.6.5
15
+ - 2.7.0
18
16
  - ruby-head
19
17
  gemfile:
20
18
  - gemfiles/rails42.gemfile
21
19
  - gemfiles/rails50.gemfile
22
20
  - gemfiles/rails51.gemfile
23
21
  - gemfiles/rails52.gemfile
22
+ - gemfiles/rails60.gemfile
24
23
  - gemfiles/rails42_haml.gemfile
25
24
  - gemfiles/rails50_haml.gemfile
26
25
  - gemfiles/rails51_haml.gemfile
27
26
  - gemfiles/rails52_haml.gemfile
27
+ - gemfiles/rails60_haml.gemfile
28
28
  - gemfiles/rails42_boc.gemfile
29
29
  - gemfiles/rails50_boc.gemfile
30
30
  - gemfiles/rails51_boc.gemfile
31
31
  - gemfiles/rails52_boc.gemfile
32
+ - gemfiles/rails60_boc.gemfile
32
33
  - gemfiles/rack.gemfile
33
34
  - gemfiles/rack_boc.gemfile
34
35
  - gemfiles/pry09.gemfile
@@ -41,15 +42,57 @@ matrix:
41
42
  - gemfile: gemfiles/pry010.gemfile
42
43
  - gemfile: gemfiles/pry011.gemfile
43
44
  exclude:
44
- - rvm: 2.4.4
45
+ - rvm: 2.2.10
46
+ gemfile: gemfiles/rails60.gemfile
47
+ - rvm: 2.2.10
48
+ gemfile: gemfiles/rails60_boc.gemfile
49
+ - rvm: 2.2.10
50
+ gemfile: gemfiles/rails60_haml.gemfile
51
+ - rvm: 2.3.8
45
52
  gemfile: gemfiles/rails42.gemfile
46
- - rvm: 2.4.4
53
+ - rvm: 2.3.8
47
54
  gemfile: gemfiles/rails42_boc.gemfile
48
- - rvm: 2.4.4
55
+ - rvm: 2.3.8
49
56
  gemfile: gemfiles/rails42_haml.gemfile
50
- - rvm: 2.5.1
57
+ - rvm: 2.3.8
58
+ gemfile: gemfiles/rails60.gemfile
59
+ - rvm: 2.3.8
60
+ gemfile: gemfiles/rails60_boc.gemfile
61
+ - rvm: 2.3.8
62
+ gemfile: gemfiles/rails60_haml.gemfile
63
+ - rvm: 2.4.9
51
64
  gemfile: gemfiles/rails42.gemfile
52
- - rvm: 2.5.1
65
+ - rvm: 2.4.9
53
66
  gemfile: gemfiles/rails42_boc.gemfile
54
- - rvm: 2.5.1
67
+ - rvm: 2.4.9
68
+ gemfile: gemfiles/rails42_haml.gemfile
69
+ - rvm: 2.4.9
70
+ gemfile: gemfiles/rails60.gemfile
71
+ - rvm: 2.4.9
72
+ gemfile: gemfiles/rails60_boc.gemfile
73
+ - rvm: 2.4.9
74
+ gemfile: gemfiles/rails60_haml.gemfile
75
+ - rvm: 2.5.7
76
+ gemfile: gemfiles/rails42.gemfile
77
+ - rvm: 2.5.7
78
+ gemfile: gemfiles/rails42_boc.gemfile
79
+ - rvm: 2.5.7
80
+ gemfile: gemfiles/rails42_haml.gemfile
81
+ - rvm: 2.6.5
82
+ gemfile: gemfiles/rails42.gemfile
83
+ - rvm: 2.6.5
84
+ gemfile: gemfiles/rails42_boc.gemfile
85
+ - rvm: 2.6.5
86
+ gemfile: gemfiles/rails42_haml.gemfile
87
+ - rvm: 2.7.0
88
+ gemfile: gemfiles/rails42.gemfile
89
+ - rvm: 2.7.0
90
+ gemfile: gemfiles/rails42_boc.gemfile
91
+ - rvm: 2.7.0
92
+ gemfile: gemfiles/rails42_haml.gemfile
93
+ - rvm: ruby-head
94
+ gemfile: gemfiles/rails42.gemfile
95
+ - rvm: ruby-head
96
+ gemfile: gemfiles/rails42_boc.gemfile
97
+ - rvm: ruby-head
55
98
  gemfile: gemfiles/rails42_haml.gemfile
data/Gemfile CHANGED
@@ -3,3 +3,4 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  # gem "pry-byebug"
6
+ gem 'simplecov', require: false
data/README.md CHANGED
@@ -35,6 +35,28 @@ end
35
35
 
36
36
  _Note: If you discover that Better Errors isn't working - particularly after upgrading from version 0.5.0 or less - be sure to set `config.consider_all_requests_local = true` in `config/environments/development.rb`._
37
37
 
38
+ ### Optional: Set `EDITOR`
39
+
40
+ For many reasons outside of Better Errors, you should have the `EDITOR` environment variable set to your preferred
41
+ editor.
42
+ Better Errors, like many other tools, will use that environment variable to show a link that opens your
43
+ editor to the file and line from the console.
44
+
45
+ By default the links will open TextMate-protocol links.
46
+
47
+ To see if your editor is supported or to set up a different editor, see [the wiki](https://github.com/BetterErrors/better_errors/wiki/Link-to-your-editor).
48
+
49
+ ### Optional: Set `BETTER_ERRORS_INSIDE_FRAME`
50
+
51
+ If your application is running inside of an iframe, or if you have a Content Security Policy that disallows links
52
+ to other protocols, the editor links will not work.
53
+
54
+ To work around this set `BETTER_ERRORS_INSIDE_FRAME=1` in the environment, and the links will include `target=_blank`,
55
+ allowing the link to open regardless of the policy.
56
+
57
+ _This works because it opens the editor from a new browser tab, escaping from the restrictions of your site._
58
+ _Unfortunately it leaves behind an empty tab each time, so only use this if needed._
59
+
38
60
  ## Security
39
61
 
40
62
  **NOTE:** It is *critical* you put better\_errors only in the **development** section of your Gemfile.
@@ -93,6 +115,16 @@ See [the wiki for instructions on configuring the editor](https://github.com/Bet
93
115
  BetterErrors.maximum_variable_inspect_size = 100_000
94
116
  ```
95
117
 
118
+ ## Ignore inspection of variables with certain classes.
119
+
120
+ ```ruby
121
+ # e.g. in config/initializers/better_errors.rb
122
+ # This will stop BetterErrors from trying to inspect objects of these classes, which can cause
123
+ # slow loading times and unneccessary database queries. Does not check inheritance chain, use
124
+ # strings not contants.
125
+ # default value: ['ActionDispatch::Request', 'ActionDispatch::Response']
126
+ BetterErrors.ignored_classes = ['ActionDispatch::Request', 'ActionDispatch::Response']
127
+ ```
96
128
 
97
129
  ## Get in touch!
98
130
 
@@ -22,9 +22,12 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_development_dependency "rake", "~> 10.0"
24
24
  s.add_development_dependency "rspec", "~> 3.5"
25
+ s.add_development_dependency "rspec-html-matchers"
25
26
  s.add_development_dependency "rspec-its"
26
27
  s.add_development_dependency "yard"
27
- s.add_development_dependency "kramdown"
28
+ # kramdown 2.1 requires Ruby 2.3+
29
+ s.add_development_dependency "kramdown", (RUBY_VERSION < '2.3' ? '< 2.0.0' : '> 2.0.0')
30
+ # simplecov and coveralls must not be included here. See the Gemfiles instead.
28
31
 
29
32
  s.add_dependency "erubi", ">= 1.0.0"
30
33
  s.add_dependency "coderay", ">= 1.0.0"
@@ -33,4 +36,12 @@ Gem::Specification.new do |s|
33
36
  # optional dependencies:
34
37
  # s.add_dependency "binding_of_caller"
35
38
  # s.add_dependency "pry"
39
+
40
+ if s.respond_to?(:metadata)
41
+ s.metadata['changelog_uri'] = 'https://github.com/BetterErrors/better_errors/releases'
42
+ s.metadata['source_code_uri'] = 'https://github.com/BetterErrors/better_errors'
43
+ s.metadata['bug_tracker_uri'] = 'https://github.com/BetterErrors/better_errors/issues'
44
+ else
45
+ puts "Your RubyGems does not support metadata. Update if you'd like to make a release."
46
+ end
36
47
  end
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 4.2.0"
4
4
  gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
6
 
6
7
  gem 'coveralls', require: false
7
8
 
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 4.2.0"
4
4
  gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
6
  gem "binding_of_caller"
6
7
 
7
8
  gem 'coveralls', require: false
@@ -2,6 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 4.2.0"
4
4
  gem 'nokogiri', RUBY_VERSION < '2.1' ? '~> 1.6.0' : '>= 1.7'
5
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
5
6
  gem "haml"
6
7
 
7
8
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.0.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
 
5
6
  gem 'coveralls', require: false
6
7
 
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.0.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "binding_of_caller"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.0.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "haml"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.1.0"
4
+ gem 'i18n', '< 1.5.2', require: false if RUBY_VERSION < '2.3'
4
5
 
5
6
  gem 'coveralls', require: false
6
7
 
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.1.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "binding_of_caller"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.1.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "haml"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.2.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
 
5
6
  gem 'coveralls', require: false
6
7
 
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.2.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "binding_of_caller"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -1,6 +1,7 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gem "rails", "~> 5.2.0"
4
+ gem 'i18n', '< 1.5.2' if RUBY_VERSION < '2.3'
4
5
  gem "haml"
5
6
 
6
7
  gem 'coveralls', require: false
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.0.0"
4
+
5
+ gem 'coveralls', require: false
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.0.0"
4
+ gem "binding_of_caller"
5
+
6
+ gem 'coveralls', require: false
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.0.0"
4
+ gem "haml"
5
+
6
+ gem 'coveralls', require: false
7
+
8
+ gemspec path: "../"
@@ -21,6 +21,7 @@ module BetterErrors
21
21
  { symbols: [:idea], sniff: /idea/i, url: "idea://open?file=%{file}&line=%{line}" },
22
22
  { symbols: [:rubymine], sniff: /mine/i, url: "x-mine://open?file=%{file}&line=%{line}" },
23
23
  { symbols: [:vscode, :code], sniff: /code/i, url: "vscode://file/%{file}:%{line}" },
24
+ { symbols: [:vscodium, :codium], sniff: /codium/i, url: "vscodium://file/%{file}:%{line}" },
24
25
  { symbols: [:atom], sniff: /atom/i, url: "atom://core/open/file?filename=%{file}&line=%{line}" },
25
26
  ]
26
27
 
@@ -54,9 +55,14 @@ module BetterErrors
54
55
  # the variable won't be returned.
55
56
  # @return int
56
57
  attr_accessor :maximum_variable_inspect_size
58
+
59
+ # List of classes that are excluded from inspection.
60
+ # @return [Array]
61
+ attr_accessor :ignored_classes
57
62
  end
58
63
  @ignored_instance_variables = []
59
64
  @maximum_variable_inspect_size = 100_000
65
+ @ignored_classes = ['ActionDispatch::Request', 'ActionDispatch::Response']
60
66
 
61
67
  # Returns a proc, which when called with a filename and line number argument,
62
68
  # returns a URL to open the filename and line in the selected editor.
@@ -26,8 +26,13 @@ module BetterErrors
26
26
  @id ||= SecureRandom.hex(8)
27
27
  end
28
28
 
29
- def render(template_name = "main")
29
+ def render(template_name = "main", csrf_token = nil)
30
30
  binding.eval(self.class.template(template_name).src)
31
+ rescue => e
32
+ # Fix the backtrace, which doesn't identify the template that failed (within Better Errors).
33
+ # We don't know the line number, so just injecting the template path has to be enough.
34
+ e.backtrace.unshift "#{self.class.template_path(template_name)}:0"
35
+ raise
31
36
  end
32
37
 
33
38
  def do_variables(opts)
@@ -59,7 +64,19 @@ module BetterErrors
59
64
  end
60
65
 
61
66
  def exception_message
62
- exception.message.lstrip
67
+ exception.message.strip.gsub(/(\r?\n\s*\r?\n)+/, "\n")
68
+ end
69
+
70
+ def active_support_actions
71
+ return [] unless defined?(ActiveSupport::ActionableError)
72
+
73
+ ActiveSupport::ActionableError.actions(exception.type)
74
+ end
75
+
76
+ def action_dispatch_action_endpoint
77
+ return unless defined?(ActionDispatch::ActionableExceptions)
78
+
79
+ ActionDispatch::ActionableExceptions.endpoint
63
80
  end
64
81
 
65
82
  def application_frames
@@ -105,11 +122,17 @@ module BetterErrors
105
122
  end
106
123
 
107
124
  def inspect_value(obj)
108
- InspectableValue.new(obj).to_html
125
+ if BetterErrors.ignored_classes.include? obj.class.name
126
+ "<span class='unsupported'>(Instance of ignored class. "\
127
+ "#{obj.class.name ? "Remove #{CGI.escapeHTML(obj.class.name)} from" : "Modify"}"\
128
+ " BetterErrors.ignored_classes if you need to see it.)</span>"
129
+ else
130
+ InspectableValue.new(obj).to_html
131
+ end
109
132
  rescue BetterErrors::ValueLargerThanConfiguredMaximum
110
- "<span class='unsupported'>(object too large. "\
111
- "Modify #{CGI.escapeHTML(obj.class.name)}#inspect "\
112
- "or adjust BetterErrors.maximum_variable_inspect_size)</span>"
133
+ "<span class='unsupported'>(Object too large. "\
134
+ "#{obj.class.name ? "Modify #{CGI.escapeHTML(obj.class.name)}#inspect or a" : "A"}"\
135
+ "djust BetterErrors.maximum_variable_inspect_size if you need to see it.)</span>"
113
136
  rescue Exception => e
114
137
  "<span class='unsupported'>(exception #{CGI.escapeHTML(e.class.to_s)} was raised in inspect)</span>"
115
138
  end
@@ -1,5 +1,6 @@
1
1
  require "json"
2
2
  require "ipaddr"
3
+ require "securerandom"
3
4
  require "set"
4
5
  require "rack"
5
6
 
@@ -33,12 +34,14 @@ module BetterErrors
33
34
  # Adds an address to the set of IP addresses allowed to access Better
34
35
  # Errors.
35
36
  def self.allow_ip!(addr)
36
- ALLOWED_IPS << IPAddr.new(addr)
37
+ ALLOWED_IPS << (addr.is_a?(IPAddr) ? addr : IPAddr.new(addr))
37
38
  end
38
39
 
39
40
  allow_ip! "127.0.0.0/8"
40
41
  allow_ip! "::1/128" rescue nil # windows ruby doesn't have ipv6 support
41
42
 
43
+ CSRF_TOKEN_COOKIE_NAME = 'BetterErrors-CSRF-Token'
44
+
42
45
  # A new instance of BetterErrors::Middleware
43
46
  #
44
47
  # @param app The Rack app/middleware to wrap with Better Errors
@@ -72,7 +75,7 @@ module BetterErrors
72
75
  def better_errors_call(env)
73
76
  case env["PATH_INFO"]
74
77
  when %r{/__better_errors/(?<id>.+?)/(?<method>\w+)\z}
75
- internal_call env, $~
78
+ internal_call(env, $~[:id], $~[:method])
76
79
  when %r{/__better_errors/?\z}
77
80
  show_error_page env
78
81
  else
@@ -89,11 +92,14 @@ module BetterErrors
89
92
  end
90
93
 
91
94
  def show_error_page(env, exception=nil)
95
+ request = Rack::Request.new(env)
96
+ csrf_token = request.cookies[CSRF_TOKEN_COOKIE_NAME] || SecureRandom.uuid
97
+
92
98
  type, content = if @error_page
93
99
  if text?(env)
94
100
  [ 'plain', @error_page.render('text') ]
95
101
  else
96
- [ 'html', @error_page.render ]
102
+ [ 'html', @error_page.render('main', csrf_token) ]
97
103
  end
98
104
  else
99
105
  [ 'html', no_errors_page ]
@@ -104,12 +110,22 @@ module BetterErrors
104
110
  status_code = ActionDispatch::ExceptionWrapper.new(env, exception).status_code
105
111
  end
106
112
 
107
- [status_code, { "Content-Type" => "text/#{type}; charset=utf-8" }, [content]]
113
+ response = Rack::Response.new(content, status_code, { "Content-Type" => "text/#{type}; charset=utf-8" })
114
+
115
+ unless request.cookies[CSRF_TOKEN_COOKIE_NAME]
116
+ response.set_cookie(CSRF_TOKEN_COOKIE_NAME, value: csrf_token, httponly: true, same_site: :strict)
117
+ end
118
+
119
+ # In older versions of Rack, the body returned here is actually a Rack::BodyProxy which seems to be a bug.
120
+ # (It contains status, headers and body and does not act like an array of strings.)
121
+ # Since we already have status code and body here, there's no need to use the ones in the Rack::Response.
122
+ (_status_code, headers, _body) = response.finish
123
+ [status_code, headers, [content]]
108
124
  end
109
125
 
110
126
  def text?(env)
111
127
  env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" ||
112
- !env["HTTP_ACCEPT"].to_s.include?('html')
128
+ !env["HTTP_ACCEPT"].to_s.include?('html')
113
129
  end
114
130
 
115
131
  def log_exception
@@ -129,13 +145,22 @@ module BetterErrors
129
145
  end
130
146
  end
131
147
 
132
- def internal_call(env, opts)
148
+ def internal_call(env, id, method)
149
+ return not_found_json_response unless %w[variables eval].include?(method)
133
150
  return no_errors_json_response unless @error_page
134
- return invalid_error_json_response if opts[:id] != @error_page.id
151
+ return invalid_error_json_response if id != @error_page.id
152
+
153
+ request = Rack::Request.new(env)
154
+ return invalid_csrf_token_json_response unless request.cookies[CSRF_TOKEN_COOKIE_NAME]
155
+
156
+ request.body.rewind
157
+ body = JSON.parse(request.body.read)
158
+ return invalid_csrf_token_json_response unless request.cookies[CSRF_TOKEN_COOKIE_NAME] == body['csrfToken']
159
+
160
+ return not_acceptable_json_response unless request.content_type == 'application/json'
135
161
 
136
- env["rack.input"].rewind
137
- response = @error_page.send("do_#{opts[:method]}", JSON.parse(env["rack.input"].read))
138
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(response)]]
162
+ response = @error_page.send("do_#{method}", body)
163
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(response)]]
139
164
  end
140
165
 
141
166
  def no_errors_page
@@ -157,18 +182,40 @@ module BetterErrors
157
182
  "The application has been restarted since this page loaded, " +
158
183
  "or the framework is reloading all gems before each request "
159
184
  end
160
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(
185
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
161
186
  error: 'No exception information available',
162
187
  explanation: explanation,
163
188
  )]]
164
189
  end
165
190
 
166
191
  def invalid_error_json_response
167
- [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(
192
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
168
193
  error: "Session expired",
169
194
  explanation: "This page was likely opened from a previous exception, " +
170
195
  "and the exception is no longer available in memory.",
171
196
  )]]
172
197
  end
198
+
199
+ def invalid_csrf_token_json_response
200
+ [200, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
201
+ error: "Invalid CSRF Token",
202
+ explanation: "The browser session might have been cleared, " +
203
+ "or something went wrong.",
204
+ )]]
205
+ end
206
+
207
+ def not_found_json_response
208
+ [404, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
209
+ error: "Not found",
210
+ explanation: "Not a recognized internal call.",
211
+ )]]
212
+ end
213
+
214
+ def not_acceptable_json_response
215
+ [406, { "Content-Type" => "application/json; charset=utf-8" }, [JSON.dump(
216
+ error: "Request not acceptable",
217
+ explanation: "The internal request did not match an acceptable content type.",
218
+ )]]
219
+ end
173
220
  end
174
221
  end
@@ -4,9 +4,8 @@ module BetterErrors
4
4
  attr_reader :exception, :message, :backtrace
5
5
 
6
6
  def initialize(exception)
7
- if exception.respond_to?(:cause)
8
- exception = exception.cause if exception.cause
9
- elsif exception.respond_to?(:original_exception) && exception.original_exception
7
+ if exception.respond_to?(:original_exception) && exception.original_exception
8
+ # This supports some specific Rails exceptions, and is not intended to act the same as `#cause`.
10
9
  exception = exception.original_exception
11
10
  end
12
11
 
@@ -36,8 +35,13 @@ module BetterErrors
36
35
 
37
36
  def setup_backtrace_from_bindings
38
37
  @backtrace = exception.__better_errors_bindings_stack.map { |binding|
39
- file = binding.eval "__FILE__"
40
- line = binding.eval "__LINE__"
38
+ if binding.respond_to?(:source_location) # Ruby >= 2.6
39
+ file = binding.source_location[0]
40
+ line = binding.source_location[1]
41
+ else
42
+ file = binding.eval "__FILE__"
43
+ line = binding.eval "__LINE__"
44
+ end
41
45
  name = binding.frame_description
42
46
  StackFrame.new(file, line, name, binding)
43
47
  }
@@ -53,6 +57,10 @@ module BetterErrors
53
57
 
54
58
  def massage_syntax_error
55
59
  case exception.class.to_s
60
+ when "ActionView::Template::Error"
61
+ if exception.respond_to?(:file_name) && exception.respond_to?(:line_number)
62
+ backtrace.unshift(StackFrame.new(exception.file_name, exception.line_number.to_i, "view template"))
63
+ end
56
64
  when "Haml::SyntaxError", "Sprockets::Coffeelint::Error"
57
65
  if /\A(.+?):(\d+)/ =~ exception.backtrace.first
58
66
  backtrace.unshift(StackFrame.new($1, $2.to_i, ""))
@@ -69,7 +69,10 @@ module BetterErrors
69
69
  def local_variables
70
70
  return {} unless frame_binding
71
71
 
72
- frame_binding.eval("local_variables").each_with_object({}) do |name, hash|
72
+ lv = frame_binding.eval("local_variables")
73
+ return {} unless lv
74
+
75
+ lv.each_with_object({}) do |name, hash|
73
76
  # Ruby 2.2's local_variables will include the hidden #$! variable if
74
77
  # called from within a rescue context. This is not a valid variable name,
75
78
  # so the local_variable_get method complains. This should probably be
@@ -94,7 +97,10 @@ module BetterErrors
94
97
  end
95
98
 
96
99
  def visible_instance_variables
97
- frame_binding.eval("instance_variables") - BetterErrors.ignored_instance_variables
100
+ iv = frame_binding.eval("instance_variables")
101
+ return {} unless iv
102
+
103
+ iv - BetterErrors.ignored_instance_variables
98
104
  end
99
105
 
100
106
  def to_s
@@ -146,6 +146,14 @@
146
146
  }
147
147
 
148
148
  /* Heading */
149
+ header.exception .fix-actions {
150
+ margin-top: .5em;
151
+ }
152
+
153
+ header.exception .fix-actions input[type=submit] {
154
+ font-weight: bold;
155
+ }
156
+
149
157
  header.exception h2 {
150
158
  font-weight: 200;
151
159
  font-size: 11pt;
@@ -153,7 +161,7 @@
153
161
 
154
162
  header.exception h2,
155
163
  header.exception p {
156
- line-height: 1.4em;
164
+ line-height: 1.5em;
157
165
  overflow: hidden;
158
166
  white-space: pre;
159
167
  text-overflow: ellipsis;
@@ -166,7 +174,7 @@
166
174
 
167
175
  header.exception p {
168
176
  font-weight: 200;
169
- font-size: 20pt;
177
+ font-size: 17pt;
170
178
  color: white;
171
179
  }
172
180
 
@@ -744,6 +752,18 @@
744
752
  <header class="exception">
745
753
  <h2><strong><%= exception_type %></strong> <span>at <%= request_path %></span></h2>
746
754
  <p><%= exception_message %></p>
755
+ <% unless active_support_actions.empty? %>
756
+ <div class='fix-actions'>
757
+ <% active_support_actions.each do |action, _| %>
758
+ <form class="button_to" method="post" action="<%= action_dispatch_action_endpoint %>">
759
+ <input type="submit" value="<%= action %>">
760
+ <input type="hidden" name="action" value="<%= action %>">
761
+ <input type="hidden" name="error" value="<%= exception_type %>">
762
+ <input type="hidden" name="location" value="<%= request_path %>">
763
+ </form>
764
+ <% end %>
765
+ </div>
766
+ <% end %>
747
767
  </header>
748
768
  </div>
749
769
 
@@ -780,6 +800,7 @@
780
800
  (function() {
781
801
 
782
802
  var OID = "<%= id %>";
803
+ var csrfToken = "<%= csrf_token %>";
783
804
 
784
805
  var previousFrame = null;
785
806
  var previousFrameInfo = null;
@@ -790,6 +811,7 @@
790
811
  var req = new XMLHttpRequest();
791
812
  req.open("POST", "//" + window.location.host + <%== uri_prefix.gsub("<", "&lt;").inspect %> + "/__better_errors/" + OID + "/" + method, true);
792
813
  req.setRequestHeader("Content-Type", "application/json");
814
+ opts.csrfToken = csrfToken;
793
815
  req.send(JSON.stringify(opts));
794
816
  req.onreadystatechange = function() {
795
817
  if(req.readyState == 4) {
@@ -1,7 +1,14 @@
1
1
  <header class="trace_info clearfix">
2
2
  <div class="title">
3
3
  <h2 class="name"><%= @frame.name %></h2>
4
- <div class="location"><span class="filename"><a href="<%= editor_url(@frame) %>"><%= @frame.pretty_path %></a></span></div>
4
+ <div class="location">
5
+ <span class="filename">
6
+ <a
7
+ href="<%= editor_url(@frame) %>"
8
+ <%= ENV.key?('BETTER_ERRORS_INSIDE_FRAME') ? "target=_blank" : '' %>
9
+ ><%= @frame.pretty_path %></a>
10
+ </span>
11
+ </div>
5
12
  </div>
6
13
  <div class="code_block clearfix">
7
14
  <%== html_formatted_code_block @frame %>
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "2.5.0"
2
+ VERSION = "2.8.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Somerville
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-27 00:00:00.000000000 Z
11
+ date: 2020-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '3.5'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec-its
42
+ name: rspec-html-matchers
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: yard
56
+ name: rspec-its
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: kramdown
70
+ name: yard
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: kramdown
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">"
88
+ - !ruby/object:Gem::Version
89
+ version: 2.0.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">"
95
+ - !ruby/object:Gem::Version
96
+ version: 2.0.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: erubi
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -157,6 +171,9 @@ files:
157
171
  - gemfiles/rails52.gemfile
158
172
  - gemfiles/rails52_boc.gemfile
159
173
  - gemfiles/rails52_haml.gemfile
174
+ - gemfiles/rails60.gemfile
175
+ - gemfiles/rails60_boc.gemfile
176
+ - gemfiles/rails60_haml.gemfile
160
177
  - lib/better_errors.rb
161
178
  - lib/better_errors/code_formatter.rb
162
179
  - lib/better_errors/code_formatter/html.rb
@@ -178,7 +195,10 @@ files:
178
195
  homepage: https://github.com/BetterErrors/better_errors
179
196
  licenses:
180
197
  - MIT
181
- metadata: {}
198
+ metadata:
199
+ changelog_uri: https://github.com/BetterErrors/better_errors/releases
200
+ source_code_uri: https://github.com/BetterErrors/better_errors
201
+ bug_tracker_uri: https://github.com/BetterErrors/better_errors/issues
182
202
  post_install_message:
183
203
  rdoc_options: []
184
204
  require_paths:
@@ -194,8 +214,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
214
  - !ruby/object:Gem::Version
195
215
  version: '0'
196
216
  requirements: []
197
- rubyforge_project:
198
- rubygems_version: 2.7.6
217
+ rubygems_version: 3.1.2
199
218
  signing_key:
200
219
  specification_version: 4
201
220
  summary: Better error page for Rails and other Rack apps