rack-mini-profiler 0.1.6 → 0.1.11.pre

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack-mini-profiler might be problematic. Click here for more details.

@@ -13,6 +13,7 @@ module Rack
13
13
  data = ::File.open(path(key),"rb") {|f| f.read}
14
14
  return Marshal.load data
15
15
  rescue => e
16
+ p e
16
17
  return nil
17
18
  end
18
19
  end
@@ -39,9 +40,14 @@ module Rack
39
40
 
40
41
  me = self
41
42
  Thread.new do
42
- while true do
43
- me.cleanup_cache if MiniProfiler.instance
44
- sleep(3600)
43
+ begin
44
+ while true do
45
+ # TODO: a sane retry count before bailing
46
+ me.cleanup_cache
47
+ sleep(3600)
48
+ end
49
+ rescue
50
+ # don't crash the thread, we can clean up next time
45
51
  end
46
52
  end
47
53
  end
@@ -83,10 +89,6 @@ module Rack
83
89
  }
84
90
  end
85
91
 
86
-
87
- private
88
-
89
-
90
92
  def cleanup_cache
91
93
  files = Dir.entries(@path)
92
94
  @timer_struct_lock.synchronize {
@@ -52,10 +52,6 @@ module Rack
52
52
  }
53
53
  end
54
54
 
55
-
56
- private
57
-
58
-
59
55
  def cleanup_cache
60
56
  expire_older_than = ((Time.now.to_f - MiniProfiler::MemoryStore::EXPIRE_TIMER_CACHE) * 1000).to_i
61
57
  @timer_struct_lock.synchronize {
@@ -22,7 +22,9 @@ module Rack
22
22
  end
23
23
 
24
24
  def to_json(*a)
25
- ::JSON.generate(@attributes, a[0])
25
+ # this does could take in an option hash, but the only interesting there is max_nesting.
26
+ # if this becomes an option we could increase
27
+ ::JSON.generate( @attributes, :max_nesting => 100 )
26
28
  end
27
29
 
28
30
  end
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+
1
3
  module MiniProfilerRails
2
4
 
3
5
  class Railtie < ::Rails::Railtie
@@ -22,7 +24,7 @@ module MiniProfilerRails
22
24
 
23
25
  # The file store is just so much less flaky
24
26
  tmp = Rails.root.to_s + "/tmp/miniprofiler"
25
- Dir::mkdir(tmp) unless File.exists?(tmp)
27
+ FileUtils.mkdir_p(tmp) unless File.exists?(tmp)
26
28
 
27
29
  c.storage_options = {:path => tmp}
28
30
  c.storage = Rack::MiniProfiler::FileStore
@@ -13,6 +13,12 @@ class SqlPatches
13
13
  rescue NameError
14
14
  false
15
15
  end
16
+
17
+ def self.module_exists?(name)
18
+ eval(name + ".class").to_s.eql?('Module')
19
+ rescue NameError
20
+ false
21
+ end
16
22
  end
17
23
 
18
24
  # The best kind of instrumentation is in the actual db provider, however we don't want to double instrument
@@ -85,6 +91,23 @@ if SqlPatches.class_exists? "PG::Result"
85
91
  class PG::Connection
86
92
  alias_method :exec_without_profiling, :exec
87
93
  alias_method :async_exec_without_profiling, :async_exec
94
+ alias_method :exec_prepared_without_profiling, :exec_prepared
95
+ alias_method :send_query_prepared_without_profiling, :send_query_prepared
96
+ alias_method :prepare_without_profiling, :prepare
97
+
98
+ def prepare(*args,&blk)
99
+ current = ::Rack::MiniProfiler.current
100
+ return prepare_without_profiling(*args,&blk) unless current
101
+
102
+ @prepare_map ||= {}
103
+ @prepare_map[args[0]] = args[1]
104
+
105
+ # dont leak more than 10k ever
106
+ @prepare_map = {} if @prepare_map.length > 10000
107
+
108
+ prepare_without_profiling(*args,&blk)
109
+
110
+ end
88
111
 
89
112
  def exec(*args,&blk)
90
113
  current = ::Rack::MiniProfiler.current
@@ -98,6 +121,34 @@ if SqlPatches.class_exists? "PG::Result"
98
121
  result
99
122
  end
100
123
 
124
+ def exec_prepared(*args,&blk)
125
+ current = ::Rack::MiniProfiler.current
126
+ return exec_prepared_without_profiling(*args,&blk) unless current
127
+
128
+ start = Time.now
129
+ result = exec_prepared_without_profiling(*args,&blk)
130
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
131
+ mapped = args[0]
132
+ mapped = @prepare_map[mapped] || args[0] if @prepare_map
133
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(mapped, elapsed_time))
134
+
135
+ result
136
+ end
137
+
138
+ def send_query_prepared(*args,&blk)
139
+ current = ::Rack::MiniProfiler.current
140
+ return send_query_prepared_without_profiling(*args,&blk) unless current
141
+
142
+ start = Time.now
143
+ result = send_query_prepared_without_profiling(*args,&blk)
144
+ elapsed_time = ((Time.now - start).to_f * 1000).round(1)
145
+ mapped = args[0]
146
+ mapped = @prepare_map[mapped] || args[0] if @prepare_map
147
+ result.instance_variable_set("@miniprofiler_sql_id", ::Rack::MiniProfiler.record_sql(mapped, elapsed_time))
148
+
149
+ result
150
+ end
151
+
101
152
  def async_exec(*args,&blk)
