← Index
NYTProf Performance Profile   « line view »
For nd2: #2 manager: init
  Run on Thu May 2 17:38:58 2019
Reported on Thu May 2 17:40:49 2019

Filename/appl/netdisco/perl5/lib/perl5/Dancer.pm
StatementsExecuted 842 statements in 2.48ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
467531.80ms3.92msDancer::::settingDancer::setting
34221700µs1.06msDancer::::configDancer::config
3311192µs192µsDancer::::debugDancer::debug
0000s0sDancer::::BEGINDancer::BEGIN
0000s0sDancer::::__ANON__[:466]Dancer::__ANON__[:466]
0000s0sDancer::::__ANON__[:467]Dancer::__ANON__[:467]
0000s0sDancer::::_init_script_dirDancer::_init_script_dir
0000s0sDancer::::_load_appDancer::_load_app
0000s0sDancer::::_redirectDancer::_redirect
0000s0sDancer::::_send_fileDancer::_send_file
0000s0sDancer::::_sessionDancer::_session
0000s0sDancer::::_startDancer::_start
0000s0sDancer::::afterDancer::after
0000s0sDancer::::anyDancer::any
0000s0sDancer::::beforeDancer::before
0000s0sDancer::::before_templateDancer::before_template
0000s0sDancer::::capturesDancer::captures
0000s0sDancer::::content_typeDancer::content_type
0000s0sDancer::::cookieDancer::cookie
0000s0sDancer::::cookiesDancer::cookies
0000s0sDancer::::danceDancer::dance
0000s0sDancer::::dancer_versionDancer::dancer_version
0000s0sDancer::::delDancer::del
0000s0sDancer::::dirnameDancer::dirname
0000s0sDancer::::engineDancer::engine
0000s0sDancer::::errorDancer::error
0000s0sDancer::::falseDancer::false
0000s0sDancer::::forwardDancer::forward
0000s0sDancer::::from_dumperDancer::from_dumper
0000s0sDancer::::from_jsonDancer::from_json
0000s0sDancer::::from_xmlDancer::from_xml
0000s0sDancer::::from_yamlDancer::from_yaml
0000s0sDancer::::getDancer::get
0000s0sDancer::::haltDancer::halt
0000s0sDancer::::headerDancer::header
0000s0sDancer::::headersDancer::headers
0000s0sDancer::::hookDancer::hook
0000s0sDancer::::importDancer::import
0000s0sDancer::::infoDancer::info
0000s0sDancer::::layoutDancer::layout
0000s0sDancer::::loadDancer::load
0000s0sDancer::::load_appDancer::load_app
0000s0sDancer::::loggerDancer::logger
0000s0sDancer::::mimeDancer::mime
0000s0sDancer::::optionsDancer::options
0000s0sDancer::::paramDancer::param
0000s0sDancer::::param_arrayDancer::param_array
0000s0sDancer::::paramsDancer::params
0000s0sDancer::::passDancer::pass
0000s0sDancer::::patchDancer::patch
0000s0sDancer::::pathDancer::path
0000s0sDancer::::postDancer::post
0000s0sDancer::::prefixDancer::prefix
0000s0sDancer::::push_headerDancer::push_header
0000s0sDancer::::putDancer::put
0000s0sDancer::::redirectDancer::redirect
0000s0sDancer::::render_with_layoutDancer::render_with_layout
0000s0sDancer::::requestDancer::request
0000s0sDancer::::send_errorDancer::send_error
0000s0sDancer::::send_fileDancer::send_file
0000s0sDancer::::sessionDancer::session
0000s0sDancer::::setDancer::set
0000s0sDancer::::set_cookieDancer::set_cookie
0000s0sDancer::::splatDancer::splat
0000s0sDancer::::startDancer::start
0000s0sDancer::::statusDancer::status
0000s0sDancer::::templateDancer::template
0000s0sDancer::::to_dumperDancer::to_dumper
0000s0sDancer::::to_jsonDancer::to_json
0000s0sDancer::::to_xmlDancer::to_xml
0000s0sDancer::::to_yamlDancer::to_yaml
0000s0sDancer::::trueDancer::true
0000s0sDancer::::uploadDancer::upload
0000s0sDancer::::uri_forDancer::uri_for
0000s0sDancer::::varDancer::var
0000s0sDancer::::varsDancer::vars
0000s0sDancer::::warningDancer::warning
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package Dancer;
2our $AUTHORITY = 'cpan:SUKRIA';
3#ABSTRACT: lightweight yet powerful web application framework
4$Dancer::VERSION = '1.3512';
5use strict;
6use warnings;
7use Carp;
8use Cwd 'realpath';
9
10use Dancer::App;
11use Dancer::Config;
12use Dancer::Cookies;
13use Dancer::FileUtils;
14use Dancer::GetOpt;
15use Dancer::Error;
16use Dancer::Hook;
17use Dancer::Logger;
18use Dancer::Renderer;
19use Dancer::Route;
20use Dancer::Serializer::JSON;
21use Dancer::Serializer::YAML;
22use Dancer::Serializer::XML;
23use Dancer::Serializer::Dumper;
24use Dancer::Session;
25use Dancer::SharedData;
26use Dancer::Handler;
27use Dancer::MIME;
28use Dancer::Exception qw(:all);
29
30use Dancer::Continuation::Halted;
31use Dancer::Continuation::Route::Forwarded;
32use Dancer::Continuation::Route::Passed;
33use Dancer::Continuation::Route::ErrorSent;
34use Dancer::Continuation::Route::FileSent;
35use Dancer::Continuation::Route::Templated;
36
37use File::Spec;
38use Scalar::Util;
39
40use base 'Exporter';
41
42our @EXPORT = qw(
43 after
44 any
45 before
46 before_template
47 cookie
48 cookies
49 config
50 content_type
51 dance
52 dancer_version
53 debug
54 del
55 dirname
56 info
57 error
58 engine
59 false
60 forward
61 from_dumper
62 from_json
63 from_yaml
64 from_xml
65 get
66 halt
67 header
68 headers
69 hook
70 layout
71 load
72 load_app
73 logger
74 mime
75 options
76 param
77 param_array
78 params
79 pass
80 path
81 patch
82 post
83 prefix
84 push_header
85 put
86 redirect
87 render_with_layout
88 request
89 send_file
90 send_error
91 set
92 setting
93 set_cookie
94 session
95 splat
96 status
97 start
98 template
99 to_dumper
100 to_json
101 to_yaml
102 to_xml
103 true
104 upload
105 captures
106 uri_for
107 var
108 vars
109 warning
110);
111
112# Dancer's syntax
113
114sub after {
115 Dancer::Deprecation->deprecated(reason => "use hooks!",
116 version => '1.3080',
117 fatal => 0);
118 Dancer::Hook->new('after', @_);
119}
120sub before {
121 Dancer::Deprecation->deprecated(reason => "use hooks!",
122 version => '1.3080',
123 fatal => 0);
124 Dancer::Hook->new('before', @_);
125}
126sub before_template {
127 Dancer::Deprecation->deprecated(reason => "use hooks!",
128 version => '1.3080',
129 fatal => 0);
130 Dancer::Hook->new('before_template', @_);
131}
132
133sub any { Dancer::App->current->registry->any_add(@_) }
134sub captures { Dancer::SharedData->request->params->{captures} }
135sub cookie { Dancer::Cookies->cookie( @_ ) }
136sub cookies { Dancer::Cookies->cookies }
137342758µs342362µs
# spent 1.06ms (700µs+362µs) within Dancer::config which was called 342 times, avg 3µs/call: # 171 times (431µs+247µs) by App::Netdisco::Util::Permission::check_acl_no at line 46 of App/Netdisco/Util/Permission.pm, avg 4µs/call # 171 times (269µs+115µs) by App::Netdisco::Util::Permission::check_acl_only at line 69 of App/Netdisco/Util/Permission.pm, avg 2µs/call
sub config { Dancer::Config::settings() }
# spent 362µs making 342 calls to Dancer::Config::settings, avg 1µs/call
138sub content_type { Dancer::SharedData->response->content_type(@_) }
139sub dance { goto &start }
140sub dancer_version { Dancer->VERSION }
14133177µs3310.1ms
# spent 192µs within Dancer::debug which was called 33 times, avg 6µs/call: # 33 times (192µs+0s) by App::Netdisco::Util::Device::_bail_msg at line 147 of App/Netdisco/Util/Device.pm, avg 6µs/call
sub debug { goto &Dancer::Logger::debug }
# spent 10.1ms making 33 calls to Dancer::Logger::debug, avg 307µs/call
142sub del { Dancer::App->current->registry->universal_add('delete', @_) }
143sub dirname { Dancer::FileUtils::dirname(@_) }
144sub engine { Dancer::Engine->engine(@_) }
145sub error { goto &Dancer::Logger::error }
146sub false { 0 }
147sub forward { Dancer::SharedData->response->forward(@_);
148 # throw a special continuation exception
149 Dancer::Continuation::Route::Forwarded->new->throw;
150 }
151sub from_dumper { Dancer::Serializer::Dumper::from_dumper(@_) }
152sub from_json { Dancer::Serializer::JSON::from_json(@_) }
153sub from_xml { Dancer::Serializer::XML::from_xml(@_) }
154sub from_yaml { Dancer::Serializer::YAML::from_yaml(@_) }
155sub get { map { my $r = $_; Dancer::App->current->registry->universal_add($r, @_) } qw(head get) }
156sub halt { Dancer::SharedData->response->halt(@_);
157 # throw a special continuation exception
158 Dancer::Continuation::Halted->new->throw;
159 }
160sub header { goto &headers }
161sub info { goto &Dancer::Logger::info }
162sub push_header { Dancer::SharedData->response->push_header(@_); }
163sub headers { Dancer::SharedData->response->headers(@_); }
164sub hook { Dancer::Hook->new(@_) }
165sub layout {
166 Dancer::Deprecation->deprecated(reason => "use 'set layout => \"value\"'",
167 version => '1.3050',
168 fatal => 1);
169}
170sub load { require $_ for @_ }
171sub load_app { goto &_load_app } # goto doesn't add a call frame. So caller() will work as expected
172sub logger {
173 Dancer::Deprecation->deprecated(reason => "use 'set logger => \"value\"'",
174 fatal => 1,version=>'1.3050');
175}
176sub mime { Dancer::MIME->instance() }
177sub options { Dancer::App->current->registry->universal_add('options', @_) }
178sub params { Dancer::SharedData->request->params(@_) }
179sub param { params->{$_[0]} }
180sub param_array {
181 my $value = param(shift);
182
183 my @array = ref $value eq 'ARRAY' ? @$value
184 : defined $value ? ( $value )
185 : ()
186 ;
187
188 return @array;
189}
190sub pass { Dancer::SharedData->response->pass(1);
191 # throw a special continuation exception
192 Dancer::Continuation::Route::Passed->new->throw;
193 }
194sub patch { Dancer::App->current->registry->universal_add('patch', @_) }
195sub path { Dancer::FileUtils::path(@_) }
196sub post { Dancer::App->current->registry->universal_add('post', @_) }
197sub prefix { @_ == 0 ? Dancer::App->current->get_prefix :
198 Dancer::App->current->set_prefix(@_) }
199sub put { Dancer::App->current->registry->universal_add('put', @_) }
200sub redirect { goto &_redirect }
201sub render_with_layout { Dancer::Template::Abstract->_render_with_layout(@_) }
202sub request { Dancer::SharedData->request }
203sub send_error { Dancer::Continuation::Route::ErrorSent->new(
204 return_value => Dancer::Error->new(
205 message => $_[0],
206 code => $_[1] || 500)->render()
207 )->throw }
208#sub send_file { goto &_send_file }
209sub send_file { Dancer::Continuation::Route::FileSent->new(
210 return_value => _send_file(@_)
211 )->throw
212 }
213sub set { goto &setting }
214sub set_cookie { Dancer::Cookies->set_cookie(@_) }
2154671.54ms9342.11ms
# spent 3.92ms (1.80+2.11) within Dancer::setting which was called 467 times, avg 8µs/call: # 171 times (687µs+792µs) by App::Netdisco::Util::Permission::check_acl_no at line 46 of App/Netdisco/Util/Permission.pm, avg 9µs/call # 171 times (541µs+654µs) by App::Netdisco::Util::Permission::check_acl_only at line 69 of App/Netdisco/Util/Permission.pm, avg 7µs/call # 57 times (346µs+413µs) by App::Netdisco::Util::Device::is_discoverable at line 174 of App/Netdisco/Util/Device.pm, avg 13µs/call # 57 times (125µs+176µs) by App::Netdisco::Util::Device::is_discoverable at line 179 of App/Netdisco/Util/Device.pm, avg 5µs/call # 11 times (104µs+78µs) by App::Netdisco::JobQueue::PostgreSQL::_get_denied_actions at line 37 of App/Netdisco/JobQueue/PostgreSQL.pm, avg 16µs/call
sub setting { Dancer::App->applications ? Dancer::App->current->setting(@_) : Dancer::Config::setting(@_) }
# spent 1.62ms making 467 calls to Dancer::Config::setting, avg 3µs/call # spent 488µs making 467 calls to Dancer::App::applications, avg 1µs/call
216sub session { goto &_session }
217sub splat { @{ Dancer::SharedData->request->params->{splat} || [] } }
218sub start { goto &_start }
219sub status { Dancer::SharedData->response->status(@_) }
220sub template { Dancer::Template::Abstract->template(@_) }
221sub to_dumper { Dancer::Serializer::Dumper::to_dumper(@_) }
222sub to_json { Dancer::Serializer::JSON::to_json(@_) }
223sub to_xml { Dancer::Serializer::XML::to_xml(@_) }
224sub to_yaml { Dancer::Serializer::YAML::to_yaml(@_) }
225sub true { 1 }
226sub upload { Dancer::SharedData->request->upload(@_) }
227sub uri_for { Dancer::SharedData->request->uri_for(@_) }
228sub var { Dancer::SharedData->var(@_) }
229sub vars { Dancer::SharedData->vars }
230sub warning { goto &Dancer::Logger::warning }
231
232# When importing the package, strict and warnings pragma are loaded,
233# and the appdir detection is performed.
234{
235 my $as_script = 0;
236
237sub import {
238 my ($class, @args) = @_;
239 my ($package, $script) = caller;
240
241 strict->import;
242 warnings->import;
243 utf8->import;
244
245 my @final_args;
246 my $syntax_only = 0;
247 foreach (@args) {
248 if ( $_ eq ':moose' ) {
249 push @final_args, '!before', '!after';
250 }
251 elsif ( $_ eq ':tests' ) {
252 push @final_args, '!pass';
253 }
254 elsif ( $_ eq ':syntax' ) {
255 $syntax_only = 1;
256 }
257 elsif ($_ eq ':script') {
258 $as_script = 1;
259 } else {
260 push @final_args, $_;
261 }
262 }
263
264 $class->export_to_level(1, $class, @final_args);
265
266 # if :syntax option exists, don't change settings
267 return if $syntax_only;
268
269 $as_script = 1 if $ENV{PLACK_ENV};
270
271 Dancer::GetOpt->process_args unless $as_script;
272
273 _init_script_dir($script);
274 Dancer::Config->load;
275}
276
277}
278
279# private code
280
281# FIXME handle previous usage of load_app with multiple app names
282sub _load_app {
283 my ($app_name, %options) = @_;
284 my $script = (caller)[1];
285 Dancer::Logger::core("loading application $app_name");
286
287 # set the application
288 my $app = Dancer::App->set_running_app($app_name);
289
290 # Application options
291 $app->set_app_prefix($options{prefix}) if $options{prefix};
292 $app->settings($options{settings}) if $options{settings};
293
294 # load the application
295 _init_script_dir($script);
296 my ($res, $error) = Dancer::ModuleLoader->load($app_name);
297 $res or raise core => "unable to load application $app_name : $error";
298
299 # restore the main application
300 Dancer::App->set_running_app('main');
301}
302
303sub _init_script_dir {
304 my ($script) = @_;
305
306 my ($script_vol, $script_dirs, $script_name) =
307 File::Spec->splitpath(File::Spec->rel2abs($script));
308
309 # normalize
310 if ( -d ( my $fulldir = File::Spec->catdir( $script_dirs, $script_name ) ) ) {
311 $script_dirs = $fulldir;
312 $script_name = '';
313 }
314
315 my @script_dirs = File::Spec->splitdir($script_dirs);
316 my $script_path;
317 if ($script_vol) {
318 $script_path = Dancer::path($script_vol, $script_dirs);
319 } else {
320 $script_path = Dancer::path($script_dirs);
321 }
322
323 my $LAYOUT_PRE_DANCER_1_2 = 1;
324
325 # in bin/ or public/ or t/ we need to go one level up to find the appdir
326 $LAYOUT_PRE_DANCER_1_2 = 0
327 if ($script_dirs[$#script_dirs - 1] eq 'bin')
328 or ($script_dirs[$#script_dirs - 1] eq 'public')
329 or ($script_dirs[$#script_dirs - 1] eq 't');
330
331 my $appdir = $ENV{DANCER_APPDIR} || (
332 $LAYOUT_PRE_DANCER_1_2
333 ? $script_path
334 : File::Spec->rel2abs(Dancer::path($script_path, '..'))
335 );
336 Dancer::setting(appdir => $appdir);
337
338 # once the dancer_appdir have been defined, we export to env
339 $ENV{DANCER_APPDIR} = $appdir;
340
341 Dancer::Logger::core("initializing appdir to: `$appdir'");
342
343 Dancer::setting(confdir => $ENV{DANCER_CONFDIR}
344 || $appdir) unless Dancer::setting('confdir');
345
346 Dancer::setting(public => $ENV{DANCER_PUBLIC}
347 || Dancer::FileUtils::path($appdir, 'public'));
348
349 Dancer::setting(views => $ENV{DANCER_VIEWS}
350 || Dancer::FileUtils::path($appdir, 'views'));
351
352 my ($res, $error) = Dancer::ModuleLoader->use_lib(Dancer::FileUtils::path($appdir, 'lib'));
353 $res or raise core => "unable to set libdir : $error";
354}
355
356
357# Scheme grammar as defined in RFC 2396
358# scheme = alpha *( alpha | digit | "+" | "-" | "." )
359my $scheme_re = qr{ [a-z][a-z0-9\+\-\.]* }ix;
360sub _redirect {
361 my ($destination, $status) = @_;
362
363 # RFC 2616 requires an absolute URI with a scheme,
364 # turn the URI into that if it needs it
365 if ($destination !~ m{^ $scheme_re : }x) {
366 my $request = Dancer::SharedData->request;
367 $destination = $request->uri_for($destination, {}, 1);
368 }
369 my $response = Dancer::SharedData->response;
370 $response->status($status || 302);
371 $response->headers('Location' => $destination);
372}
373
374sub _session {
375 engine 'session'
376 or raise core => "Must specify session engine in settings prior to using 'session' keyword";
377 @_ == 0 ? Dancer::Session->get
378 : @_ == 1 ? Dancer::Session->read(@_)
379 : Dancer::Session->write(@_);
380}
381
382sub _send_file {
383 my ($path, %options) = @_;
384 my $env = Dancer::SharedData->request->env;
385
386 my $request = Dancer::Request->new_for_request('GET' => $path);
387 Dancer::SharedData->request($request);
388
389 # if you asked for streaming but it's not supported in PSGI
390 if ( $options{'streaming'} && ! $env->{'psgi.streaming'} ) {
391 # TODO: throw a fit (AKA "exception") or a Dancer::Error?
392 raise core => 'Sorry, streaming is not supported on this server.';
393 }
394
395 if (exists($options{content_type})) {
396 $request->content_type($options{content_type});
397 }
398
399 # If we're given an IO::Scalar object, DTRT (take the scalar ref from it)
400 if (Scalar::Util::blessed($path) && $path->isa('IO::Scalar')) {
401 $path = $path->sref;
402 }
403
404 my $resp;
405 if (ref($path) eq "SCALAR") {
406 # send_data
407 $resp = Dancer::SharedData->response() || Dancer::Response->new();
408 $resp->header('Content-Type' => exists($options{content_type}) ?
409 $options{content_type} : Dancer::MIME->default());
410 $resp->content($$path);
411 } else {
412 # real send_file
413 if ($options{system_path} && -f $path) {
414 $resp = Dancer::Renderer->get_file_response_for_path($path);
415 } else {
416 $resp = Dancer::Renderer->get_file_response();
417 }
418 }
419
420 if ($resp) {
421
422 if (exists($options{filename})) {
423 $resp->push_header('Content-Disposition' =>
424 "attachment; filename=\"$options{filename}\""
425 );
426 }
427
428 if ( $options{'streaming'} ) {
429 # handle streaming
430 $resp->streamed( sub {
431 my ( $status, $headers ) = @_;
432 my %callbacks = defined $options{'callbacks'} ?
433 %{ $options{'callbacks'} } :
434 ();
435
436 return sub {
437 my $respond = shift;
438 exists $callbacks{'override'}
439 and return $callbacks{'override'}->( $respond, $resp );
440
441 # get respond callback and set headers, get writer in return
442 my $writer = $respond->( [
443 $status,
444 $headers,
445 ] );
446
447 # get content from original response
448 my $content = $resp->content;
449
450 exists $callbacks{'around'}
451 and return $callbacks{'around'}->( $writer, $content );
452
453 if ( ref $content ) {
454 my $bytes = $options{'bytes'} || '43008'; # 42K (dams)
455 my $buf;
456 while ( ( my $read = sysread $content, $buf, $bytes ) != 0 ) {
457 if ( exists $callbacks{'around_content'} ) {
458 $callbacks{'around_content'}->( $writer, $buf );
459 } else {
460 $writer->write($buf);
461 }
462 }
463 } else {
464 $writer->write($content);
465 }
466 };
467 } );
468 }
469
470 return $resp;
471
472 }
473
474 Dancer::Error->new(
475 code => 404,
476 message => "No such file: `$path'"
477 )->render();
478}
479
480# Start/Run the application with the chosen apphandler
481sub _start {
482 my ($class, $request) = @_;
483 Dancer::Config->load;
484
485 # Backward compatibility for app.psgi that has sub { Dancer->dance($req) }
486 if ($request) {
487 Dancer::Handler->init_request_headers( $request->env );
488 # TODO _build_headers should either not be private, or we should call
489 # init
490 $request->_build_headers;
491 return Dancer::Handler->handle_request($request);
492 }
493
494 my $handler = Dancer::Handler->get_handler;
495 Dancer::Logger::core("loading handler '".ref($handler)."'");
496 return $handler->dance;
497}
498
499
5001;
501
502__END__