changes so that we skip encoding under programmatic situations
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Request / Upload.pm
CommitLineData
146554c5 1package Catalyst::Request::Upload;
2
e5ecd5bc 3use Moose;
531f1ab6 4with 'MooseX::Emulate::Class::Accessor::Fast';
146554c5 5
a2f2cde9 6use Catalyst::Exception;
47ae6960 7use File::Copy ();
89cb63ec 8use IO::File ();
3e22baa5 9use File::Spec::Unix;
554c7587 10use namespace::clean -except => 'meta';
146554c5 11
5fb12dbb 12has filename => (is => 'rw');
13has headers => (is => 'rw');
14has size => (is => 'rw');
15has tempname => (is => 'rw');
16has type => (is => 'rw');
02570318 17has basename => (is => 'ro', lazy_build => 1);
6adc45cf 18has raw_basename => (is => 'ro', lazy_build => 1);
19has charset => (is=>'ro', predicate=>'has_charset');
059c085b 20
21has fh => (
22 is => 'rw',
23 required => 1,
24 lazy => 1,
25 default => sub {
26 my $self = shift;
27
28 my $fh = IO::File->new($self->tempname, IO::File::O_RDONLY);
29 unless ( defined $fh ) {
30 my $filename = $self->tempname;
31 Catalyst::Exception->throw(
32 message => qq/Can't open '$filename': '$!'/ );
33 }
059c085b 34 return $fh;
35 },
36);
37
02570318 38sub _build_basename {
6adc45cf 39 my $basename = shift->raw_basename;
40 $basename =~ s|[^\w\.-]+|_|g;
41 return $basename;
42}
43
44sub _build_raw_basename {
02570318 45 my $self = shift;
46 my $basename = $self->filename;
47 $basename =~ s|\\|/|g;
48 $basename = ( File::Spec::Unix->splitpath($basename) )[2];
02570318 49 return $basename;
50}
51
059c085b 52no Moose;
146554c5 53
965f3e35 54=for stopwords uploadtmp
55
146554c5 56=head1 NAME
57
bab3a22c 58Catalyst::Request::Upload - handles file upload requests
146554c5 59
60=head1 SYNOPSIS
61
33455c7e 62 my $upload = $c->req->upload('field');
63
3e22baa5 64 $upload->basename;
bab3a22c 65 $upload->copy_to;
66 $upload->fh;
6adc45cf 67 $upload->decoded_fh
146554c5 68 $upload->filename;
4be535b1 69 $upload->headers;
3ffaf022 70 $upload->link_to;
146554c5 71 $upload->size;
32d4bba8 72 $upload->slurp;
6adc45cf 73 $upload->decoded_slurp;
146554c5 74 $upload->tempname;
75 $upload->type;
6adc45cf 76 $upload->charset;
146554c5 77
7257e9db 78To specify where Catalyst should put the temporary files, set the 'uploadtmp'
79option in the Catalyst config. If unset, Catalyst will use the system temp dir.
80
81 __PACKAGE__->config( uploadtmp => '/path/to/tmpdir' );
82
146554c5 83See also L<Catalyst>.
84
85=head1 DESCRIPTION
86
bab3a22c 87This class provides accessors and methods to handle client upload requests.
146554c5 88
89=head1 METHODS
90
b5ecfcf0 91=head2 $upload->new
cd3bb248 92
bab3a22c 93Simple constructor.
cd3bb248 94
b5ecfcf0 95=head2 $upload->copy_to
47ae6960 96
bab3a22c 97Copies the temporary file using L<File::Copy>. Returns true for success,
98false for failure.
47ae6960 99
3ffaf022 100 $upload->copy_to('/path/to/target');
101
47ae6960 102=cut
103
3ffaf022 104sub copy_to {
c462faf0 105 my $self = shift;
106 return File::Copy::copy( $self->tempname, @_ );
47ae6960 107}
108
6adc45cf 109=head2 $upload->is_utf8_encoded
110
111Returns true of the upload defines a character set at that value is 'UTF-8'.
112This does not try to inspect your upload and make any guesses if the Content
113Type charset is undefined.
114
115=cut
116
117sub is_utf8_encoded {
118 my $self = shift;
119 if(my $charset = $self->charset) {
120 return $charset eq 'UTF-8' ? 1 : 0;
121 }
122 return 0;
123}
124
b5ecfcf0 125=head2 $upload->fh
146554c5 126
bab3a22c 127Opens a temporary file (see tempname below) and returns an L<IO::File> handle.
146554c5 128
6adc45cf 129This is a filehandle that is opened with no additional IO Layers.
130
131=head2 $upload->decoded_fh(?$encoding)
132
133Returns a filehandle that has binmode set to UTF-8 if a UTF-8 character set
134is found. This also accepts an override encoding value that you can use to
135force a particular L<PerlIO> layer. If neither are found the filehandle is
136set to :raw.
137
138This is useful if you are pulling the file into code and inspecting bit and
139maybe then sending those bits back as the response. (Please not this is not
140a suitable filehandle to set in the body; use C<fh> if you are doing that).
141
142Please note that using this method sets the underlying filehandle IO layer
143so once you use this method if you go back and use the C<fh> method you
144still get the IO layer applied.
145
146=cut
147
148sub decoded_fh {
149 my ($self, $layer) = @_;
150 my $fh = $self->fh;
151
152 $layer = ":encoding(UTF-8)" if !$layer && $self->is_utf8_encoded;
153 $layer = ':raw' unless $layer;
154
155 binmode($fh, $layer);
156 return $fh;
157}
158
b5ecfcf0 159=head2 $upload->filename
146554c5 160
bab3a22c 161Returns the client-supplied filename.
146554c5 162
b5ecfcf0 163=head2 $upload->headers
4be535b1 164
bab3a22c 165Returns an L<HTTP::Headers> object for the request.
4be535b1 166
b5ecfcf0 167=head2 $upload->link_to
146554c5 168
b0ad47c1 169Creates a hard link to the temporary file. Returns true for success,
bab3a22c 170false for failure.
146554c5 171
3ffaf022 172 $upload->link_to('/path/to/target');
146554c5 173
174=cut
175
3ffaf022 176sub link_to {
47ae6960 177 my ( $self, $target ) = @_;
5c0ff128 178 return CORE::link( $self->tempname, $target );
146554c5 179}
180
b5ecfcf0 181=head2 $upload->size
146554c5 182
bab3a22c 183Returns the size of the uploaded file in bytes.
146554c5 184
6adc45cf 185=head2 $upload->slurp(?$encoding)
186
187Optionally accepts an argument to define an IO Layer (which is applied to
188the filehandle via binmode; if no layer is defined the default is set to
189":raw".
32d4bba8 190
bab3a22c 191Returns a scalar containing the contents of the temporary file.
32d4bba8 192
965f3e35 193Note that this will cause the filehandle pointed to by C<< $upload->fh >> to
194be reset to the start of the file using seek and the file handle to be put
6adc45cf 195into whatever encoding mode is applied.
0fd00e7b 196
32d4bba8 197=cut
198
199sub slurp {
200 my ( $self, $layer ) = @_;
201
4be535b1 202 unless ($layer) {
32d4bba8 203 $layer = ':raw';
204 }
205
206 my $content = undef;
207 my $handle = $self->fh;
208
209 binmode( $handle, $layer );
210
89cb63ec 211 $handle->seek(0, IO::File::SEEK_SET);
32d4bba8 212 while ( $handle->sysread( my $buffer, 8192 ) ) {
213 $content .= $buffer;
214 }
215
89cb63ec 216 $handle->seek(0, IO::File::SEEK_SET);
32d4bba8 217 return $content;
218}
219
6adc45cf 220=head2 $upload->decoded_slurp(?$encoding)
221
222Works just like C<slurp> except we use C<decoded_fh> instead of C<fh> to
223open a filehandle to slurp. This means if your upload charset is UTF8
224we binmode the filehandle to that encoding.
225
226=cut
227
228sub decoded_slurp {
229 my ( $self, $layer ) = @_;
230 my $handle = $self->decoded_fh($layer);
231
232 my $content = undef;
233 $handle->seek(0, IO::File::SEEK_SET);
234 while ( $handle->sysread( my $buffer, 8192 ) ) {
235 $content .= $buffer;
236 }
237
238 $handle->seek(0, IO::File::SEEK_SET);
239 return $content;
240}
241
3e22baa5 242=head2 $upload->basename
243
6adc45cf 244Returns basename for C<filename>. This filters the name through a regexp
245C<basename =~ s|[^\w\.-]+|_|g> to make it safe for filesystems that don't
246like advanced characters. This will of course filter UTF8 characters.
247If you need the exact basename unfiltered use C<raw_basename>.
248
249=head2 $upload->raw_basename
250
251Just like C<basename> but without filtering the filename for characters that
252don't always write to a filesystem.
3e22baa5 253
b5ecfcf0 254=head2 $upload->tempname
146554c5 255
bab3a22c 256Returns the path to the temporary file.
146554c5 257
b5ecfcf0 258=head2 $upload->type
146554c5 259
bab3a22c 260Returns the client-supplied Content-Type.
146554c5 261
6adc45cf 262=head2 $upload->charset
263
264The character set information part of the content type, if any. Useful if you
265need to figure out any encodings on the file upload.
266
059c085b 267=head2 meta
268
269Provided by Moose
270
bab3a22c 271=head1 AUTHORS
146554c5 272
2f381252 273Catalyst Contributors, see Catalyst.pm
146554c5 274
275=head1 COPYRIGHT
276
536bee89 277This library is free software. You can redistribute it and/or modify
146554c5 278it under the same terms as Perl itself.
279
280=cut
281
e5ecd5bc 282__PACKAGE__->meta->make_immutable;
283
146554c5 2841;