102
153
  current = ::Rack::MiniProfiler.current
103
154
  return exec_without_profiling(*args,&blk) unless current
@@ -134,45 +185,46 @@ end
134
185
 
135
186
  ## based off https://github.com/newrelic/rpm/blob/master/lib/new_relic/agent/instrumentation/active_record.rb
136
187
  ## fallback for alls sorts of weird dbs
137
- module Rack
138
- class MiniProfiler
139
- module ActiveRecordInstrumentation
140
- def self.included(instrumented_class)
141
- instrumented_class.class_eval do
142
- unless instrumented_class.method_defined?(:log_without_miniprofiler)
143
- alias_method :log_without_miniprofiler, :log
144
- alias_method :log, :log_with_miniprofiler
145
- protected :log
188
+ if SqlPatches.module_exists?('ActiveRecord')
189
+ module Rack
190
+ class MiniProfiler
191
+ module ActiveRecordInstrumentation
192
+ def self.included(instrumented_class)
193
+ instrumented_class.class_eval do
194
+ unless instrumented_class.method_defined?(:log_without_miniprofiler)
195
+ alias_method :log_without_miniprofiler, :log
196
+ alias_method :log, :log_with_miniprofiler
197
+ protected :log
198
+ end
146
199
  end
147
200
  end
148
- end
149
201
 
150
- def log_with_miniprofiler(*args, &block)
151
- current = ::Rack::MiniProfiler.current
152
- return log_without_miniprofiler(*args, &block) unless current
202
+ def log_with_miniprofiler(*args, &block)
203
+ current = ::Rack::MiniProfiler.current
204
+ return log_without_miniprofiler(*args, &block) unless current
153
205
 
154
- sql, name, binds = args
155
- t0 = Time.now
156
- rval = log_without_miniprofiler(*args, &block)
157
-
158
- # Don't log schema queries if the option is set
159
- return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
206
+ sql, name, binds = args
207
+ t0 = Time.now
208
+ rval = log_without_miniprofiler(*args, &block)
209
+
210
+ # Don't log schema queries if the option is set
211
+ return rval if Rack::MiniProfiler.config.skip_schema_queries and name =~ /SCHEMA/
160
212
 
161
- elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
162
- Rack::MiniProfiler.record_sql(sql, elapsed_time)
163
- rval
213
+ elapsed_time = ((Time.now - t0).to_f * 1000).round(1)
214
+ Rack::MiniProfiler.record_sql(sql, elapsed_time)
215
+ rval
216
+ end
164
217
  end
