lrd_rack_bug 0.3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +45 -0
  3. data/MIT-LICENSE.txt +19 -0
  4. data/README.md +123 -0
  5. data/Rakefile +23 -0
  6. data/Thorfile +113 -0
  7. data/lib/rack/bug/autoloading.rb +25 -0
  8. data/lib/rack/bug/filtered_backtrace.rb +38 -0
  9. data/lib/rack/bug/options.rb +89 -0
  10. data/lib/rack/bug/panel.rb +50 -0
  11. data/lib/rack/bug/panel_app.rb +33 -0
  12. data/lib/rack/bug/panels/active_record_panel/activerecord_extensions.rb +7 -0
  13. data/lib/rack/bug/panels/active_record_panel.rb +45 -0
  14. data/lib/rack/bug/panels/cache_panel/dalli_extension.rb +16 -0
  15. data/lib/rack/bug/panels/cache_panel/memcache_extension.rb +129 -0
  16. data/lib/rack/bug/panels/cache_panel/panel_app.rb +48 -0
  17. data/lib/rack/bug/panels/cache_panel/stats.rb +97 -0
  18. data/lib/rack/bug/panels/cache_panel.rb +51 -0
  19. data/lib/rack/bug/panels/log_panel/logger_extension.rb +24 -0
  20. data/lib/rack/bug/panels/log_panel.rb +56 -0
  21. data/lib/rack/bug/panels/memory_panel.rb +27 -0
  22. data/lib/rack/bug/panels/mongo_panel/mongo_extension.rb +27 -0
  23. data/lib/rack/bug/panels/mongo_panel/stats.rb +48 -0
  24. data/lib/rack/bug/panels/mongo_panel.rb +44 -0
  25. data/lib/rack/bug/panels/rails_info_panel.rb +23 -0
  26. data/lib/rack/bug/panels/redis_panel/redis_extension.rb +28 -0
  27. data/lib/rack/bug/panels/redis_panel/stats.rb +52 -0
  28. data/lib/rack/bug/panels/redis_panel.rb +44 -0
  29. data/lib/rack/bug/panels/request_variables_panel.rb +52 -0
  30. data/lib/rack/bug/panels/sphinx_panel/sphinx_extension.rb +25 -0
  31. data/lib/rack/bug/panels/sphinx_panel/stats.rb +96 -0
  32. data/lib/rack/bug/panels/sphinx_panel.rb +44 -0
  33. data/lib/rack/bug/panels/sql_panel/panel_app.rb +37 -0
  34. data/lib/rack/bug/panels/sql_panel/query.rb +63 -0
  35. data/lib/rack/bug/panels/sql_panel/sql_extension.rb +22 -0
  36. data/lib/rack/bug/panels/sql_panel.rb +60 -0
  37. data/lib/rack/bug/panels/templates_panel/actionview_extension.rb +21 -0
  38. data/lib/rack/bug/panels/templates_panel/rendering.rb +77 -0
  39. data/lib/rack/bug/panels/templates_panel/trace.rb +44 -0
  40. data/lib/rack/bug/panels/templates_panel.rb +51 -0
  41. data/lib/rack/bug/panels/timer_panel.rb +40 -0
  42. data/lib/rack/bug/params_signature.rb +63 -0
  43. data/lib/rack/bug/public/__rack_bug__/bookmarklet.html +10 -0
  44. data/lib/rack/bug/public/__rack_bug__/bookmarklet.js +217 -0
  45. data/lib/rack/bug/public/__rack_bug__/bug.css +220 -0
  46. data/lib/rack/bug/public/__rack_bug__/bug.js +84 -0
  47. data/lib/rack/bug/public/__rack_bug__/jquery-1.3.2.js +4376 -0
  48. data/lib/rack/bug/public/__rack_bug__/jquery.tablesorter.min.js +1 -0
  49. data/lib/rack/bug/public/__rack_bug__/spinner.gif +0 -0
  50. data/lib/rack/bug/rack_static_bug_avoider.rb +16 -0
  51. data/lib/rack/bug/redirect_interceptor.rb +27 -0
  52. data/lib/rack/bug/render.rb +66 -0
  53. data/lib/rack/bug/toolbar.rb +64 -0
  54. data/lib/rack/bug/views/error.html.erb +16 -0
  55. data/lib/rack/bug/views/panels/active_record.html.erb +17 -0
  56. data/lib/rack/bug/views/panels/cache.html.erb +93 -0
  57. data/lib/rack/bug/views/panels/execute_sql.html.erb +32 -0
  58. data/lib/rack/bug/views/panels/explain_sql.html.erb +32 -0
  59. data/lib/rack/bug/views/panels/log.html.erb +21 -0
  60. data/lib/rack/bug/views/panels/mongo.html.erb +32 -0
  61. data/lib/rack/bug/views/panels/profile_sql.html.erb +32 -0
  62. data/lib/rack/bug/views/panels/rails_info.html.erb +19 -0
  63. data/lib/rack/bug/views/panels/redis.html.erb +46 -0
  64. data/lib/rack/bug/views/panels/request_variables.html.erb +29 -0
  65. data/lib/rack/bug/views/panels/sphinx.html.erb +32 -0
  66. data/lib/rack/bug/views/panels/sql.html.erb +43 -0
  67. data/lib/rack/bug/views/panels/templates.html.erb +7 -0
  68. data/lib/rack/bug/views/panels/timer.html.erb +19 -0
  69. data/lib/rack/bug/views/panels/view_cache.html.erb +19 -0
  70. data/lib/rack/bug/views/redirect.html.erb +16 -0
  71. data/lib/rack/bug/views/toolbar.html.erb +42 -0
  72. data/lib/rack/bug.rb +82 -0
  73. data/lrd_rack_bug.gemspec +37 -0
  74. data/spec/custom_matchers.rb +21 -0
  75. data/spec/fixtures/config.ru +8 -0
  76. data/spec/fixtures/dummy_panel.rb +2 -0
  77. data/spec/fixtures/sample_app.rb +46 -0
  78. data/spec/rack/bug/panels/active_record_panel_spec.rb +30 -0
  79. data/spec/rack/bug/panels/cache_panel_spec.rb +167 -0
  80. data/spec/rack/bug/panels/log_panel_spec.rb +43 -0
  81. data/spec/rack/bug/panels/memory_panel_spec.rb +22 -0
  82. data/spec/rack/bug/panels/mongo_panel_spec.rb +51 -0
  83. data/spec/rack/bug/panels/rails_info_panel_spec.rb +40 -0
  84. data/spec/rack/bug/panels/redis_panel_spec.rb +69 -0
  85. data/spec/rack/bug/panels/sql_panel_spec.rb +146 -0
  86. data/spec/rack/bug/panels/templates_panel_spec.rb +71 -0
  87. data/spec/rack/bug/panels/timer_panel_spec.rb +38 -0
  88. data/spec/rack/bug_spec.rb +137 -0
  89. data/spec/rcov.opts +1 -0
  90. data/spec/spec.opts +1 -0
  91. data/spec/spec_helper.rb +44 -0
  92. metadata +177 -0
@@ -0,0 +1,52 @@
1
+ module Rack
2
+ class Bug
3
+
4
+ class RequestVariablesPanel < Panel
5
+
6
+ def name
7
+ "request_variables"
8
+ end
9
+
10
+ def before(env)
11
+ @env = env
12
+ end
13
+
14
+ def heading
15
+ "Rack Env"
16
+ end
17
+
18
+ def content
19
+ sections = {}
20
+ sections["GET"] = sort(@request.GET) if @request.GET.any?
21
+ sections["POST"] = sort(@request.GET) if @request.POST.any?
22
+ sections["Session"] = sort(@request.env["rack.session"]) if @request.env["rack.session"] && @request.env["rack.session"].any?
23
+ sections["Cookies"] = sort(@request.env["rack.request.cookie_hash"]) if @request.env["rack.request.cookie_hash"] && @request.env["rack.request.cookie_hash"].any?
24
+ server, rack = split_and_filter_env(@env)
25
+ sections["SERVER VARIABLES"] = sort(server)
26
+ sections["Rack ENV"] = sort(rack)
27
+ render_template "panels/request_variables", :sections => sections
28
+ end
29
+
30
+ private
31
+ def sort(hash)
32
+ hash.sort_by { |k, v| k.to_s }
33
+ end
34
+
35
+ def split_and_filter_env(env)
36
+ server, rack = {}, {}
37
+ env.each do |k,v|
38
+ if k.index("rack.") == 0
39
+ rack[k] = v
40
+ elsif k.index("rack-bug.") == 0
41
+ #don't output the rack-bug variables - especially secret_key
42
+ else
43
+ server[k] = v
44
+ end
45
+ end
46
+ return server, rack
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,25 @@
1
+ require 'riddle'
2
+
3
+ if defined?(Riddle)
4
+ Riddle::Client.class_eval do
5
+ def request_with_rack_bug(command, messages)
6
+ Rack::Bug::SphinxPanel.record(command, messages) do
7
+ request_without_rack_bug(command, messages)
8
+ end
9
+ end
10
+
11
+ alias_method_chain :request, :rack_bug
12
+ end
13
+ end
14
+
15
+ if defined?(Sphinx::Client)
16
+ Sphinx::Client.class_eval do
17
+ def PerformRequest_with_rack_bug(command, request, additional = nil)
18
+ Rack::Bug::SphinxPanel.record(command, request) do
19
+ PerformRequest_without_rack_bug(command, request, additional)
20
+ end
21
+ end
22
+
23
+ alias_method_chain :PerformRequest, :rack_bug
24
+ end
25
+ end
@@ -0,0 +1,96 @@
1
+ module Rack
2
+ class Bug
3
+ class SphinxPanel
4
+
5
+ class Stats
6
+ class Query
7
+ attr_reader :time
8
+ attr_reader :command
9
+
10
+ def initialize(time, *command_args)
11
+ @time = time
12
+ if command_args.flatten.first == :search
13
+ @command = "search: " + decode_message(command_args.first.flatten.last).collect{|k,v| "#{k} => #{v}"}.join(", ")
14
+ else
15
+ @command = command_args.flatten.first.to_s + ": No more info is available for this Sphinx request type"
16
+ end
17
+ end
18
+
19
+ def display_time
20
+ "%.2fms" % time
21
+ end
22
+
23
+ def decode_message(m)
24
+ @m = m.clone
25
+ params = ActiveSupport::OrderedHash.new
26
+
27
+ params[:offset] = consume_int
28
+ params[:limit] = consume_int
29
+ params[:match_mode] = consume_int
30
+ params[:rank_mode] = consume_int
31
+ params[:sort_mode] = consume_int
32
+ params[:sort_by] = consume_string
33
+ params[:query] = consume_string
34
+ wl = consume_int
35
+ weights = []
36
+ wl.times do weights << consume_int end
37
+ params[:weights] = weights
38
+
39
+ params[:index] = consume_string
40
+
41
+ consume_string
42
+
43
+ params[:id_range] = [consume_64int, consume_64int]
44
+ params
45
+ end
46
+
47
+ def consume_int
48
+ i = @m.unpack("N").first
49
+ @m = @m.slice(4, @m.length - 4)
50
+ i
51
+ end
52
+
53
+ def consume_64int
54
+ i = @m.unpack("NN").first
55
+ @m = @m.slice(8, @m.length - 8)
56
+ i
57
+ end
58
+
59
+ def consume_string
60
+ len = consume_int
61
+ s = @m.slice(0, len)
62
+ @m = @m.slice(len, @m.length - len)
63
+ s
64
+ end
65
+ end
66
+
67
+ attr_reader :calls
68
+ attr_reader :queries
69
+
70
+ def initialize
71
+ @queries = []
72
+ @calls = 0
73
+ @time = 0.0
74
+ end
75
+
76
+ def record_call(time, *command_args)
77
+
78
+ @queries << Query.new(time, command_args)
79
+ @calls += 1
80
+ @time += time
81
+ end
82
+
83
+ def display_time
84
+ "%.2fms" % time
85
+ end
86
+
87
+ def time
88
+ @queries.inject(0) do |memo, query|
89
+ memo + query.time
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,44 @@
1
+ module Rack
2
+ class Bug
3
+
4
+ class SphinxPanel < Panel
5
+ require "rack/bug/panels/sphinx_panel/sphinx_extension"
6
+
7
+ autoload :Stats, "rack/bug/panels/sphinx_panel/stats"
8
+
9
+ def self.record(*sphinx_command_args, &block)
10
+ return block.call unless Rack::Bug.enabled?
11
+
12
+ start_time = Time.now
13
+ result = block.call
14
+ total_time = Time.now - start_time
15
+ stats.record_call(total_time * 1_000, sphinx_command_args)
16
+ return result
17
+ end
18
+
19
+ def self.reset
20
+ Thread.current["rack.bug.sphinx"] = Stats.new
21
+ end
22
+
23
+ def self.stats
24
+ Thread.current["rack.bug.sphinx"] ||= Stats.new
25
+ end
26
+
27
+ def name
28
+ "sphinx"
29
+ end
30
+
31
+ def heading
32
+ "Sphinx: %.2fms (#{self.class.stats.queries.size} calls)" % self.class.stats.time
33
+ end
34
+
35
+ def content
36
+ result = render_template "panels/sphinx", :stats => self.class.stats
37
+ self.class.reset
38
+ return result
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,37 @@
1
+ module Rack
2
+ class Bug
3
+ class SQLPanel
4
+
5
+ class PanelApp < ::Rack::Bug::PanelApp
6
+
7
+ def dispatch
8
+ case request.path_info
9
+ when "/__rack_bug__/explain_sql" then explain_sql
10
+ when "/__rack_bug__/profile_sql" then profile_sql
11
+ when "/__rack_bug__/execute_sql" then execute_sql
12
+ else not_found
13
+ end
14
+ end
15
+
16
+ def explain_sql
17
+ validate_params
18
+ query = Query.new(params["query"], params["time"].to_f)
19
+ render_template "panels/explain_sql", :result => query.explain, :query => query.sql, :time => query.time
20
+ end
21
+
22
+ def profile_sql
23
+ validate_params
24
+ query = Query.new(params["query"], params["time"].to_f)
25
+ render_template "panels/profile_sql", :result => query.profile, :query => query.sql, :time => query.time
26
+ end
27
+
28
+ def execute_sql
29
+ validate_params
30
+ query = Query.new(params["query"], params["time"].to_f)
31
+ render_template "panels/execute_sql", :result => query.execute, :query => query.sql, :time => query.time
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,63 @@
1
+ module Rack
2
+ class Bug
3
+ class SQLPanel
4
+
5
+ class Query
6
+ include Rack::Bug::FilteredBacktrace
7
+
8
+ attr_reader :sql
9
+ attr_reader :time
10
+
11
+ def initialize(sql, time, backtrace = [])
12
+ @sql = sql
13
+ @time = time
14
+ @backtrace = backtrace
15
+ end
16
+
17
+ def human_time
18
+ "%.2fms" % (@time * 1_000)
19
+ end
20
+
21
+ def inspectable?
22
+ sql.strip =~ /^SELECT /i
23
+ end
24
+
25
+ def with_profiling
26
+ self.class.execute("SET PROFILING=1")
27
+ result = yield
28
+ self.class.execute("SET PROFILING=0")
29
+ return result
30
+ end
31
+
32
+ def explain
33
+ self.class.execute "EXPLAIN #{@sql}"
34
+ end
35
+
36
+ def profile
37
+ with_profiling do
38
+ execute
39
+ self.class.execute <<-SQL
40
+ SELECT *
41
+ FROM information_schema.profiling
42
+ WHERE query_id = (SELECT query_id FROM information_schema.profiling ORDER BY query_id DESC LIMIT 1)
43
+ SQL
44
+ end
45
+ end
46
+
47
+ def execute
48
+ self.class.execute(@sql)
49
+ end
50
+
51
+ def valid_hash?(secret_key, possible_hash)
52
+ hash = Digest::SHA1.hexdigest [secret_key, @sql].join(":")
53
+ possible_hash == hash
54
+ end
55
+
56
+ def self.execute(sql)
57
+ ActiveRecord::Base.connection.execute(sql)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,22 @@
1
+ if defined?(ActiveRecord) && defined?(ActiveRecord::ConnectionAdapters)
2
+
3
+ if defined?(ActiveSupport::Notifications)
4
+ require 'active_record/base'
5
+ ActiveSupport::Notifications.subscribe(/sql.active_record/) do |*args|
6
+ event = ActiveSupport::Notifications::Event.new(*args)
7
+ Rack::Bug::SQLPanel.record_event(event.payload[:sql], event.duration) # TODO: is there any way to get a backtrace out of here?
8
+ end
9
+ else
10
+
11
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
12
+ def log_with_rack_bug(sql, name, &block)
13
+ Rack::Bug::SQLPanel.record(sql, Kernel.caller) do
14
+ log_without_rack_bug(sql, name, &block)
15
+ end
16
+ end
17
+
18
+ alias_method_chain :log, :rack_bug
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,60 @@
1
+ require "digest"
2
+
3
+ module Rack
4
+ class Bug
5
+
6
+ class SQLPanel < Panel
7
+ require "rack/bug/panels/sql_panel/sql_extension"
8
+
9
+ autoload :PanelApp, "rack/bug/panels/sql_panel/panel_app"
10
+ autoload :Query, "rack/bug/panels/sql_panel/query"
11
+
12
+ def panel_app
13
+ PanelApp.new
14
+ end
15
+
16
+ def self.record(sql, backtrace = [], &block)
17
+ return block.call unless Rack::Bug.enabled?
18
+
19
+ start_time = Time.now
20
+ result = block.call
21
+ queries << Query.new(sql, Time.now - start_time, backtrace)
22
+
23
+ return result
24
+ end
25
+
26
+ def self.record_event(sql, duration, backtrace = [])
27
+ return unless Rack::Bug.enabled?
28
+ queries << Query.new(sql, duration, backtrace)
29
+ end
30
+
31
+ def self.reset
32
+ Thread.current["rack.test.queries"] = []
33
+ end
34
+
35
+ def self.queries
36
+ Thread.current["rack.test.queries"] ||= []
37
+ end
38
+
39
+ def self.total_time
40
+ (queries.inject(0) { |memo, query| memo + query.time}) * 1_000
41
+ end
42
+
43
+ def name
44
+ "sql"
45
+ end
46
+
47
+ def heading
48
+ "#{self.class.queries.size} Queries (%.2fms)" % self.class.total_time
49
+ end
50
+
51
+ def content
52
+ result = render_template "panels/sql", :queries => self.class.queries
53
+ self.class.reset
54
+ return result
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,21 @@
1
+ if defined?(ActionView) && defined?(ActionView::Template)
2
+ if defined?(ActiveSupport::Notifications)
3
+
4
+ ActiveSupport::Notifications.subscribe /^render.*\.action_view/ do |*args|
5
+ event = ActiveSupport::Notifications::Event.new(*args)
6
+ Rack::Bug::TemplatesPanel.record_event(event)
7
+ end
8
+
9
+ else
10
+ ActionView::Template.class_eval do
11
+
12
+ def render_template_with_rack_bug(*args, &block)
13
+ Rack::Bug::TemplatesPanel.record(path_without_format_and_extension) do
14
+ render_template_without_rack_bug(*args, &block)
15
+ end
16
+ end
17
+
18
+ alias_method_chain :render_template, :rack_bug
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,77 @@
1
+ module Rack
2
+ class Bug
3
+ class TemplatesPanel
4
+
5
+ class Rendering
6
+ attr_accessor :name
7
+ attr_accessor :start_time
8
+ alias_method :time, :start_time
9
+ attr_accessor :end_time
10
+ attr_accessor :parent
11
+ attr_reader :children
12
+
13
+ def initialize(name, start_time = nil, end_time = nil)
14
+ @name = name
15
+ @start_time = start_time || Time.now
16
+ @end_time = end_time
17
+ @children = []
18
+ end
19
+
20
+ def add(rendering)
21
+ @children << rendering
22
+ rendering.parent = self
23
+ end
24
+
25
+ def delete(rendering)
26
+ @children.delete(rendering)
27
+ end
28
+
29
+ def duration
30
+ if @end_time
31
+ @end_time - @start_time
32
+ else
33
+ child_duration
34
+ end
35
+ end
36
+
37
+ def exclusive_duration
38
+ duration - child_duration
39
+ end
40
+
41
+ def child_duration
42
+ children.inject(0.0) { |memo, c| memo + c.duration }
43
+ end
44
+
45
+ def duration_summary
46
+ if children.any?
47
+ "%.2fms, %.2f exclusive" % [duration * 1_000, exclusive_duration * 1_000]
48
+ else
49
+ "%.2fms" % (duration * 1_000)
50
+ end
51
+ end
52
+ def html
53
+ <<-HTML
54
+ <li>
55
+ <p>#{name} (#{duration_summary})</p>
56
+
57
+ #{children_html}
58
+ </li>
59
+ HTML
60
+ end
61
+
62
+ def children_html
63
+ return "" unless children.any?
64
+
65
+ <<-HTML
66
+ <ul>#{joined_children_html}</ul>
67
+ HTML
68
+ end
69
+
70
+ def joined_children_html
71
+ children.map { |c| c.html }.join
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,44 @@
1
+ module Rack
2
+ class Bug
3
+ class TemplatesPanel
4
+
5
+ class Trace
6
+
7
+ def start(template_name)
8
+ rendering = Rendering.new(template_name)
9
+ rendering.start_time = Time.now
10
+ @current.add(rendering)
11
+ @current = rendering
12
+ end
13
+
14
+ def add(template_name, start_time, end_time, event)
15
+ current = Rendering.new(template_name, start_time, end_time)
16
+ root_rendering.children.each do |child|
17
+ next unless event.parent_of?(child)
18
+ root_rendering.delete(child)
19
+ current.add(child)
20
+ end
21
+ root_rendering.add(current)
22
+ end
23
+
24
+ def finished(template_name)
25
+ @current.end_time = Time.now
26
+ @current = @current.parent
27
+ end
28
+
29
+ def initialize
30
+ @current = root_rendering
31
+ end
32
+
33
+ def total_time
34
+ root_rendering.duration
35
+ end
36
+
37
+ def root_rendering
38
+ @root_rendering ||= Rendering.new("root")
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,51 @@
1
+ module Rack
2
+ class Bug
3
+
4
+ class TemplatesPanel < Panel
5
+ require "rack/bug/panels/templates_panel/actionview_extension"
6
+
7
+ autoload :Trace, "rack/bug/panels/templates_panel/trace"
8
+ autoload :Rendering, "rack/bug/panels/templates_panel/rendering"
9
+
10
+ def self.record(template, &block)
11
+ return block.call unless Rack::Bug.enabled?
12
+
13
+ template_trace.start(template)
14
+ result = block.call
15
+ template_trace.finished(template)
16
+ return result
17
+ end
18
+
19
+ def self.record_event(event)
20
+ return unless Rack::Bug.enabled?
21
+
22
+ template_description = "#{event.name}: #{event.payload[:virtual_path] || event.payload[:identifier]}"
23
+ template_trace.add(template_description, event.time, event.end, event)
24
+ end
25
+
26
+ def self.reset
27
+ Thread.current["rack.bug.template_trace"] = Trace.new
28
+ end
29
+
30
+ def self.template_trace
31
+ Thread.current["rack.bug.template_trace"] ||= Trace.new
32
+ end
33
+
34
+ def name
35
+ "templates"
36
+ end
37
+
38
+ def heading
39
+ "Templates: %.2fms" % (self.class.template_trace.total_time * 1_000)
40
+ end
41
+
42
+ def content
43
+ result = render_template "panels/templates", :root_rendering => self.class.template_trace.root_rendering
44
+ self.class.reset
45
+ return result
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,40 @@
1
+ require "benchmark"
2
+
3
+ module Rack
4
+ class Bug
5
+
6
+ class TimerPanel < Panel
7
+
8
+ def name
9
+ "timer"
10
+ end
11
+
12
+ def call(env)
13
+ status, headers, body = nil
14
+ @times = Benchmark.measure do
15
+ status, headers, body = @app.call(env)
16
+ end
17
+
18
+ @measurements = [
19
+ ["User CPU time", "%.2fms" % (@times.utime * 1_000)],
20
+ ["System CPU time", "%.2fms" % (@times.stime * 1_000)],
21
+ ["Total CPU time", "%.2fms" % (@times.total * 1_000)],
22
+ ["Elapsed time", "%.2fms" % (@times.real * 1_000)]
23
+ ]
24
+
25
+ env["rack-bug.panels"] << self
26
+ return [status, headers, body]
27
+ end
28
+
29
+ def heading
30
+ "%.2fms" % (@times.real * 1_000)
31
+ end
32
+
33
+ def content
34
+ render_template "panels/timer", :measurements => @measurements
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,63 @@
1
+ require "digest"
2
+
3
+ module Rack
4
+ class Bug
5
+
6
+ class ParamsSignature
7
+ extend ERB::Util
8
+
9
+ def self.sign(request, hash)
10
+ parts = []
11
+
12
+ hash.keys.sort.each do |key|
13
+ parts << "#{key}=#{u(hash[key])}"
14
+ end
15
+
16
+ signature = new(request).signature(hash)
17
+ parts << "hash=#{u(signature)}"
18
+
19
+ parts.join("&amp;")
20
+ end
21
+
22
+ attr_reader :request
23
+
24
+ def initialize(request)
25
+ @request = request
26
+ end
27
+
28
+ def secret_key
29
+ @request.env['rack-bug.secret_key']
30
+ end
31
+
32
+ def secret_key_blank?
33
+ secret_key.nil? || secret_key == ""
34
+ end
35
+
36
+ def validate!
37
+ if secret_key_blank?
38
+ raise SecurityError.new("Missing secret key")
39
+ elsif request.params["hash"] != signature(request.params)
40
+ raise SecurityError.new("Invalid query hash.")
41
+ end
42
+ end
43
+
44
+ def signature(params)
45
+ Digest::SHA1.hexdigest(signature_base(params))
46
+ end
47
+
48
+ def signature_base(params)
49
+ signature = []
50
+ signature << secret_key
51
+
52
+ params.keys.sort.each do |key|
53
+ next if key == "hash"
54
+ signature << params[key].to_s
55
+ end
56
+
57
+ signature.join(":")
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end