rack-profiler 0.0.5 → 1.0.0

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.
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