165
218
  end
166
- end
167
219
 
168
- def self.insert_instrumentation
169
- ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
170
- include ::Rack::MiniProfiler::ActiveRecordInstrumentation
220
+ def self.insert_instrumentation
221
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
222
+ include ::Rack::MiniProfiler::ActiveRecordInstrumentation
223
+ end
171
224
  end
172
- end
173
225
 
174
- if defined?(::Rails) && !SqlPatches.patched?
175
- insert_instrumentation
226
+ if defined?(::Rails) && !SqlPatches.patched?
227
+ insert_instrumentation
228
+ end
176
229
  end
177
230
  end
178
-
@@ -1,6 +1,6 @@
1
- require File.expand_path('mini_profiler/profiler', File.dirname(__FILE__) )
2
- require File.expand_path('patches/sql_patches', File.dirname(__FILE__) )
1
+ require 'mini_profiler/profiler'
2
+ require 'patches/sql_patches'
3
3
 
4
4
  if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 3
5
- require File.expand_path('mini_profiler_rails/railtie', File.dirname(__FILE__) )
5
+ require 'mini_profiler_rails/railtie'
6
6
  end
@@ -1,9 +1,8 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rack-mini-profiler"
3
- s.version = "0.1.6"
3
+ s.version = "0.1.11.pre"
4
4
  s.summary = "Profiles loading speed for rack applications."
5
5
  s.authors = ["Aleks Totic","Sam Saffron", "Robin Ward"]
6
- s.date = "2012-04-02"
7
6
  s.description = "Page loading speed displayed on every page. Optimize while you develop, performance is a feature."
8
7
  s.email = "sam.saffron@gmail.com"
9
8
  s.homepage = "http://miniprofiler.com"
@@ -14,9 +13,9 @@ Gem::Specification.new do |s|
14
13
  "README.md",
15
14
  "CHANGELOG"
16
15
  ]
17
- s.add_runtime_dependency 'rack', '>= 1.1.3'
16
+ s.add_runtime_dependency 'rack', '>= 1.1.3'
18
17
  if RUBY_VERSION < "1.9"
19
- s.add_runtime_dependency 'json', '>= 1.6'
18
+ s.add_runtime_dependency 'json', '>= 1.6'
20
19
  end
21
20
 
22
21
  s.add_development_dependency 'rake'
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-mini-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
5
- prerelease:
4
+ version: 0.1.11.pre
5
+ prerelease: 7
6
6
  platform: ruby
7
7
  authors:
8
8
  - Aleks Totic
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-04-02 00:00:00.000000000 Z
14
+ date: 2012-08-10 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rack
@@ -93,7 +93,6 @@ files:
93
93
  - lib/mini_profiler/page_timer_struct.rb
94
94
  - lib/mini_profiler/context.rb
95
95
  - lib/mini_profiler/config.rb
96
- - lib/mini_profiler/body_add_proxy.rb
97
96
  - lib/mini_profiler/profiling_methods.rb
98
97
  - lib/mini_profiler/client_timer_struct.rb
99
98
  - lib/mini_profiler/profiler.rb
@@ -107,7 +106,6 @@ files:
107
106
  - lib/html/share.html
108
107
  - lib/html/includes.less
109
108
  - lib/html/list.css
110
- - lib/html/MiniProfilerHandler.cs
111
109
  - lib/html/includes.js
112
110
  - lib/html/jquery.tmpl.js
113
111
  - lib/html/list.tmpl
@@ -132,16 +130,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
130
  version: '0'
133
131
  segments:
134
132
  - 0
135
- hash: -974819475
133
+ hash: -126757873
136
134
  required_rubygems_version: !ruby/object:Gem::Requirement
137
135
  none: false
138
136
  requirements:
139
- - - ! '>='
137
+ - - ! '>'
140
138
  - !ruby/object:Gem::Version
141
- version: '0'
142
- segments:
143
- - 0
144
- hash: -974819475
139
+ version: 1.3.1
145
140
  requirements: []
146
141
  rubyforge_project:
147
142
  rubygems_version: 1.8.24
@@ -1,419 +0,0 @@
1
- using System;
2
- using System.Collections.Generic;
3
- using System.IO;
4
- using System.Web;
5
- using System.Web.Routing;
6
- using System.Linq;
7
-
8
- using StackExchange.Profiling.Helpers;
9
- using System.Text;
10
- using System.Collections.Concurrent;
11
-
12
- namespace StackExchange.Profiling.UI
13
- {
14
- /// <summary>
15
- /// Understands how to route and respond to MiniProfiler UI urls.
16
- /// </summary>
17
- public class MiniProfilerHandler : IRouteHandler, IHttpHandler
18
- {
19
- internal static HtmlString RenderIncludes(MiniProfiler profiler, RenderPosition? position = null, bool? showTrivial = null, bool? showTimeWithChildren = null, int? maxTracesToShow = null, bool? showControls = null, bool? useExistingjQuery = null)
20
- {
21
- string format = GetResource("include.partial.html");
22
-
23
- var result = "";
24
-
25
- if (profiler != null)
26
- {
27
- // HACK: unviewed ids are added to this list during Storage.Save, but we know we haven't see the current one yet,
28
- // so go ahead and add it to the end - it's usually the only id, but if there was a redirect somewhere, it'll be there, too
29
- MiniProfiler.Settings.EnsureStorageStrategy();
30
-
31
- var authorized =
32
- MiniProfiler.Settings.Results_Authorize == null ||
33
- MiniProfiler.Settings.Results_Authorize(HttpContext.Current.Request);
34
-
35
- List<Guid> ids;
36
- if (authorized)
37
- {
38
- ids = MiniProfiler.Settings.Storage.GetUnviewedIds(profiler.User);
39
- ids.Add(profiler.Id);
40
- }
41
- else
42
- {
43
- ids = new List<Guid> { profiler.Id };
44
- }
45
-
46
- result = format.Format(new
47
- {
48
- path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash(),
49
- version = MiniProfiler.Settings.Version,
50
- ids = ids.ToJson(),
51
- position = (position ?? MiniProfiler.Settings.PopupRenderPosition).ToString().ToLower(),
52
- showTrivial = showTrivial ?? MiniProfiler.Settings.PopupShowTrivial ? "true" : "false",
53
- showChildren = showTimeWithChildren ?? MiniProfiler.Settings.PopupShowTimeWithChildren ? "true" : "false",
54
- maxTracesToShow = maxTracesToShow ?? MiniProfiler.Settings.PopupMaxTracesToShow,
55
- showControls = showControls ?? MiniProfiler.Settings.ShowControls ? "true" : "false",
56
- currentId = profiler.Id,
57
- authorized = authorized ? "true" : "false",
58
- useExistingjQuery = useExistingjQuery ?? MiniProfiler.Settings.UseExistingjQuery ? "true" : "false"
59
- });
60
-
61
- }
62
-
63
- return new HtmlString(result);
64
- }
65
-
66
- /// <summary>
67
- /// Usually called internally, sometimes you may clear the routes during the apps lifecycle, if you do that call this to bring back mp
68
- /// </summary>
69
- public static void RegisterRoutes()
70
- {
71
-
72
- var routes = RouteTable.Routes;
73
- var handler = new MiniProfilerHandler();
74
- var prefix = MiniProfiler.Settings.RouteBasePath.Replace("~/", "").EnsureTrailingSlash();
75
-
76
- using (routes.GetWriteLock())
77
- {
78
- var route = new Route(prefix + "{filename}", handler)
79
- {
80
- // we have to specify these, so no MVC route helpers will match, e.g. @Html.ActionLink("Home", "Index", "Home")
81
- Defaults = new RouteValueDictionary( new { controller = "MiniProfilerHandler", action = "ProcessRequest" }),
82
- Constraints = new RouteValueDictionary( new { controller = "MiniProfilerHandler", action = "ProcessRequest" })
83
- };
84
-
85
- // put our routes at the beginning, like a boss
86
- routes.Insert(0, route);
87
- }
88
- }
89
-
90
- /// <summary>
91
- /// Returns this <see cref="MiniProfilerHandler"/> to handle <paramref name="requestContext"/>.
92
- /// </summary>
93
- public IHttpHandler GetHttpHandler(RequestContext requestContext)
94
- {
95
- return this; // elegant? I THINK SO.
96
- }
97
-
98
- /// <summary>
99
- /// Try to keep everything static so we can easily be reused.
100
- /// </summary>
101
- public bool IsReusable
102
- {
103
- get { return true; }
104
- }
105
-
106
- /// <summary>
107
- /// Returns either includes' css/javascript or results' html.
108
- /// </summary>
109
- public void ProcessRequest(HttpContext context)
110
- {
111
- string output;
112
- string path = context.Request.AppRelativeCurrentExecutionFilePath;
113
-
114
- switch (Path.GetFileNameWithoutExtension(path).ToLowerInvariant())
115
- {
116
- case "jquery.1.7.1":
117
- case "jquery.tmpl":
118
- case "includes":
119
- case "list":
120
- output = Includes(context, path);
121
- break;
122
-
123
- case "results-index":
124
- output = Index(context);
125
- break;
126
-
127
- case "results-list":
128
- output = ResultList(context);
129
- break;
130
-
131
- case "results":
132
- output = Results(context);
133
- break;
134
-
135
- default:
136
- output = NotFound(context);
137
- break;
138
- }
139
-
140
- context.Response.Write(output);
141
- }
142
-
143
- private static string ResultList(HttpContext context)
144
- {
145
- string message;
146
- if (!AuthorizeRequest(context, isList: true, message: out message))
147
- {
148
- return message;
149
- }
150
-
151
- var lastId = context.Request["last-id"];
152
- Guid lastGuid = Guid.Empty;
153
-
154
- if (!lastId.IsNullOrWhiteSpace()) {
155
- Guid.TryParse(lastId, out lastGuid);
156
- }
157
-
158
- var guids = MiniProfiler.Settings.Storage.List(100);
159
-
160
- if (lastGuid != Guid.Empty)
161
- {
162
- guids = guids.TakeWhile(g => g != lastGuid);
163
- }
164
-
165
- guids = guids.Reverse();
166
-
167
- return guids.Select(g =>
168
- {
169
- var profiler = MiniProfiler.Settings.Storage.Load(g);
170
- return new
171
- {
172
- profiler.Id,
173
- profiler.Name,
174
- profiler.DurationMilliseconds,
175
- profiler.DurationMillisecondsInSql,
176
- profiler.ClientTimings,
177
- profiler.Started,
178
- profiler.ExecutedNonQueries,
179
- profiler.ExecutedReaders,
180
- profiler.ExecutedScalars,
181
- profiler.HasAllTrivialTimings,
182
- profiler.HasDuplicateSqlTimings,
183
- profiler.HasSqlTimings,
184
- profiler.HasTrivialTimings,
185
- profiler.HasUserViewed,
186
- profiler.MachineName,
187
- profiler.User
188
- };
189
- }
190
-
191
- ).ToJson();
192
- }
193
-
194
- private static string Index(HttpContext context)
195
- {
196
- string message;
197
- if (!AuthorizeRequest(context, isList: true, message: out message))
198
- {
199
- return message;
200
- }
201
-
202
- context.Response.ContentType = "text/html";
203
-
204
- var path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash();
205
-
206
- return new StringBuilder()
207
- .AppendLine("<html><head>")
208
- .AppendFormat("<title>List of profiling sessions</title>")
209
- .AppendLine()
210
- .AppendLine("<script type='text/javascript' src='" + path + "jquery.1.7.1.js?v=" + MiniProfiler.Settings.Version + "'></script>")
211
- .AppendLine("<script type='text/javascript' src='" + path + "jquery.tmpl.js?v=" + MiniProfiler.Settings.Version + "'></script>")
212
- .AppendLine("<script type='text/javascript' src='" + path + "includes.js?v=" + MiniProfiler.Settings.Version + "'></script>")
213
- .AppendLine("<script type='text/javascript' src='" + path + "list.js?v=" + MiniProfiler.Settings.Version + "'></script>")
214
- .AppendLine("<link href='" + path +"list.css?v=" + MiniProfiler.Settings.Version + "' rel='stylesheet' type='text/css'>")
215
- .AppendLine("<script type='text/javascript'>MiniProfiler.list.init({path: '" + path + "', version: '" + MiniProfiler.Settings.Version + "'})</script>")
216
- .AppendLine("</head><body></body></html>")
217
- .ToString();
218
- }
219
-
220
- /// <summary>
221
- /// Handles rendering static content files.
222
- /// </summary>
223
- private static string Includes(HttpContext context, string path)
224
- {
225
- var response = context.Response;
226
-
227
- switch (Path.GetExtension(path))
228
- {
229
- case ".js":
230
- response.ContentType = "application/javascript";
231
- break;
232
- case ".css":
233
- response.ContentType = "text/css";
234
- break;
235
- case ".tmpl":
236
- response.ContentType = "text/x-jquery-tmpl";
237
- break;
238
- default:
239
- return NotFound(context);
240
- }
241
-
242
- #if !DEBUG
243
- var cache = response.Cache;
244
- cache.SetCacheability(System.Web.HttpCacheability.Public);
245
- cache.SetExpires(DateTime.Now.AddDays(7));
246
- cache.SetValidUntilExpires(true);
247
- #endif
248
-
249
-
250
- var embeddedFile = Path.GetFileName(path);
251
- return GetResource(embeddedFile);
252
- }
253
-
254
- /// <summary>
255
- /// Handles rendering a previous MiniProfiler session, identified by its "?id=GUID" on the query.
256
- /// </summary>
257
- private static string Results(HttpContext context)
258
- {
259
- // when we're rendering as a button/popup in the corner, we'll pass ?popup=1
260
- // if it's absent, we're rendering results as a full page for sharing
261
- var isPopup = !string.IsNullOrWhiteSpace(context.Request["popup"]);
262
-
263
- // this guid is the MiniProfiler.Id property
264
- Guid id;
265
- if (!Guid.TryParse(context.Request["id"], out id))
266
- return isPopup ? NotFound(context) : NotFound(context, "text/plain", "No Guid id specified on the query string");
267
-
268
- MiniProfiler.Settings.EnsureStorageStrategy();
269
- var profiler = MiniProfiler.Settings.Storage.Load(id);
270
-
271
- var provider = WebRequestProfilerProvider.Settings.UserProvider;
272
- string user = null;
273
- if (provider != null)
274
- {
275
- user = provider.GetUser(context.Request);
276
- }
277
-
278
- MiniProfiler.Settings.Storage.SetViewed(user, id);
279
-
280
- if (profiler == null)
281
- {
282
- return isPopup ? NotFound(context) : NotFound(context, "text/plain", "No MiniProfiler results found with Id=" + id.ToString());
283
- }
284
-
285
- bool needsSave = false;
286
- if (profiler.ClientTimings == null)
287
- {
288
- profiler.ClientTimings = ClientTimings.FromRequest(context.Request);
289
- if (profiler.ClientTimings != null)
290
- {
291
- needsSave = true;
292
- }
293
- }
294
-
295
- if (profiler.HasUserViewed == false)
296
- {
297
- profiler.HasUserViewed = true;
298
- needsSave = true;
299
- }
300
-
301
- if (needsSave) MiniProfiler.Settings.Storage.Save(profiler);
302
-
303
-
304
- var authorize = MiniProfiler.Settings.Results_Authorize;
305
-
306
-
307
- if (authorize != null && !authorize(context.Request))
308
- {
309
- context.Response.ContentType = "application/json";
310
- return "hidden".ToJson();
311
- }
312
-
313
- return isPopup ? ResultsJson(context, profiler) : ResultsFullPage(context, profiler);
314
- }
315
-
316
- private static bool AuthorizeRequest(HttpContext context, bool isList, out string message)
317
- {
318
- message = null;
319
- var authorize = MiniProfiler.Settings.Results_Authorize;
320
- var authorizeList = MiniProfiler.Settings.Results_List_Authorize;
321
-
322
- if (authorize != null && !authorize(context.Request) || (isList && (authorizeList == null || !authorizeList(context.Request))))
323
- {
324
- context.Response.StatusCode = 401;
325
- context.Response.ContentType = "text/plain";
326
- message = "unauthorized";
327
- return false;
328
- }
329
- return true;
330
- }
331
-
332
- private static string ResultsJson(HttpContext context, MiniProfiler profiler)
333
- {
334
- context.Response.ContentType = "application/json";
335
- return MiniProfiler.ToJson(profiler);
336
- }
337
-
338
- private static string ResultsFullPage(HttpContext context, MiniProfiler profiler)
339
- {
340
- context.Response.ContentType = "text/html";
341
-
342
- var template = GetResource("share.html");
343
- return template.Format(new
344
- {
345
- name = profiler.Name,
346
- duration = profiler.DurationMilliseconds.ToString(),
347
- path = VirtualPathUtility.ToAbsolute(MiniProfiler.Settings.RouteBasePath).EnsureTrailingSlash(),
348
- json = MiniProfiler.ToJson(profiler),
349
- includes = RenderIncludes(profiler),
350
- version = MiniProfiler.Settings.Version
351
- });
352
- }
353
-
354
- private static bool bypassLocalLoad = false;
355
- private static string GetResource(string filename)
356
- {
357
- filename = filename.ToLower();
358
- string result;
359
-
360
- #if DEBUG
361
- // attempt to simply load from file system, this lets up modify js without needing to recompile A MILLION TIMES
362
- if (!bypassLocalLoad)
363
- {
364
-
365
- var trace = new System.Diagnostics.StackTrace(true);
366
- var path = System.IO.Path.GetDirectoryName(trace.GetFrames()[0].GetFileName()) + "\\..\\UI\\" + filename;
367
- try
368
- {
369
- return File.ReadAllText(path);
370
- }
371
- catch
372
- {
373
- bypassLocalLoad = true;
374
- }
375
- }
376
-
377
- #endif
378
-
379
- if (!_ResourceCache.TryGetValue(filename, out result))
380
- {
381
- string customTemplatesPath = HttpContext.Current.Server.MapPath(MiniProfiler.Settings.CustomUITemplates);
382
- string customTemplateFile = System.IO.Path.Combine(customTemplatesPath, filename);
383
-
384
- if (System.IO.File.Exists(customTemplateFile))
385
- {
386
- result = File.ReadAllText(customTemplateFile);
387
- }
388
- else
389
- {
390
- using (var stream = typeof(MiniProfilerHandler).Assembly.GetManifestResourceStream("StackExchange.Profiling.UI." + filename))
391
- using (var reader = new StreamReader(stream))
392
- {
393
- result = reader.ReadToEnd();
394
- }
395
- }
396
- _ResourceCache[filename] = result;
397
- }
398
-
399
- return result;
400
- }
401
-
402
- /// <summary>
403
- /// Embedded resource contents keyed by filename.
404
- /// </summary>
405
- private static readonly ConcurrentDictionary<string, string> _ResourceCache = new ConcurrentDictionary<string, string>();
406
-
407
- /// <summary>
408
- /// Helper method that sets a proper 404 response code.
409
- /// </summary>
410
- private static string NotFound(HttpContext context, string contentType = "text/plain", string message = null)
411
- {
412
- context.Response.StatusCode = 404;
413
- context.Response.ContentType = contentType;
414
-
415
- return message;
416
- }
417
-
418
- }
419
- }