NAME
HTTP::Upload::FlowJs::Examples - examples for HTTP::Upload::FlowJs
Pure PSGI example
This is a verbose example that assumes a PSGI / Plack environment and some helper routines to handle the payload of POST parameters.
ASSUMPTIONS
It is assumed in the below code that your HTTP framework implements some routines to retrieve information about the current request:
sub params() {
# return request parameters, both GET and POST parameters
# as a hash reference
}
sub upload {
# return something like a file system object to retrieve the content
# of a file upload parameter
}
SETUP
use HTTP::Upload::FlowJs;
my @parameter_names = (
'file', # The name of the file
'flowChunkNumber', # The index of the chunk in the current upload.
# First chunk is 1 (no base-0 counting here).
'flowTotalChunks', # The total number of chunks.
'flowCurrentChunkSize', # Current chunk size
'flowChunkSize', # The general chunk size. Using this value and
# flowTotalSize you can calculate the total number of
# chunks. Please note that the size of the data received in
# the HTTP might be lower than flowChunkSize of this for
# the last chunk for a file.
'flowTotalSize', # The total file size.
'flowIdentifier', # A unique identifier for the file contained in the request.
'flowFilename', # The original file name (since a bug in Firefox results in
# the file name not being transmitted in chunk
# multipart posts).
'flowRelativePath', # The file's relative path when selecting a directory
# (defaults to file name in all browsers except Chrome).
);
my $uploads = '/tmp/flowjs_uploads/';
my $flowjs = HTTP::Upload::FlowJs->new(
incomingDirectory => $uploads,
allowedContentType => sub { $_[0] =~ m!^image/! },
parameter_names => \@parameter_names, # to override the default names
);
POST handler
Your handler for POST requests is where you have to validate and store a received chunk. This is also where you determine whether a file was received completely and hand it off for further processing.
sub POST_upload {
my $params = params();
my %info;
@info{ @parameter_names } = @{$params}{@parameter_names};
$info{ localChunkSize } = -s $params{ file };
# or however you get the size of the uploaded chunk
# you might want to set this so users don't clobber each others upload
my $session_id = '';
my @invalid = $flowjs->validateRequest( 'POST', \%info, $session_id );
if( @invalid ) {
warn 'Invalid flow.js upload request:';
warn $_ for @invalid;
return [500,[],["Invalid request"]];
return;
};
if( $flowjs->disallowedContentType( \%info, $session_id )) {
# We can determine the content type, and it's not an image
return [415,[],["File type disallowed"]];
};
my $chunkname = $flowjs->chunkName( \%info, undef );
# Save or copy the uploaded file
upload('file')->copy_to($chunkname);
# Now check if we have received all chunks of the file
if( $flowjs->uploadComplete( \%info, undef )) {
# Combine all chunks to final name
my $digest = Digest::SHA256->new();
my( $content_type, $ext ) = $flowjs->sniffContentType();
my $final_name = "file1.$ext";
open( my $fh, '>', $final_name )
or die $!;
binmode $fh;
my( $ok, @unlink_chunks )
= $flowjs->combineChunks( \%info, undef, $fh, $digest );
unlink @unlink_chunks;
# Notify backend that a file arrived
print sprintf "File '%s' upload complete\n", $final_name;
};
# Signal OK
return [200,[],[]]
};
GET handler
The GET handler is used by the Javascript code to retrieve information about whether a chunk already has been uploaded or not.
sub GET_upload {
my $params = params();
my %info;
@info{ @parameter_names} = @{$params}{@parameter_names};
my $flowjs = HTTP::Upload::FlowJs->new(
incomingDirectory => $uploads,
allowedContentType => sub { $_[0] =~ m!^image/! },
);
my @invalid = $flowjs->validateRequest( 'GET', \%info, session->{connid} );
if( @invalid ) {
warn 'Invalid flow.js upload request:';
warn $_ for @invalid;
return [500, [], [] ];
} elsif( $flowjs->disallowedContentType( \%info, $session_id)) {
# We can determine the content type, and it's not an image
return [415,[],["File type disallowed"]];
} else {
my( $status, @messages )
= $flowjs->chunkOK( $uploads, \%info, $session_id );
if( $status != 500 ) {
# 200 or 416
return [$status, [], [] ];
} else {
warn $_ for @messages;
return [$status, [], [] ];
};
};
};