Dancer2
view release on metacpan or search on metacpan
* GH #916: Fix test example. (Peter Mottram - @SysPete)
* GH #912, #913: Fix documentation on when stacks are printed.
(Andrew Solomon)
0.160001 2015-05-14 20:40:10+02:00 Europe/Amsterdam
[ BUG FIXES ]
* GH #893, #895: Catch config parse errors when Config::Any doesn't throw
them. (Russell Jenkins)
* GH #899: Minimum YAML version supported is v0.86 (Shlomi Fish)
* GH #906: send_file - missing import and fix logic error for streaming
by default (Russell Jenkins)
[ DOCUMENTATION ]
* GH #897: Remove docs for unimplemented 'load' keyword (Fayland Lam)
[ ENHANCEMENT ]
* GH #894, #898: Add status and headers methods to ::Response::Delayed
(Yanick Champoux, Charlie Gonzalez)
0.160000 2015-04-27 00:12:55+02:00 Europe/Amsterdam
[ BUG FIXES ]
* GH #856: Memory leak when throwing exception from a hook. (Sawyer X)
0.159001 2015-02-25 15:31:35+01:00 Europe/Amsterdam
[ BUG FIXES ]
* GH #855: Ensure Dancer2::Test is compatible with Pod::Simple 3.30.
(Russell Jenkins)
[ DOCUMENTATION ]
* Add an example for delayed (async) streaming response. (Sawyer X)
* Small link fix. (Sawyer X)
0.159000 2015-02-24 04:51:20+01:00 Europe/Amsterdam
[ BUG FIXES ]
* GH #762: Delay app cleanup until errors are rendered. (Russell Jenkins)
* GH #835: Correct Logic error in Logger if no request exists.
(Lennart Hengstmengel)
* GH #839: Correct "no_server_tokens" definition in production.yml.
(Nikita K)
lib/Dancer2/Core/App.pm view on Meta::CPAN
( exists $options{'charset'} ) and $charset = $options{'charset'};
$content_type .= "; charset=$charset" if $content_type and $charset;
( defined $content_type )
and $self->response->header('Content-Type' => $content_type );
# content disposition
( exists $options{filename} )
and $self->response->header( 'Content-Disposition' =>
($options{content_disposition} || "attachment") . "; filename=\"$options{filename}\"" );
# use a delayed response unless server does not support streaming
my $use_streaming = exists $options{streaming} ? $options{streaming} : 1;
my $response;
my $env = $self->request->env;
if ( $env->{'psgi.streaming'} && $use_streaming ) {
my $cb = sub {
my $responder = $Dancer2::Core::Route::RESPONDER;
my $res = $Dancer2::Core::Route::RESPONSE;
return $responder->(
[ $res->status, $res->headers_to_array, $fh ]
);
};
Scalar::Util::weaken( my $weak_self = $self );
lib/Dancer2/Core/DSL.pm view on Meta::CPAN
local $Dancer2::Core::Route::RESPONDER = $responder;
local $Dancer2::Core::Route::WRITER = $writer;
local $Dancer2::Core::Route::ERROR_HANDLER = $handler;
$cb->(@_);
};
}
sub flush {
my $responder = $Dancer2::Core::Route::RESPONDER
or croak 'flush() called outside streaming response';
my $response = $Dancer2::Core::Route::RESPONSE;
$Dancer2::Core::Route::WRITER = $responder->([
$response->status, $response->headers_to_array,
]);
}
sub done {
my $writer = $Dancer2::Core::Route::WRITER
or croak 'done() called outside streaming response';
$writer->close;
}
sub pass { shift->app->pass }
#
# Route handler helpers
#
lib/Dancer2/Core/Response/Delayed.pm view on Meta::CPAN
error_cb => sub {
my ($error) = @_;
...
},
);
# or in an app
get '/' => sub {
# delayed response:
delayed {
# streaming content
content "data";
content "more data";
# close user connection
done;
} on_error => sub {
my ($error) = @_;
warning 'Failed to stream to user: ' . request->remote_address;
};
};
lib/Dancer2/Manual.pod view on Meta::CPAN
to initiate an asynchronous response, allowing you to deliver long-running
results, or handling long-running operations.
=head2 done
Once everything is set, you can use C<done> to finalize and send the
response to the visitor.
=head2 flush
To send parts of the response incrementally, C<flush> allows streaming
content to the client in a delayed response without closing the connection.
=head2 Example: Asynchronous HTTP Request
Hereâs how you can fetch data asynchronously in Dancer2. Instead of
waiting for a response, the request runs in the background and delivers
the result when itâs ready:
use Dancer2;
use Future::HTTP;
lib/Dancer2/Manual/Keywords.pod view on Meta::CPAN
Initiates an asynchronous response. Requires a Plack/PSGI server capable
of serving requests asynchronously.
B<When to use>: When starting an asynchronous reponse.
B<Related Keywords>: L</done>, L</flush>
=head2 L<done|Dancer2::Manual/done>
Finalizes an asynchronous repsonse and closes the connection. Can only
be run within the streaming response callback.
B<When to use>: When finishing delivery of data asynchronously.
B<See also>: L</delayed>, L</flush>
=head2 L<encode_json|Dancer2::Manual/encode_json>
Serializes a data structure to a UTF-8 encoded binary JSON string. Calling
this keyword will not trigger the application's serializer hooks.
B<When to use>: When needing to translate a Perl data structure to JSON.
B<See also>: L</decode_json>, L</to_json>
=head2 L<flush|Dancer2::Manual/flush>
Flushes content headers when streaming a response. This is necessary when
C<content> is called multiple times.
B<When to use>: When streaming large amounts of data (such as video)
asynchronously.
B<See also>: L</delayed>, L</done>
=head2 L<forward|Dancer2::Manual/forward>
Forwards the request to another route handler.
B<When to use>: Internally redirect to another route within the app.
t/dsl/send_file.t view on Meta::CPAN
};
get '/check_content_type' => sub {
my $temp = File::Temp->new();
print $temp "hello";
close $temp;
send_file($temp->filename, content_type => 'image/png',
system_path => 1);
};
get '/no_streaming' => sub {
my $file = File::Spec->rel2abs(__FILE__);
send_file( $file, system_path => 1, streaming => 0 );
};
get '/options_streaming' => sub {
my $file = File::Spec->rel2abs(__FILE__);
send_file( $file, system_path => 1, streaming => 1 );
};
get '/content_disposition/attachment' => sub {
send_file('1x1.png', filename => '1x1.png');
};
get '/content_disposition/inline' => sub {
send_file('1x1.png', filename => '1x1.png', content_disposition => 'inline');
};
}
t/dsl/send_file.t view on Meta::CPAN
subtest "filehandles" => sub {
my $r = $cb->( GET '/filehandle' );
is( $r->code, 200, 'send_file set status to 200 (filehandle)');
is( $r->content_type, 'text/plain', 'expected content_type');
is( $r->content_type_charset, 'UTF-8', 'expected charset');
like( $r->content, qr{package StaticContent}, 'filehandle content' );
};
subtest "no streaming" => sub {
my $r = $cb->( GET '/no_streaming' );
is( $r->code, 200, 'send_file set status to 200 (no streaming)');
like( $r->content, qr{package StaticContent}, 'no streaming - content' );
};
subtest "options streaming" => sub {
my $r = $cb->( GET '/options_streaming' );
is( $r->code, 200, 'send_file set status to 200 (options streaming)');
like( $r->content, qr{package StaticContent}, 'options streaming - content' );
};
subtest 'send_file returns correct content type' => sub {
my $r = $cb->( GET '/check_content_type' );
ok($r->is_success, 'send_file returns success');
is($r->content_type, 'image/png', 'send_file returns correct content_type');
};
subtest 'Content-Disposition defaults to "attachment"' => sub {
( run in 0.581 second using v1.01-cache-2.11-cpan-5dc5da66d9d )