Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'devel'

  • Loading branch information...
commit 61aa0c06e4f61d171254ce9feb6a4f2e6c0e3e81 2 parents 47f5c52 + 0808a03
Alexis Sukrieh authored
View
23 CHANGES
@@ -1,3 +1,26 @@
+1.3010_01 12.02.2011
+
+ [ BUG FIXES ]
+ * GH#136: fix again Mime::Type issues in preforking environment
+ (Chris Andrews)
+ * GH#220: fix for path issues under MacOS X and Windows platforms.
+ A new function is provided by Dancer::FileUtils: path_no_verify()
+ (Rowan Thorpe)
+ * Fix for infinite loops detection in before filters
+ (Flavio Poletti)
+
+ [ ENHANCEMENTS ]
+ * Better detection of the application layout under non-UNIX platforms.
+ (Rowan Thorpe, Alexis Sukrieh)
+
+ [ DOCUMENTATION ]
+ * Fix a typo in Dancer::Request::Upload's POD
+ (Rowan Thorpe)
+ * Better documentation for the before filters, explanations about the
+ potential infinite loops that can happen when using before filters (and
+ what Dancer does in that case).
+ (Flavio Poletti)
+
1.3010 10.02.2011
[ BUG FIXES ]
View
2  MANIFEST
@@ -151,10 +151,12 @@ t/03_route_handler/28_plack_mount.t
t/03_route_handler/29_forward.t
t/03_route_handler/29_redirect_immediately.t
t/03_route_handler/30_bug_gh190.t
+t/03_route_handler/31_infinite_loop.t
t/03_route_handler/public/404.html
t/03_route_handler/views/hello.tt
t/04_static_file/001_base.t
t/04_static_file/002_mime_types.t
+t/04_static_file/003_mime_types_reinit.t
t/04_static_file/03_get_mime_type.t
t/04_static_file/static/hello.foo
t/04_static_file/static/hello.txt
View
34 lib/Dancer.pm
@@ -7,7 +7,7 @@ use Cwd 'abs_path', 'realpath';
use vars qw($VERSION $AUTHORITY @EXPORT);
-$VERSION = '1.3010';
+$VERSION = '1.3010_01';
$AUTHORITY = 'SUKRIA';
use Dancer::Config;
@@ -235,14 +235,19 @@ sub start {
sub _init {
- my $script = shift;
- my $script_path = File::Spec->rel2abs(path(dirname($script)));
+ my $script = shift;
+
+ my ($script_vol, $script_dirs, $script_name) =
+ File::Spec->splitpath(File::Spec->rel2abs($script));
+ my @script_dirs = File::Spec->splitdir($script_dirs);
+ my $script_path = File::Spec->catdir($script_vol, $script_dirs);
my $LAYOUT_PRE_DANCER_1_2 = 1;
+
+ # in bin/ or public/ we need to go one level upper to find the appdir
$LAYOUT_PRE_DANCER_1_2 = 0
- if ( basename($script) eq 'app.pl'
- || basename($script) eq 'dispatch.cgi'
- || basename($script) eq 'dispatch.fcgi');
+ if ($script_dirs[$#script_dirs - 1] eq 'bin')
+ or ($script_dirs[$#script_dirs - 1] eq 'public');
setting appdir => $ENV{DANCER_APPDIR}
|| (
@@ -261,14 +266,14 @@ sub _init {
|| setting('appdir');
setting public => $ENV{DANCER_PUBLIC}
- || path(setting('appdir'), 'public');
+ || Dancer::FileUtils::path_no_verify(setting('appdir'), 'public');
setting views => $ENV{DANCER_VIEWS}
- || path(setting('appdir'), 'views');
+ || Dancer::FileUtils::path_no_verify(setting('appdir'), 'views');
setting logger => 'file';
- my ($res, $error) = Dancer::ModuleLoader->use_lib(path(setting('appdir'), 'lib'));
+ my ($res, $error) = Dancer::ModuleLoader->use_lib(Dancer::FileUtils::path_no_verify(setting('appdir'), 'lib'));
$res or croak "unable to set libdir : $error";
}
@@ -374,7 +379,16 @@ Defines a before filter:
};
The anonymous function which is given to C<before> will be executed before
-looking for a route handler to handle the request.
+executing a route handler to handle the request.
+
+If the function modifies the request's C<path_info> or C<method>, a new
+search for a matching route is performed and the filter is re-executed
+again. Considering that this can lead to an infinite loop, this mechanism
+is stopped after 10 times with an exception.
+
+The before filter can set a response with a redirection code (either
+301 or 302): in this case the matched route (if any) will be ignored and the
+redirection will be performed immediately.
You can define multiple before filters, using the C<before> helper as
many times as you wish; each filter will be executed in the order you added
View
14 lib/Dancer/FileUtils.pm
@@ -6,13 +6,25 @@ use warnings;
use File::Basename ();
use File::Spec;
use Carp;
+use Cwd 'realpath';
use base 'Exporter';
use vars '@EXPORT_OK';
@EXPORT_OK = qw(path dirname read_file_content read_glob_content open_file);
-sub path { File::Spec->catfile(@_) }
+sub path {
+ File::Spec->catfile(@_);
+}
+
+sub path_no_verify {
+ my @nodes = @_;
+
+ # [0->?] path(must exist),[last] file(maybe exists)
+ return realpath(File::Spec->catdir(@nodes[0 .. ($#nodes - 1)])) . '/'
+ . $nodes[-1];
+}
+
sub dirname { File::Basename::dirname(@_) }
sub open_file {
View
9 lib/Dancer/MIME.pm
@@ -6,6 +6,15 @@ use base 'Dancer::Object::Singleton';
use MIME::Types;
+# Initialise MIME::Types at compile time, to ensure it's done before
+# the fork in a preforking webserver like mod_perl or Starman. Not
+# doing this leads to all MIME types being returned as "text/plain",
+# as MIME::Types fails to load its mappings from the DATA handle. See
+# t/04_static_file/003_mime_types_reinit.t and GH#136.
+BEGIN {
+ MIME::Types->new(only_complete => 1);
+}
+
__PACKAGE__->attributes( qw/mime_type aliases/ );
sub init {
View
2  lib/Dancer/Plugins.pod
@@ -26,7 +26,7 @@ should be.
Provides easy acces to DBIx::Class database virtualization.
-=item L<Dancer::Plugin::Authorize>
+=item L<Dancer::Plugin::Auth::RBAC>
Dancer Authentication, Security and Role-Based Access Control Framework.
View
10 lib/Dancer/Renderer.pm
@@ -83,7 +83,7 @@ sub html_page {
}
sub get_action_response {
- my $response;
+ my $depth = shift || 1;
# save the request before the filters are ran
my $request = Dancer::SharedData->request;
@@ -99,19 +99,17 @@ sub get_action_response {
$_->() for @{$app->registry->hooks->{before}};
# recurse if something has changed
- my $limit = 0;
my $MAX_RECURSIVE_LOOP = 10;
if ( ($path ne Dancer::SharedData->request->path_info)
|| ($method ne Dancer::SharedData->request->method))
{
- $limit++;
- if ($limit > $MAX_RECURSIVE_LOOP) {
+ if ($depth > $MAX_RECURSIVE_LOOP) {
croak "infinite loop detected, "
. "check your route/filters for "
. $method . ' '
. $path;
}
- return get_action_response();
+ return get_action_response($depth + 1);
}
# redirect immediately - skip route execution
@@ -130,7 +128,7 @@ sub get_action_response {
# else, get the route handler's response
Dancer::App->current($handler->app);
- $response = $handler->run($request);
+ my $response = $handler->run($request);
$response = serialize_response_if_needed($response);
$_->($response) for (@{$app->registry->hooks->{after}});
return $response;
View
2  lib/Dancer/Request/Upload.pm
@@ -110,7 +110,7 @@ Returns a scalar containing the contents of the temporary file.
Copies the temporary file using File::Copy. Returns true for success,
false for failure.
- $upload->copy_to('/path/to/targe')
+ $upload->copy_to('/path/to/target')
=back
View
9 t/02_request/14_uploads.t
@@ -3,6 +3,7 @@ use warnings;
use Dancer ':syntax';
use Dancer::Request;
+use Dancer::FileUtils;
use Test::More 'import' => ['!pass'];
@@ -95,11 +96,11 @@ do {
$upload->copy_to($dest_file);
ok( ( -f $dest_file ), "file '$dest_file' has been copied" );
- SKIP: {
- skip "bogus upload tests on win32", 3 if ( $^O eq 'MSWin32' or $^O eq 'cygwin' );
+ $upload->link_to( Dancer::FileUtils::path_no_verify( $dest_dir, "hardlink" ) );
+ ok( ( -f Dancer::FileUtils::path_no_verify( $dest_dir, "hardlink" ) ), "hardlink is created" );
- $upload->link_to( path( $dest_dir, "hardlink" ) );
- ok( ( -f path( $dest_dir, "hardlink" ) ), "hardlink is created" );
+ SKIP: {
+ skip "bogus upload tests on win32", 2 if ( $^O eq 'MSWin32' or $^O eq 'cygwin' );
# make sure cleanup is performed when the HTTP::Body object is purged
my $file = $upload->tempname;
View
26 t/03_route_handler/31_infinite_loop.t
@@ -0,0 +1,26 @@
+use strict;
+use warnings;
+
+use Test::More tests => 7, import => ['!pass'];
+use Dancer ':syntax';
+use Dancer::Test;
+
+my $i = 0;
+
+
+ok(get('/:id', sub { "whatever " . params->{id} }), 'installed basic route handler');
+
+route_exists [GET => '/:id'];
+response_status_is [GET => "/$i"], 200, 'before not installed yet, response status is 200 looks good for GET /0';
+response_content_is [GET => "/$i"], "whatever $i";
+
+ok(
+ before(
+ sub {
+ ++$i;
+ request->path_info("/$i");
+ }
+ ), 'installed before hook',
+);
+ok(! eval { dancer_response(GET => "/$i") }, 'before messes all up, route not OK any more');
+like($@, qr{infinite loop}, 'infinite loop detected');
View
46 t/04_static_file/003_mime_types_reinit.t
@@ -0,0 +1,46 @@
+use strict;
+use warnings;
+
+use IO::Handle;
+
+use Dancer::MIME;
+use Dancer ':syntax';
+use Dancer::ModuleLoader;
+
+use Test::More import => ['!pass'];
+
+plan tests => 3;
+
+# Test that MIME::Types gets initialised before the fork, as it'll
+# fail to read from DATA in all bar one child process in a
+# mod_perl-type preforking situation.
+#
+# See the comment near the top of Dancer/MIME.pm, and GH#136.
+
+my @cts;
+for (my $i = 0; $i < 3; $i++) {
+ my ($p, $c) = (IO::Handle->new, IO::Handle->new);
+ pipe($p, $c);
+
+ if (my $pid = fork()) {
+ # parent
+ $c->close;
+ my $ct = $p->getline;
+ $p->close();
+ waitpid($pid, 0);
+ push @cts, $ct;
+ }
+ else {
+ # child
+ $p->close;
+ my $mime = Dancer::MIME->instance();
+ my $type = $mime->mime_type_for('css');
+ $c->print($type);
+ $c->close;
+ exit 0;
+ }
+}
+
+ok($cts[0] eq 'text/css');
+ok($cts[1] eq 'text/css');
+ok($cts[2] eq 'text/css');
Please sign in to comment.
Something went wrong with that request. Please try again.