module Rack::PerftoolsProfiler class ProfilerArgumentError < RuntimeError; end; class ProfilerMiddleware include Rack::Utils PRINTER_CONTENT_TYPE = { :text => 'text/plain', :gif => 'image/gif', :pdf => 'application/pdf', :callgrind => 'text/plain', :raw => 'application/octet-stream' } PRINTERS = PRINTER_CONTENT_TYPE.keys def initialize(app, options = {}) @app = app @profiler = Profiler.new(@app, options.clone) end def call(env) # I used to clone the env, but it broke any apps that used Warden # ex) @env = env.clone @env = env action = Action.for_env(@env, @profiler, self) action.act action.response rescue ProfilerArgumentError => err @env['rack.errors'].write(err.message) [400, {'Content-Type' => 'text/plain'}, [err.message]] rescue ProfilingError => err @env['rack.errors'].write(err.message + "\n" + err.stderr) [500, {'Content-Type' => 'text/plain'}, [err.message+"\n\n", "Standard error:\n"+err.stderr+"\n"]] end def call_app(env) @app.call(env) end def force_stop @profiler.stop end def profiler_data_response(profiling_data) format, body = profiling_data body = Array(body) if format==:none message = 'No profiling data available. Visit /__stop__ and then visit /__data__' [404, {'Content-Type' => 'text/plain'}, [message]] else [200, headers(format, body), Array(body)] end end private def headers(printer, body) headers = { 'Content-Type' => PRINTER_CONTENT_TYPE[printer], 'Content-Length' => content_length(body) } if printer ==:raw filetype = printer filename='profile_data' headers['Content-Disposition'] = %(attachment; filename="#{filename}.#{filetype}") end headers end def content_length(body) body.inject(0) { |len, part| len + bytesize(part) }.to_s end end end