Mojolicious-Plugin-RenderFile-0.12/0000755000000000000000000000000013161670360015702 5ustar rootrootMojolicious-Plugin-RenderFile-0.12/t/0000755000000000000000000000000013161670357016153 5ustar rootrootMojolicious-Plugin-RenderFile-0.12/t/multibyte_filename.t0000755000000000000000000000327313161667265022232 0ustar rootrootuse utf8; use Mojo::Base -strict; use Test::More; use Encode; use File::Copy qw( copy ); use File::Temp qw( tempdir ); use Mojolicious::Lite; use Test::Mojo; use lib '../lib'; use utf8; use File::Basename qw/dirname/; use File::Spec::Functions qw/rel2abs/; my $FILE = rel2abs( tempdir( CLEANUP => 1) . '/' . '漢字.txt' ); copy( rel2abs( dirname(__FILE__) . '/' . 'unicode.txt' ), $FILE) || plan skip_all => 'unable to create file with unicode filename'; plugin 'RenderFile'; get "/default" => sub { my $self = shift; $self->render_file( filepath => $FILE ); }; get "/filename" => sub { my $self = shift; $self->render_file( filepath => $FILE, filename => '別名.txt', ); }; get "/encoded" => sub { my $self = shift; $self->render_file( filepath => encode_utf8 $FILE, ); }; get "/encoded_filename" => sub { my $self = shift; $self->render_file( filepath => encode_utf8 $FILE, filename => encode_utf8 '別名.txt', ); }; my $t = Test::Mojo->new; $t->get_ok("/default") ->status_is(200) ->content_is( '漢字(かんじ)は、古代中国に発祥を持つ文字。' ) ->header_is( 'Content-Disposition' => encode_utf8 'attachment;filename="漢字.txt"' ); $t->get_ok("/filename") ->status_is(200) ->header_is( 'Content-Disposition' => encode_utf8 'attachment;filename="別名.txt"' ); $t->get_ok("/encoded") ->status_is(200) ->header_is( 'Content-Disposition' => encode_utf8 'attachment;filename="漢字.txt"' ); $t->get_ok("/encoded_filename") ->status_is(200) ->header_is( 'Content-Disposition' => encode_utf8 'attachment;filename="別名.txt"' ); done_testing(); Mojolicious-Plugin-RenderFile-0.12/t/sample.txt0000755000000000000000000000002013161667265020174 0ustar rootrootfile to downloadMojolicious-Plugin-RenderFile-0.12/t/basic.t0000755000000000000000000000637513161667265017443 0ustar rootrootuse Mojo::Base -strict; use Test::More; use Mojolicious::Lite; use Test::Mojo; use lib '../lib'; use File::Basename qw/dirname/; use File::Spec::Functions qw/rel2abs/; my $FILE = rel2abs( dirname(__FILE__) . '/' . 'sample.txt' ); plugin 'RenderFile'; get '/default' => sub { my $self = shift; $self->render_file( filepath => $FILE ); }; get '/data' => sub { my $self = shift; $self->render_file( data => 'data to download', filename => 'sample.txt' ); }; get '/data/custom_content_type' => sub { my $self = shift; $self->render_file( data => 'data to download', filename => 'sample.txt', content_type => 'application/pdf' ); }; get '/data/no_filename' => sub { my $self = shift; $self->render_file( data => 'data to download' ); }; get '/all_attrs' => sub { my $self = shift; $self->render_file( filepath => $FILE, filename => 'mysample.txt', status => 201, format => 'pdf', content_disposition => 'inline' ); }; my $t = Test::Mojo->new; $t->get_ok('/default') ->status_is(200) ->content_is('file to download') ->content_type_is('application/x-download;name="sample.txt"') ->header_is( 'Content-Disposition' => 'attachment;filename="sample.txt"' ); $t->get_ok('/all_attrs') ->status_is(201) ->content_is('file to download') ->content_type_is('application/pdf;name="mysample.txt"') ->header_is( 'Content-Disposition' => 'inline;filename="mysample.txt"' ); $t->get_ok('/default' => { 'Range' => 'bytes=5-' }) ->status_is(206) ->content_is('to download') ->content_type_is('application/x-download;name="sample.txt"') ->header_is( 'Content-Disposition' => 'attachment;filename="sample.txt"' ); $t->get_ok('/default' => { 'Range' => 'bytes=5-6' }) ->status_is(206) ->content_is('to') ->content_type_is('application/x-download;name="sample.txt"') ->header_is( 'Content-Disposition' => 'attachment;filename="sample.txt"' ); $t->get_ok('/default' => { 'Range' => 'bytes=17-3' }) ->status_is(416); $t->get_ok('/data') ->status_is(200) ->content_is('data to download') ->content_type_is('application/x-download;name="sample.txt"') ->header_is( 'Content-Disposition' => 'attachment;filename="sample.txt"' ); $t->get_ok('/data' => { 'Range' => 'bytes=5-' }) ->status_is(206) ->content_is('to download') ->content_type_is('application/x-download;name="sample.txt"') ->header_is( 'Content-Disposition' => 'attachment;filename="sample.txt"' ); $t->get_ok('/data' => { 'Range' => 'bytes=5-6' }) ->status_is(206) ->content_is('to') ->content_type_is('application/x-download;name="sample.txt"') ->header_is( 'Content-Disposition' => 'attachment;filename="sample.txt"' ); $t->get_ok('/data/custom_content_type' => { 'Range' => 'bytes=5-6' }) ->status_is(206) ->content_is('to') ->content_type_is('application/pdf;name="sample.txt"') ->header_is( 'Content-Disposition' => 'attachment;filename="sample.txt"' ); $t->get_ok('/data/no_filename') ->status_is(200) ->content_is('data to download') ->content_type_is('application/x-download;name="no_filename"') ->header_is( 'Content-Disposition' => 'attachment;filename="no_filename"' ); done_testing(); Mojolicious-Plugin-RenderFile-0.12/t/unicode.txt0000755000000000000000000000010213161667265020342 0ustar rootroot漢字(かんじ)は、古代中国に発祥を持つ文字。Mojolicious-Plugin-RenderFile-0.12/Changes0000755000000000000000000000135613161670251017204 0ustar rootrootRevision history for Mojolicious::Plugin::RenderFile 0.01 First version, released on an unsuspecting world. 0.02 Fixed POD 0.03 Added byte range support (Akron) 0.04 Added "content_type" support and "content_disposition" options 0.04 Replaced "content_type" option with "format" option. Added "data" option 0.06 Multibyte filenames support. Updated Mojolicious version dependency to 3.90 0.07 Added license Fixed utf8 filename issue 0.08 File cleanup support 0.09 Not loose previously setted headers 0.10 Do not include unicode in distro 0.11 Add "content_type" option 0.12 Fix warning about content_type and format incompatiblity Mojolicious-Plugin-RenderFile-0.12/README.pod0000755000000000000000000000656313161667265017372 0ustar rootroot=head1 NAME Mojolicious::Plugin::RenderFile - "render_file" helper for Mojolicious =head1 SYNOPSIS # Mojolicious $self->plugin('RenderFile'); # Mojolicious::Lite plugin 'RenderFile'; # In controller $self->render_file('filepath' => '/tmp/files/file.pdf'); # file name will be "file.pdf" # Provide any file name $self->render_file('filepath' => '/tmp/files/file.pdf', 'filename' => 'report.pdf'); # Render data from memory as file $self->render_file('data' => 'some data here', 'filename' => 'report.pdf'); # Open file in browser(do not show save dialog) $self->render_file( 'filepath' => '/tmp/files/file.pdf', 'format' => 'pdf', # will change Content-Type "application/x-download" to "application/pdf" 'content_disposition' => 'inline', # will change Content-Disposition from "attachment" to "inline" 'cleanup' => 1, # delete file after completed ); =head1 DESCRIPTION L is a L plugin that adds "render_file" helper. It does not read file in memory and just streaming it to a client. =head1 HELPERS =head2 C $self->render_file(filepath => '/tmp/files/file.pdf', 'filename' => 'report.pdf' ); With this helper you can easily provide files for download. By default "Content-Type" header is "application/x-download" and "content_disposition" option value is "attachment". Therefore, a browser will ask where to save file. You can provide "format" option to change "Content-Type" header. =head3 Supported Options: =over =item C Path on the filesystem to the file. You must always pass "filepath" or "data" option =item C Binary content which will be transfered to browser. You must always pass "filepath" or "data" option =item C (optional) Browser will use this name for saving the file =item C (optional) The "Content-Type" header is based on the MIME type mapping of the "format" option value. These mappings can be easily extended or changed with L. By default "Content-Type" header is "application/x-download" You cannot pass both the "format" and the "content_type" option, as they are mutually exclusive. =item C (optional) With this option, the "Content-Type" can be set directly. By default "Content-Type" header is "application/x-download" You cannot pass both the "format" and the "content_type" option, as they are mutually exclusive. =item C (optional) Tells browser how to present the file. "attachment" (default) - is for dowloading "inline" - is for showing file inline =item C (optional) Indicates if the file should be deleted when rendering is complete =back This plugin respects HTTP Range headers. =head1 AUTHOR Viktor Turskyi =head1 CONTRIBUTORS Nils Diewald (Akron) =head1 BUGS Please report any bugs or feature requests to Github L =head1 SEE ALSO L, L, L. Copyright 2011 Viktor Turskyi This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License. See http://dev.perl.org/licenses/ for more information. =cut Mojolicious-Plugin-RenderFile-0.12/META.json0000755000000000000000000000202313161670360017323 0ustar rootroot{ "abstract" : "unknown", "author" : [ "Viktor Turskyi " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Mojolicious-Plugin-RenderFile", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Mojolicious" : "5.78", "perl" : "5.01" } } }, "release_status" : "stable", "resources" : { "repository" : { "url" : "https://github.com/koorchik/Mojolicious-Plugin-RenderFile" } }, "version" : "0.12" } Mojolicious-Plugin-RenderFile-0.12/MANIFEST0000755000000000000000000000046113161670361017040 0ustar rootrootChanges MANIFEST Makefile.PL README.pod lib/Mojolicious/Plugin/RenderFile.pm t/basic.t t/sample.txt t/multibyte_filename.t t/unicode.txt META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Mojolicious-Plugin-RenderFile-0.12/Makefile.PL0000755000000000000000000000103413161667265017667 0ustar rootrootuse strict; use warnings; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Mojolicious::Plugin::RenderFile', VERSION_FROM => 'lib/Mojolicious/Plugin/RenderFile.pm', AUTHOR => 'Viktor Turskyi ', MIN_PERL_VERSION => 5.010, PREREQ_PM => { 'Mojolicious' => '5.78' }, META_MERGE => { resources => { repository => 'https://github.com/koorchik/Mojolicious-Plugin-RenderFile', }, }, test => { TESTS => 't/*.t' }, ); Mojolicious-Plugin-RenderFile-0.12/lib/0000755000000000000000000000000013161670357016456 5ustar rootrootMojolicious-Plugin-RenderFile-0.12/lib/Mojolicious/0000755000000000000000000000000013161670357020752 5ustar rootrootMojolicious-Plugin-RenderFile-0.12/lib/Mojolicious/Plugin/0000755000000000000000000000000013161670357022210 5ustar rootrootMojolicious-Plugin-RenderFile-0.12/lib/Mojolicious/Plugin/RenderFile.pm0000755000000000000000000001452513161670167024576 0ustar rootrootpackage Mojolicious::Plugin::RenderFile; use Mojo::Base 'Mojolicious::Plugin'; use strict; use warnings; use File::Basename; use Encode qw( encode decode_utf8 ); use Mojo::Util 'quote'; our $VERSION = '0.12'; sub register { my ( $self, $app ) = @_; $app->helper( 'render_file' => sub { my $c = shift; my %args = @_; utf8::decode($args{filename}) if $args{filename} && !utf8::is_utf8($args{filename}); utf8::decode($args{filepath}) if $args{filepath} && !utf8::is_utf8($args{filepath}); my $filename = $args{filename}; my $status = $args{status} || 200; my $content_disposition = $args{content_disposition} || 'attachment'; my $cleanup = $args{cleanup} // 0; # Content type based on format if ($args{format} && $args{content_type}) { $c->app->log->error('You cannot provide both "format" and "content_type" option'); return; } my $content_type = $args{content_type}; $content_type ||= $c->app->types->type( $args{format} ) if $args{format}; $content_type ||= 'application/x-download'; # Create asset my $asset; if ( my $filepath = $args{filepath} ) { unless ( -f $filepath && -r $filepath ) { $c->app->log->error("Cannot read file [$filepath]. error [$!]"); return; } $filename ||= fileparse($filepath); $asset = Mojo::Asset::File->new( path => $filepath ); $asset->cleanup($cleanup); } elsif ( $args{data} ) { $filename ||= $c->req->url->path->parts->[-1] || 'download'; $asset = Mojo::Asset::Memory->new(); $asset->add_chunk( $args{data} ); } else { $c->app->log->error('You must provide "data" or "filepath" option'); return; } # Set response headers my $headers = $c->res->content->headers(); $filename = quote($filename); # quote the filename, per RFC 5987 $filename = encode("UTF-8", $filename); $headers->add( 'Content-Type', $content_type . ';name=' . $filename ); $headers->add( 'Content-Disposition', $content_disposition . ';filename=' . $filename ); # Range # Partially based on Mojolicious::Static if ( my $range = $c->req->headers->range ) { my $start = 0; my $size = $asset->size; my $end = $size - 1 >= 0 ? $size - 1 : 0; # Check range if ( $range =~ m/^bytes=(\d+)-(\d+)?/ && $1 <= $end ) { $start = $1; $end = $2 if defined $2 && $2 <= $end; $status = 206; $headers->add( 'Content-Length' => $end - $start + 1 ); $headers->add( 'Content-Range' => "bytes $start-$end/$size" ); } else { # Not satisfiable return $c->rendered(416); } # Set range for asset $asset->start_range($start)->end_range($end); } else { $headers->add( 'Content-Length' => $asset->size ); } # Stream content directly from file $c->res->content->asset($asset); return $c->rendered($status); } ); } 1; =head1 NAME Mojolicious::Plugin::RenderFile - "render_file" helper for Mojolicious =head1 SYNOPSIS # Mojolicious $self->plugin('RenderFile'); # Mojolicious::Lite plugin 'RenderFile'; # In controller $self->render_file('filepath' => '/tmp/files/file.pdf'); # file name will be "file.pdf" # Provide any file name $self->render_file('filepath' => '/tmp/files/file.pdf', 'filename' => 'report.pdf'); # Render data from memory as file $self->render_file('data' => 'some data here', 'filename' => 'report.pdf'); # Open file in browser(do not show save dialog) $self->render_file( 'filepath' => '/tmp/files/file.pdf', 'format' => 'pdf', # will change Content-Type "application/x-download" to "application/pdf" 'content_disposition' => 'inline', # will change Content-Disposition from "attachment" to "inline" 'cleanup' => 1, # delete file after completed ); =head1 DESCRIPTION L is a L plugin that adds "render_file" helper. It does not read file in memory and just streaming it to a client. =head1 HELPERS =head2 C $self->render_file(filepath => '/tmp/files/file.pdf', 'filename' => 'report.pdf' ); With this helper you can easily provide files for download. By default "Content-Type" header is "application/x-download" and "content_disposition" option value is "attachment". Therefore, a browser will ask where to save file. You can provide "format" option to change "Content-Type" header. =head3 Supported Options: =over =item C Path on the filesystem to the file. You must always pass "filepath" or "data" option =item C Binary content which will be transferred to browser. You must always pass "filepath" or "data" option =item C (optional) Browser will use this name for saving the file =item C (optional) The "Content-Type" header is based on the MIME type mapping of the "format" option value. These mappings can be easily extended or changed with L. By default "Content-Type" header is "application/x-download" =item C (optional) Tells browser how to present the file. "attachment" (default) - is for dowloading "inline" - is for showing file inline =item C (optional) Indicates if the file should be deleted when rendering is complete =back This plugin respects HTTP Range headers. =head1 AUTHOR Viktor Turskyi =head1 CONTRIBUTORS Nils Diewald (Akron) Danil Greben (SDSWanderer) =head1 BUGS Please report any bugs or feature requests to Github L =head1 SEE ALSO L, L, L. Copyright 2011 Viktor Turskyi This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License. See http://dev.perl.org/licenses/ for more information. =cut Mojolicious-Plugin-RenderFile-0.12/META.yml0000755000000000000000000000113113161670360017152 0ustar rootroot--- abstract: unknown author: - 'Viktor Turskyi ' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Mojolicious-Plugin-RenderFile no_index: directory: - t - inc requires: Mojolicious: '5.78' perl: '5.01' resources: repository: https://github.com/koorchik/Mojolicious-Plugin-RenderFile version: '0.12'