This file is indexed.

/usr/share/perl5/Mojolicious/Plugin/RenderFile.pm is in libmojolicious-plugin-renderfile-perl 0.12-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package 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<Mojolicious::Plugin::RenderFile> is a L<Mojolicious> plugin that adds "render_file" helper. It does not read file in memory and just streaming it to a client.

=head1 HELPERS

=head2 C<render_file>

    $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<filepath>

Path on the filesystem to the file. You must always pass "filepath" or "data" option

=item C<data>

Binary content which will be transferred to browser. You must always pass "filepath" or "data" option

=item C<filename> (optional)

Browser will use this name for saving the file

=item C<format> (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<Mojolicious/"types">.

By default "Content-Type" header is "application/x-download"

=item C<content_disposition> (optional)

Tells browser how to present the file.

"attachment" (default) - is for dowloading

"inline" - is for showing file inline

=item C<cleanup> (optional)

Indicates if the file should be deleted when rendering is complete

=back

This plugin respects HTTP Range headers.

=head1 AUTHOR

Viktor Turskyi <koorchik@cpan.org>

=head1 CONTRIBUTORS

Nils Diewald (Akron)
Danil Greben (SDSWanderer)

=head1 BUGS

Please report any bugs or feature requests to Github L<https://github.com/koorchik/Mojolicious-Plugin-RenderFile>

=head1 SEE ALSO

L<Mojolicious>, L<Mojolicious::Guides>, L<http://mojolicio.us>.

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