Dancer2

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

    * 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

Changes  view on Meta::CPAN

    [ 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.676 second using v1.01-cache-2.11-cpan-5dc5da66d9d )