rack-profiler 0.0.5 → 1.0.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
  SHA1:
3
- metadata.gz: d84a8f5ef46d358a0da6c75940fdb9c5faf28d2c
4
- data.tar.gz: 80a1d8da3c99c037717710177999f98a90d2e6d6
3
+ metadata.gz: ada3784e0444ea4df49d755fac6dc82e3ae30ee2
4
+ data.tar.gz: 7611769984c985b48d7a49cfb36750a92c000da3
5
5
  SHA512:
6
- metadata.gz: 875f0998cdf03527b766fa2b9d83fa946673683fdd4842e737fa69fe8c82fb5a60fcf8767fccd0b1249f5d9354206189c364b96015fde59f4a25dcc945f73da6
7
- data.tar.gz: 3c71402f03f05b104d2d5a2294ff17e4533e24b9925a75e2bc436ac1704f4be750bc7bdb04b597a581de362ddc36c5044d1870f7d6ca56bddc22bdd0579334e9
6
+ metadata.gz: c3d87464a4fdf2c46f2f236ff9633b042535ffdf5184fe03453d11706e77b2b2b27a9de0dfc76dfcf87308458a5d1e5aa9f11be2fc1e4ef19adf21fe721eda89
7
+ data.tar.gz: 62c9a482614f8be5ddde9917ac96c0f36eb278b5d7e62d479682f574b5c677a90c4f704c4ca5414e4eec802574951f3ccd2d5bfe589fd28fb03016ede66e9b61
data/README.md CHANGED
@@ -55,27 +55,33 @@ require 'rack/profiler'
55
55
  use Rack::Profiler
56
56
  ```
57
57
 
58
+ NOTE: you should not expose the profiler publicly in the production environment,
59
+ as it may contain sensitive information. Refer to the [`authorization
60
+ section`](#authorization) on how to protect it.
61
+
58
62
  ### Rails
59
63
 
60
64
  You can add the `Rack::Profiler` middleware at the beginning of your `config.ru`
61
65
  like in the Rack/Sinatra installation or insert it in the middlewares stack configuration
62
- in the `application.rb`:
66
+ in your `config/environments/<env>.rb` files:
63
67
 
64
68
  ```ruby
65
- module YourApp
66
- class Application < Rails::Application
67
-
68
- # ...
69
-
70
- config.middleware.insert_before Rack::Runtime, Rack::Profiler
69
+ YourApp.configure do |config|
70
+ # ...
71
71
 
72
- end
72
+ config.middleware.insert 0, Rack::Profiler
73
73
  end
74
74
  ```
75
75
 
76
+ NOTE: you should not expose the profiler publicly in the production environment,
77
+ as it may contain sensitive information. Refer to the [`authorization
78
+ section`](#authorization) for on to protect it.
79
+
76
80
  ## Configuration
77
81
 
78
- You can configure `Rack::Profiler` passing a block to `use`. In the block you can subscribe to more notifications and change some defaults:
82
+ You can configure `Rack::Profiler` passing a block to `use` (or
83
+ `middleware.insert` in Rails configuration). In the block you can subscribe to
84
+ more notifications and change some defaults:
79
85
 
80
86
  ```ruby
81
87
  use Rack::Profiler do |profiler|
@@ -88,6 +94,39 @@ use Rack::Profiler do |profiler|
88
94
  end
