Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/1.3091'

  • Loading branch information...
commit dfe5e6f36ff037ca5de341755bae0bc7651295a2 2 parents 8fe4534 + 6627af8
@xsawyerx xsawyerx authored
View
20 CHANGES
@@ -1,5 +1,25 @@
{{$NEXT}}
+1.3091 17.12.2011
+
+ [ BUG FIXES ]
+ * Reverting template() behavior by popular demand. (Damien Krotkine)
+ * GH #714: Run post-request hooks when custom continuations were created.
+ (Damien Krotkine)
+ * Always call write_session_id() to update expires. (David Precious)
+
+ [ ENHANCEMENTS ]
+ * GH #711, #652: Add server_tokens variable to allow removal of headers.
+ (John Wittkoski)
+
+ [ DOCUMENTATION ]
+ * GH #680: Document problems with multiple apps in Dancer using
+ Plack::Handler::Apache2 and recommend a workaround.
+ (Asaf Gordon, Pedro Melo)
+ * RT #73258: Spelling glitches. (Damyan Ivanov)
+ * Use ":script" instead of ":syntax" in Cookbook. (John Barrett)
+ * Typos in Deployment doc. (David Precious)
+
1.3090 13.12.2011
** Codename: Hornburg of Hannover // Stefan Hornburg (racke) **
View
50 lib/Dancer.pm
@@ -5,7 +5,7 @@ use warnings;
use Carp;
use Cwd 'realpath';
-our $VERSION = '1.3090';
+our $VERSION = '1.3091';
our $AUTHORITY = 'SUKRIA';
use Dancer::App;
@@ -201,9 +201,7 @@ sub session { goto &_session }
sub splat { @{ Dancer::SharedData->request->params->{splat} || [] } }
sub start { goto &_start }
sub status { Dancer::SharedData->response->status(@_) }
-sub template { Dancer::Continuation::Route::Templated->new(
- return_value => Dancer::Template::Abstract->template(@_)
- )->throw }
+sub template { Dancer::Template::Abstract->template(@_) }
sub to_dumper { Dancer::Serializer::Dumper::to_dumper(@_) }
sub to_json { Dancer::Serializer::JSON::to_json(@_) }
sub to_xml { Dancer::Serializer::XML::to_xml(@_) }
@@ -1687,26 +1685,46 @@ L<Dancer::HTTP/"HTTP CODES">.
=head2 template
-Tells the route handler to build a response with the current template engine:
+Returns the response of processing the given template with the given parameters
+(and optional settings), wrapping it in the default or specified layout too, if
+layouts are in use.
+
+An example of a route handler which returns the result of using template to
+build a response with the current template engine:
get '/' => sub {
...
- template 'some_view', { token => 'value'};
+ return template 'some_view', { token => 'value'};
};
-B<WARNING> : Issuing a template immediately exits the current route, and perform
-the template. Thus, any code after a template is ignored, until the end of the route.
-So it's not necessary anymore to use C<return> with template.
+Note that C<template> simply returns the content, so when you use it in a route
+handler, if execution of the the route handler should stop at that point, make
+sure you use 'return' to ensure your route handler returns the content.
- get '/some/route' => sub {
+Since template just returns the result of rendering the template, you can also
+use it to perform other templating tasks, e.g. generating emails:
+
+ post '/some/route' => sub {
if (...) {
- # we want to let the next matching route handler process this one
- template(...);
- # This code will be ignored
- do_stuff();
+ email {
+ to => 'someone@example.com',
+ from => 'foo@example.com',
+ subject => 'Hello there',
+ msg => template('emails/foo', { name => params->{name} }),
+ };
+
+ return template 'message_sent';
+ } else {
+ return template 'error';
}
};
+Compatibility notice: C<template> was changed in version 1.3090 to immediately
+interrupt execution of a route handler and return the content, as it's typically
+used at the end of a route handler to return content. However, this caused
+issues for some people who were using C<template> to generate emails etc, rather
+than accessing the template engine directly, so this change has been reverted
+in 1.3091.
The first parameter should be a template available in the views directory, the
second one (optional) is a HashRef of tokens to interpolate, and the third
@@ -1715,13 +1733,13 @@ second one (optional) is a HashRef of tokens to interpolate, and the third
For example, to disable the layout for a specific request:
get '/' => sub {
- template 'index.tt', {}, { layout => undef };
+ template 'index', {}, { layout => undef };
};
Or to request a specific layout, of course:
get '/user' => sub {
- template 'user.tt', {}, { layout => 'user' };
+ template 'user', {}, { layout => 'user' };
};
Some tokens are automatically added to your template (C<perl_version>,
View
32 lib/Dancer/Config.pm
@@ -220,18 +220,19 @@ sub load_settings_from_yaml {
}
sub load_default_settings {
- $SETTINGS->{server} ||= $ENV{DANCER_SERVER} || '0.0.0.0';
- $SETTINGS->{port} ||= $ENV{DANCER_PORT} || '3000';
- $SETTINGS->{content_type} ||= $ENV{DANCER_CONTENT_TYPE} || 'text/html';
- $SETTINGS->{charset} ||= $ENV{DANCER_CHARSET} || '';
- $SETTINGS->{startup_info} ||= $ENV{DANCER_STARTUP_INFO} || 1;
- $SETTINGS->{daemon} ||= $ENV{DANCER_DAEMON} || 0;
- $SETTINGS->{apphandler} ||= $ENV{DANCER_APPHANDLER} || 'Standalone';
- $SETTINGS->{warnings} ||= $ENV{DANCER_WARNINGS} || 0;
- $SETTINGS->{auto_reload} ||= $ENV{DANCER_AUTO_RELOAD} || 0;
- $SETTINGS->{traces} ||= $ENV{DANCER_TRACES} || 0;
- $SETTINGS->{logger} ||= $ENV{DANCER_LOGGER} || 'file';
- $SETTINGS->{environment} ||=
+ $SETTINGS->{server} ||= $ENV{DANCER_SERVER} || '0.0.0.0';
+ $SETTINGS->{port} ||= $ENV{DANCER_PORT} || '3000';
+ $SETTINGS->{content_type} ||= $ENV{DANCER_CONTENT_TYPE} || 'text/html';
+ $SETTINGS->{charset} ||= $ENV{DANCER_CHARSET} || '';
+ $SETTINGS->{startup_info} ||= $ENV{DANCER_STARTUP_INFO} || 1;
+ $SETTINGS->{daemon} ||= $ENV{DANCER_DAEMON} || 0;
+ $SETTINGS->{apphandler} ||= $ENV{DANCER_APPHANDLER} || 'Standalone';
+ $SETTINGS->{warnings} ||= $ENV{DANCER_WARNINGS} || 0;
+ $SETTINGS->{auto_reload} ||= $ENV{DANCER_AUTO_RELOAD} || 0;
+ $SETTINGS->{traces} ||= $ENV{DANCER_TRACES} || 0;
+ $SETTINGS->{server_tokens} ||= $ENV{DANCER_SERVER_TOKENS} || 1;
+ $SETTINGS->{logger} ||= $ENV{DANCER_LOGGER} || 'file';
+ $SETTINGS->{environment} ||=
$ENV{DANCER_ENVIRONMENT}
|| $ENV{PLACK_ENV}
|| 'development';
@@ -445,6 +446,13 @@ If set to true, tells Dancer to consider all warnings as blocking errors.
If set to true, Dancer will display full stack traces when a warning or a die
occurs. (Internally sets Carp::Verbose). Default to false.
+=head3 server_tokens (boolean)
+
+If set to true, Dancer will add an "X-Powered-By" header and also append
+the Dancer version to the "Server" header. Default to true.
+
+You can also use the environment variable C<DANCER_SERVER_TOKENS>.
+
=head3 log_path (string)
Folder where the ``file C<logger>'' saves logfiles.
View
6 lib/Dancer/Cookbook.pod
@@ -694,7 +694,7 @@ Use Dancer instead. Without any ado, magic or too big jumps, you can use the
values from config.yml and some additional default values:
# bin/script1.pl
- use Dancer ':syntax';
+ use Dancer ':script';
print "template:".config->{template}."\n"; #simple
print "log:".config->{log}."\n"; #undef
@@ -709,7 +709,7 @@ deducts where the config.yml file is (typically $webapp/config.yml).
# bin/script2.pl
use FindBin;
use Cwd qw/realpath/;
- use Dancer ':syntax';
+ use Dancer ':script';
#tell the Dancer where the app lives
my $appdir=realpath( "$FindBin::Bin/..");
@@ -734,7 +734,7 @@ e.g.:
If you want to load an environment other than the default, try this:
# bin/script2.pl
- use Dancer ':syntax';
+ use Dancer ':script';
#tell the Dancer where the app lives
Dancer::Config::setting('appdir','/path/to/app/dir');
View
15 lib/Dancer/Deployment.pod
@@ -33,7 +33,7 @@ sites-available/*site*):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
- RewriteRule ^(.*)$ /dispatch.cgi$1 [QSA,L]
+ RewriteRule ^(.*)$ /dispatch.cgi/$1 [QSA,L]
ErrorLog /var/log/apache2/www.example.com-error.log
CustomLog /var/log/apache2/www.example.com-access_log common
@@ -429,7 +429,8 @@ following:
CustomLog /websites/myapp.example.com/logs/access_log common
</VirtualHost>
-To set the environment you want to use for your application (production or development), you can set it this way:
+To set the environment you want to use for your application (production or
+development), you can set it this way:
<VirtualHost>
...
@@ -437,6 +438,16 @@ To set the environment you want to use for your application (production or devel
...
</VirtualHost>
+B<NOTE:> Only a single Dancer application can be deployed using the
+C<Plack::Handler::Apache2> method. Multiple Dancer applications
+B<will not work properly> (The routes will be mixed-up between the
+applications).
+
+It's recommended to start each app with C<plackup> using your
+favorite server (Starman, for example) and then put a web server (Apache,
+Nginx, Perlbal, etc.) as a frontend server for both apps using reverse proxy
+(HTTP based, no fastcgi).
+
=head3 Running from Apache under appdir
If you want to deploy multiple applications under the same VirtualHost, using
View
2  lib/Dancer/Deprecation.pm
@@ -66,7 +66,7 @@ List of possible parameters:
=back
-You can call the method with no arguments, and a default message using informations from C<caller> will be build for you.
+You can call the method with no arguments, and a default message using information from C<caller> will be built for you.
=head1 LICENSE
View
12 lib/Dancer/Error.pm
@@ -14,6 +14,7 @@ use Dancer::Factory::Hook;
use Dancer::Session;
use Dancer::FileUtils qw(open_file);
use Dancer::Engine;
+use Dancer::Exception qw(:all);
Dancer::Factory::Hook->instance->install_hooks(
qw/before_error_render after_error_render before_error_init/);
@@ -174,7 +175,16 @@ sub render {
my $serializer = setting('serializer');
Dancer::Factory::Hook->instance->execute_hooks('before_error_render', $self);
- my $response = $serializer ? $self->_render_serialized() : $self->_render_html();
+ my $response;
+ try {
+ $response = $serializer ? $self->_render_serialized() : $self->_render_html();
+ } continuation {
+ my ($continuation) = @_;
+ # If we have a Route continuation, run the after hook, then
+ # propagate the continuation
+ Dancer::Factory::Hook->instance->execute_hooks('after_error_render', $response);
+ $continuation->rethrow();
+ };
Dancer::Factory::Hook->instance->execute_hooks('after_error_render', $response);
$response;
}
View
4 lib/Dancer/Exception.pm
@@ -216,7 +216,7 @@ parameters is an exception message, but it's left to the exception class
implementation.
If the exception class name starts with a C<+>, then the
-C<Dancer::Exception::Base::> won't be added. This allows to build their own
+C<Dancer::Exception::Base::> won't be added. This allows one to build their own
exception class hierarchy, but you should first look at C<register_exception>
before implementing your own class hierarchy. If you really wish to build your
own exception class hierarchy, we recommend that all exceptions inherit of
@@ -229,7 +229,7 @@ it would be camelized into C<'Myexception'>.
=head2 register_exception
-This method allows to register custom exceptions, usable by Dancer users in
+This method allows one to register custom exceptions, usable by Dancer users in
their route code (actually pretty much everywhere).
# simple exception
View
2  lib/Dancer/FileUtils.pm
@@ -220,7 +220,7 @@ Provides comfortable path resolving, internally using L<File::Spec>.
Returns either the content of a file (whose filename is the input), I<undef>
if the file could not be opened.
-In array context it returns each line (as defined by $/) as a seperate element;
+In array context it returns each line (as defined by $/) as a separate element;
in scalar context returns the entire contents of the file.
=head2 read_glob_content
View
33 lib/Dancer/Renderer.pm
@@ -56,10 +56,12 @@ sub render_error {
sub response_with_headers {
my $response = Dancer::SharedData->response();
- $response->{headers} ||= HTTP::Headers->new;
- my $powered_by = "Perl Dancer " . $Dancer::VERSION;
- $response->header('X-Powered-By' => $powered_by);
- $response->header('Server' => $powered_by);
+ if (Dancer::Config::setting('server_tokens')) {
+ $response->{headers} ||= HTTP::Headers->new;
+ my $powered_by = "Perl Dancer " . $Dancer::VERSION;
+ $response->header('X-Powered-By' => $powered_by);
+ $response->header('Server' => $powered_by);
+ }
return $response;
}
@@ -127,8 +129,17 @@ sub get_action_response {
return $class->serialize_response_if_needed() if defined $response && $response->exists;
# else, get the route handler's response
Dancer::App->current($handler->{app});
- $handler->run($request);
- $class->serialize_response_if_needed();
+ try {
+ $handler->run($request);
+ $class->serialize_response_if_needed();
+ } continuation {
+ my ($continuation) = @_;
+ # If we have a Route continuation, run the after hook, then
+ # propagate the continuation
+ my $resp = Dancer::SharedData->response();
+ Dancer::Factory::Hook->instance->execute_hooks('after', $resp);
+ $continuation->rethrow();
+ };
my $resp = Dancer::SharedData->response();
Dancer::Factory::Hook->instance->execute_hooks('after', $resp);
return $resp;
@@ -143,7 +154,15 @@ sub serialize_response_if_needed {
if (Dancer::App->current->setting('serializer') && $response->content()){
Dancer::Factory::Hook->execute_hooks('before_serializer', $response);
- Dancer::Serializer->process_response($response);
+ try {
+ Dancer::Serializer->process_response($response);
+ } continuation {
+ my ($continuation) = @_;
+ # If we have a Route continuation, run the after hook, then
+ # propagate the continuation
+ Dancer::Factory::Hook->execute_hooks('after_serializer', $response);
+ $continuation->rethrow();
+ };
Dancer::Factory::Hook->execute_hooks('after_serializer', $response);
}
return $response;
View
4 lib/Dancer/Route/Cache.pm
@@ -161,7 +161,7 @@ the requested path to a route.
A major drawback is that L<Dancer> has to go over the matching on every request,
which (especially on CGI-based applications) can be very time consuming.
-The caching mechanism allows to cache some requests to specific routes (but
+The caching mechanism allows one to cache some requests to specific routes (but
B<NOT> specific results) and run those routes on a specific path. This allows us
to speed up L<Dancer> quite a lot.
@@ -215,7 +215,7 @@ Returns all the paths in the cache. This is used to enforce the path limit.
=head2 size_limit($limit)
-Allows to set a size limit of the cache.
+Allows one to set a size limit of the cache.
Returns the limit (post-set).
View
6 lib/Dancer/Session.pm
@@ -28,8 +28,12 @@ sub get_current_session {
if (not defined $session) {
$session = $class->create();
- engine->write_session_id($session->id);
}
+
+ # Generate a session cookie; we want to do this regardless of whether the
+ # session is new or existing, so that the cookie expiry is updated.
+ engine->write_session_id($session->id);
+
return $session;
}
View
25 lib/Dancer/Template/Abstract.pm
@@ -7,6 +7,7 @@ use Carp;
use Dancer::Logger;
use Dancer::Factory::Hook;
use Dancer::FileUtils 'path';
+use Dancer::Exception qw(:all);
use base 'Dancer::Engine';
@@ -62,7 +63,16 @@ sub apply_renderer {
Dancer::Factory::Hook->execute_hooks('before_template_render', $tokens);
- my $content = $self->render($view, $tokens);
+ my $content;
+ try {
+ $content = $self->render($view, $tokens);
+ } continuation {
+ my ($continuation) = @_;
+ # If we have a Route continuation, run the after hook, then
+ # propagate the continuation
+ Dancer::Factory::Hook->execute_hooks('after_template_render', \$content);
+ $continuation->rethrow();
+ };
Dancer::Factory::Hook->execute_hooks('after_template_render', \$content);
@@ -92,8 +102,17 @@ sub apply_layout {
Dancer::Factory::Hook->execute_hooks('before_layout_render', $tokens, \$content);
- my $full_content =
- $self->layout($layout, $tokens, $content);
+ my $full_content;
+
+ try {
+ $full_content = $self->layout($layout, $tokens, $content);
+ } continuation {
+ my ($continuation) = @_;
+ # If we have a Route continuation, run the after hook, then
+ # propagate the continuation
+ Dancer::Factory::Hook->execute_hooks('after_layout_render', \$full_content);
+ $continuation->rethrow();
+ };
Dancer::Factory::Hook->execute_hooks('after_layout_render', \$full_content);
View
37 t/22_hooks/11_error_in_hook.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use Test::More tests => 3, import => ['!pass'];
+use Test::More tests => 10, import => ['!pass'];
use Dancer ':syntax';
use Dancer::Test;
@@ -19,3 +19,38 @@ get '/' => sub {
route_exists [ GET => '/' ];
response_content_like( [ GET => '/' ], qr/Unable to process your query/ );
response_status_is( [ GET => '/' ], 500 => "We get a 500 status" );
+
+
+
+my $var = 5;
+
+ok(
+ hook ( after => sub {
+ $var = 42;
+ } ),
+ 'after hook is defined'
+ );
+
+get '/error' => sub {
+ send_error "FAIL";
+ # should not be executed
+ fail("This code should not be executed (1)");
+};
+
+route_exists [ GET => '/error' ];
+response_status_is( [ GET => '/error' ], 500 => "We get a 500 status" );
+
+is ($var, 42, "The after hook were called even after a send error");
+
+get '/halt_me' => sub {
+ halt({error => "This is some error"});
+ # should not be executed
+ fail("This code should not be executed (2)");
+};
+
+$var = 5;
+
+route_exists [ GET => '/halt_me' ];
+response_status_is( [ GET => '/halt_me' ], 500 => "We get a 200 status" );
+
+is ($var, 5, "The after hook is bypassed if in a 'halt' state, as it was before version 1.3080");
Please sign in to comment.
Something went wrong with that request. Please try again.