Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature no default middleware #1459

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions lib/Dancer2/Config.pod
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,19 @@ hard-configured in the proxy if possible. For Apache this would be:
RequestHeader set X_FORWARDED_PROTO "https"
RequestHeader set X_FORWARDED_HOST "www.example.com"

=head3 no_default_middleware (boolean)

If set to true, your Dancer2 application will B<NOT> be wrapped with the default
PSGI middleware. The default middleware wrappers are:

=over 4

=item * L<Plack::Middleware::FixMissingBodyInRedirect>

=item * L<Plack::Middleware::Head>

=back

=head2 Content type / character set

=head3 content_type (string)
Expand Down
16 changes: 9 additions & 7 deletions lib/Dancer2/Core/App.pm
Original file line number Diff line number Diff line change
Expand Up @@ -1397,11 +1397,7 @@ sub to_app {
return $response;
};

# Wrap with common middleware
# FixMissingBodyInRedirect
$psgi = Plack::Middleware::FixMissingBodyInRedirect->wrap( $psgi );

# Only add static content handler if requires
# Only add static content handler if required
if ( $self->config->{'static_handler'} ) {
# Use App::File to "serve" the static content
my $static_app = Plack::App::File->new(
Expand All @@ -1417,8 +1413,14 @@ sub to_app {
);
}

# Apply Head. After static so a HEAD request on static content DWIM.
$psgi = Plack::Middleware::Head->wrap( $psgi );
# Wrap with common middleware
if ( ! $self->config->{'no_default_middleware'} ) {
# FixMissingBodyInRedirect
$psgi = Plack::Middleware::FixMissingBodyInRedirect->wrap( $psgi );
# Apply Head. After static so a HEAD request on static content DWIM.
$psgi = Plack::Middleware::Head->wrap( $psgi );
}

return $psgi;
}

Expand Down
33 changes: 28 additions & 5 deletions lib/Dancer2/Manual.pod
Original file line number Diff line number Diff line change
Expand Up @@ -1932,15 +1932,14 @@ If you want to use Plack middlewares, you need to enable them using
L<Plack::Builder> as such:

# in app.psgi or any other handler
use Dancer2;
use MyApp;
use Plack::Builder;

builder {
enable 'Deflater';
enable 'Session', store => 'File';
enable 'Debug', panels => [ qw<DBITrace Memory Timer> ];
dance;
MyApp->to_app;
};

The nice thing about this setup is that it will work seamlessly through
Expand All @@ -1960,17 +1959,41 @@ If you want to set up a middleware for a specific path, you can do that using
L<Plack::Builder> which uses L<Plack::App::URLMap>:

# in your app.psgi or any other handler
use Dancer2;
use MyApp;
use Plack::Builder;

my $special_handler = sub { ... };

builder {
mount '/' => dance;
mount '/special' => $special_handler;
mount '/' => MyApp->to_app;
};

=head3 Removing default middlewares

By default, a Dancer2 app is automatically wrapped with the following middleware

=over 4

=item * L<Plack::Middleware::FixMissingBodyInRedirect>

=item * L<Plack::Middleware::Head>

=back

You can configure the setting C<no_default_middleware> to a true value to stop your
Dancer2 app being wrapped with these default middleware layers.

# in you Dancer2 app or config.yml
package MyApp;
use Dancer2

set no_default_middleware => true;

This is necessary if you need to add eTag or ContentMD5 headers to
C<HEAD> requests, and you are encouraged to manually add those default
middleware back into your PSGI stack.

=head3 Running on Perl web servers with plackup

A number of Perl web servers supporting PSGI are available on CPAN:
Expand Down Expand Up @@ -2019,7 +2042,7 @@ F<app.psgi>) edit it to use L<Plack::Builder>, as described above:

builder {
enable 'Deflater';
dance;
MyApp->to_app;
};

To test if content compression works, trace the HTTP request and response
Expand Down
59 changes: 59 additions & 0 deletions t/no_default_middleware.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use strict;
use warnings;
use Test::More;
use Plack::Test;
use Plack::Builder;
use HTTP::Request::Common;

use Plack::Middleware::Head;
use Plack::Middleware::FixMissingBodyInRedirect;

# No default middleware wrappers

{
package MyTestApp;
use Dancer2;
set no_default_middleware => 1;

get '/' => sub { return 'some content' };

get '/redirect' => sub { redirect '/' };
}


subtest 'Head' => sub {
my $plain = Plack::Test->create( MyTestApp->to_app );
my $res = $plain->request( HEAD '/' );
ok( length( $res->content ) > 0, 'HEAD request on unwrapped app has content' );

my $test = Plack::Test->create(
builder {
enable 'Head';
MyTestApp->to_app;
}
);
my $response = $test->request( HEAD '/' );
is( length( $response->content ), 0, 'HEAD request on wrapped app has no content' );

is( $res->header('Content-Length'),
$response->header('Content-Length'),
'HEAD requests have consistent content length header'
);
};

subtest 'FixMissingBodyInRedirect' => sub {
my $plain = Plack::Test->create( MyTestApp->to_app );
my $res = $plain->request( GET '/redirect' );
is( length( $res->content ), 0, 'GET request that redirects on unwrapped app has no content' );

my $test = Plack::Test->create(
builder {
enable 'FixMissingBodyInRedirect';
MyTestApp->to_app;
}
);
my $response = $test->request( GET '/redirect' );
ok( length( $response->content ) > 0, 'GET request that redirects on wrapped app has content' );
};

done_testing;