89
95
  ```
90
96
 
97
+ ## Authorization
98
+
99
+ You typically *do not want to expose profiling publicly*, as it may contain
100
+ sensible information about your data and app. To protect your data, the easiest
101
+ option is to only enable the profiler in the development environment:
102
+
103
+ ```ruby
104
+ if ENV['RACK_ENV'] == 'development'
105
+ require 'rack/profiler'
106
+ use Rack::Profiler
107
+ end
108
+ ```
109
+
110
+ Sometimes though, you might want to run the profiler in the production
111
+ environment, in order to get results in a real setting (including caching and
112
+ optimizations). In this case, you can configure your custom authorization logic,
113
+ which can rely on the Rack env:
114
+
115
+ ```ruby
116
+ use Rack::Profiler do |profiler|
117
+ profiler.authorize do |env|
118
+ # env is the Rack environment of the request. This block should return a
119
+ # truthy value when the request is allowed to be profiled, falsy otherwise.
120
+ env['rack-profiler-enabled'] == true
121
+ end
122
+ end
123
+
124
+ # ...then in your app:
125
+ before do
126
+ env['rack-profiler-enabled'] = true if current_user.admin?
127
+ end
128
+ ```
129
+
91
130
  ## Usage
92
131
 
93
132
  ### Custom steps
data/lib/rack/profiler.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  require "rack"
2
2
  require "rack/request"
3
+ require "rack/auth/basic"
3
4
  require "rack/profiler/version"
4
5
  require "active_support/notifications"
5
6
 
6
7
  module Rack
7
8
  class Profiler
8
9
 
9
- attr_reader :events, :backtrace_filter, :subscriptions
10
+ attr_reader :events, :backtrace_filter, :subscriptions, :authorizator
10
11
  attr_accessor :dashboard_path
11
12
 
12
13
  DEFAULT_SUBSCRIPTIONS = ['sql.active_record',
@@ -36,6 +37,7 @@ module Rack
36
37
  def call(env)
37
38
  @events = []
38
39
  req = Rack::Request.new(env)
40
+ env['rack-profiler'] = self
39
41
 
40
42
  if req.path == dashboard_path
41
43
  render_dashboard
@@ -69,6 +71,10 @@ module Rack
69
71
  @backtrace_filter = block
70
72
  end
71
73
 
74
+ def authorize(&block)
75
+ @authorizator = block
76
+ end
77
+
72
78
  private
73
79
 
74
80
  def render_profiler_results(env)
@@ -76,16 +82,16 @@ module Rack
76
82
  ActiveSupport::Notifications.instrument('rack-profiler.total_time') do
77
83
  status, headers, body = @app.call(env)
78
84
  end
79
- [ 200,
80
- { 'Content-Type' => 'application/json' },
81
- [ { events: events.sort_by { |event| event[:start] },
82
- response: {
83
- status: status,
84
- headers: headers,
85
- body: stringify_body(body)
86
- }
87
- }.to_json ]
88
- ]
85
+ return [status, headers, body] unless authorized?(env)
86
+ results = {
87
+ events: events.sort_by { |event| event[:start] },
88
+ response: {
89
+ status: status,
90
+ headers: headers,
91
+ body: stringify_body(body)
92
+ }
93
+ }
94
+ [200, { 'Content-Type' => 'application/json' }, [results.to_json]]
89
95
  end
90
96
 
91
97
  def render_dashboard
@@ -115,5 +121,9 @@ module Rack
115
121
  body.each { |part| str << part }
116
122
  str
117
123
  end
124
+
125
+ def authorized?(env)
126
+ @authorizator.nil? || @authorizator.call(env)
127
+ end
118
128
  end
119
129
  end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Profiler
3
- VERSION = "0.0.5"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
@@ -89,7 +89,7 @@
89
89
  <option value="POST">POST</option>
90
90
  <option value="PUT">PUT</option>
91
91
  <option value="PATCH">PATCH</option>
92
- <option value="OPTIONS">OPTIONS</option>
92
+ <option value="DELETE">DELETE</option>
93
93
  </select>
94
94
  </div>
95
95
  <div class="col-md-3">
@@ -34,6 +34,7 @@ describe Rack::Profiler do
34
34
  it "sets the correct defaults" do
35
35
  expect(profiler.dashboard_path).to eq('/rack-profiler')
36
36
  expect(profiler.backtrace_filter).to be_nil
37
+ expect(profiler.authorizator).to be_nil
37
38
  expect(profiler.subscriptions).to include(
38
39
  *Rack::Profiler::DEFAULT_SUBSCRIPTIONS
39
40
  )
@@ -118,25 +119,25 @@ describe Rack::Profiler do
118
119
 
119
120
  let(:env) do
120
121
  {
121
- "PATH_INFO" => "/",
122
- "QUERY_STRING" => "",
123
- "REMOTE_HOST" => "localhost",
124
- "REQUEST_METHOD" => "GET",
125
- "REQUEST_URI" => "http://localhost:3000/",
126
- "SCRIPT_NAME" => "",
127
- "SERVER_NAME" => "localhost",
128
- "SERVER_PORT" => "3000",
129
- "SERVER_PROTOCOL" => "HTTP/1.1",
130
- "HTTP_HOST" => "localhost:3000",
131
- "rack.version" => [1, 2],
132
- "rack.input" => StringIO.new,
133
- "rack.errors" => StringIO.new,
134
- "rack.multithread" => true,
122
+ "PATH_INFO" => "/",
123
+ "QUERY_STRING" => "",
124
+ "REMOTE_HOST" => "localhost",
125
+ "REQUEST_METHOD" => "GET",
126
+ "REQUEST_URI" => "http://localhost:3000/",
127
+ "SCRIPT_NAME" => "",
128
+ "SERVER_NAME" => "localhost",
129
+ "SERVER_PORT" => "3000",
130
+ "SERVER_PROTOCOL" => "HTTP/1.1",
131
+ "HTTP_HOST" => "localhost:3000",
132
+ "rack.version" => [1, 2],
133
+ "rack.input" => StringIO.new,
134
+ "rack.errors" => StringIO.new,
135
+ "rack.multithread" => true,
135
136
  "rack.multiprocess" => false,
136
- "rack.run_once" => false,
137
- "rack.url_scheme" => "http",
138
- "HTTP_VERSION" => "HTTP/1.1",
139
- "REQUEST_PATH" => "/"
137
+ "rack.run_once" => false,
138
+ "rack.url_scheme" => "http",
139
+ "HTTP_VERSION" => "HTTP/1.1",
140
+ "REQUEST_PATH" => "/"
140
141
  }
141
142
  end
142
143
 
@@ -146,7 +147,7 @@ describe Rack::Profiler do
146
147
  expect(profiler.events).not_to include('xxx')
147
148
  end
148
149
 
149
- context "when the path is config.dashboard_path" do
150
+ context "when the path is dashboard_path" do
150
151
  it "renders dashboard" do
151
152
  path = ::File.expand_path('../../public/rack-profiler.html',
152
153
  ::File.dirname( __FILE__ ) )
@@ -193,6 +194,27 @@ describe Rack::Profiler do
193
194
  parsed_body['events'].map { |e| e['name'] }
194
195
  ).to include('rack-profiler.total_time', 'rack-profiler.step')
195
196
  end
197
+
198
+ context "when authorization is configured" do
199
+ before do
200
+ profiler.authorize { |env| env['rack-profiler-allowed'] }
201
+ end
202
+
203
+ it "returns the original response if the request is not authorized" do
204
+ response = profiler.call(env_with_param)
205
+ expect(response).to eq(
206
+ [200, { 'X-My-Header' => 'foo' }, ['hello hello']]
207
+ )
208
+ end
209
+
210
+ it "returns the profiler results if the request is authorized" do
211
+ status, headers, body = profiler.call(
212
+ env_with_param.merge('rack-profiler-allowed' => true)
213
+ )
214
+ parsed_body = JSON.parse(body.join)
215
+ expect(parsed_body).to have_key('events')
216
+ end
217
+ end
196
218
  end
197
219
  end
198
220
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Ongaro
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-01-28 00:00:00.000000000 Z
12
+ date: 2015-01-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack