def call(env)
client_settings = ClientSettings.new(env)
status = headers = body = nil
query_string = env['QUERY_STRING']
path = env['PATH_INFO']
env['RACK_MINI_PROFILER_ORIGINAL_SCRIPT_NAME'] = env['SCRIPT_NAME']
skip_it = (@config.pre_authorize_cb && !@config.pre_authorize_cb.call(env)) ||
(@config.skip_paths && @config.skip_paths.any?{ |p| path.start_with?(p) }) ||
query_string =~ /pp=skip/
has_profiling_cookie = client_settings.has_cookie?
if skip_it || (@config.authorization_mode == :whitelist && !has_profiling_cookie)
status,headers,body = @app.call(env)
if !skip_it && @config.authorization_mode == :whitelist && !has_profiling_cookie && MiniProfiler.request_authorized?
client_settings.write!(headers)
end
return [status,headers,body]
end
return serve_html(env) if path.start_with? @config.base_url_path
has_disable_cookie = client_settings.disable_profiling?
if query_string =~ /pp=disable/ || has_disable_cookie
skip_it = true
end
if query_string =~ /pp=enable/ && (@config.authorization_mode != :whitelist || MiniProfiler.request_authorized?)
skip_it = false
config.enabled = true
end
if skip_it || !config.enabled
status,headers,body = @app.call(env)
client_settings.disable_profiling = true
client_settings.write!(headers)
return [status,headers,body]
else
client_settings.disable_profiling = false
end
if query_string =~ /pp=profile-gc/
current.measure = false if current
return Rack::MiniProfiler::GCProfiler.new.profile_gc(@app, env)
end
if query_string =~ /pp=profile-memory/
query_params = Rack::Utils.parse_nested_query(query_string)
options = {
:ignore_files => query_params['memory_profiler_ignore_files'],
:allow_files => query_params['memory_profiler_allow_files'],
}
options[:top]= Integer(query_params['memory_profiler_top']) if query_params.key?('memory_profiler_top')
result = StringIO.new
report = MemoryProfiler.report(options) do
_,_,body = @app.call(env)
body.close if body.respond_to? :close
end
report.pretty_print(result)
return text_result(result.string)
end
MiniProfiler.create_current(env, @config)
MiniProfiler.deauthorize_request if @config.authorization_mode == :whitelist
if query_string =~ /pp=normal-backtrace/
client_settings.backtrace_level = ClientSettings::BACKTRACE_DEFAULT
elsif query_string =~ /pp=no-backtrace/
current.skip_backtrace = true
client_settings.backtrace_level = ClientSettings::BACKTRACE_NONE
elsif query_string =~ /pp=full-backtrace/ || client_settings.backtrace_full?
current.full_backtrace = true
client_settings.backtrace_level = ClientSettings::BACKTRACE_FULL
elsif client_settings.backtrace_none?
current.skip_backtrace = true
end
flamegraph = nil
trace_exceptions = query_string =~ /pp=trace-exceptions/ && defined? TracePoint
status, headers, body, exceptions,trace = nil
start = Time.now
if trace_exceptions
exceptions = []
trace = TracePoint.new(:raise) do |tp|
exceptions << tp.raised_exception
end
trace.enable
end
begin
if config.disable_caching
env['HTTP_IF_MODIFIED_SINCE'] = ''
env['HTTP_IF_NONE_MATCH'] = ''
end
if query_string =~ /pp=flamegraph/
unless defined?(Flamegraph) && Flamegraph.respond_to?(:generate)
flamegraph = "Please install the flamegraph gem and require it: add gem 'flamegraph' to your Gemfile"
status,headers,body = @app.call(env)
else
current.measure = false
match_data = query_string.match(/flamegraph_sample_rate=([\d\.]+)/)
mode = query_string =~ /mode=c/ ? :c : :ruby
if match_data && !match_data[1].to_f.zero?
sample_rate = match_data[1].to_f
else
sample_rate = config.flamegraph_sample_rate
end
flamegraph = Flamegraph.generate(nil, :fidelity => sample_rate, :embed_resources => query_string =~ /embed/, :mode => mode) do
status,headers,body = @app.call(env)
end
end
else
status,headers,body = @app.call(env)
end
client_settings.write!(headers)
ensure
trace.disable if trace
end
skip_it = current.discard
if (config.authorization_mode == :whitelist && !MiniProfiler.request_authorized?)
if status.to_i >= 200 && status.to_i < 300 && ((Time.now - start) > 0.1)
client_settings.discard_cookie!(headers)
end
skip_it = true
end
return [status,headers,body] if skip_it
if trace_exceptions
body.close if body.respond_to? :close
return dump_exceptions exceptions
end
if query_string =~ /pp=env/ && !config.disable_env_dump
body.close if body.respond_to? :close
return dump_env env
end
if query_string =~ /pp=analyze-memory/
body.close if body.respond_to? :close
return analyze_memory
end
if query_string =~ /pp=help/
body.close if body.respond_to? :close
return help(client_settings, env)
end
page_struct = current.page_struct
page_struct[:user] = user(env)
page_struct[:root].record_time((Time.now - start) * 1000)
if flamegraph
body.close if body.respond_to? :close
return self.flamegraph(flamegraph)
end
begin
@storage.set_unviewed(page_struct[:user], page_struct[:id])
@storage.save(page_struct)
if status >= 200 && status < 300
client_settings.write!(headers)
result = inject_profiler(env,status,headers,body)
return result if result
end
rescue Exception => e
if @config.storage_failure != nil
@config.storage_failure.call(e)
end
end
client_settings.write!(headers)
[status, headers, body]
ensure
self.current = nil
end