Apache-UploadMeter

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

###
0.15 : Dec  12, 2001 - Improved configuration code to auto-detect namespace (for possible future subclassing)
###
0.16a: Jan  08, 2002 -  Added basic JIT handlers to configuration
###
0.17 : Jan  13, 2002 - Cleaned up some more code and documentation - seems beta-able
###
UploadMeter_port.patch:  Adds the port number to the generated Refresh URL

UploadMeter_finished.patch:  Stops the Meter from Refreshing endlessly
when the upload is complete

UploadMeter_starttime.patch:  Adds the time the upload started to the
output to allow upload rate calculations

(Patches submitted by Cees Hek <cees@sitesuite.org>)
###
XSLT + XML Patch submitted by Cees Hek <cees@sitesuite.org>
Started migrating internal calculations to XSLT
Updated Schema (switch from DTD to xsd)
###
0.21 : Feb   3, 2002 - Prebundled "basic" skin on sourceforge.  Migrate from DTD to schema.  Time/Date formatting currently server-side.
###
0.22 : Feb   4, 2002 - Fixed incorrect XSLT address.
###
0.99_03 : Jan  22, 2007
* Ported to Apache2/mod_perl2
* Fixed logging utilities to use internal log_level instead of our own $DEBUG level
* Get rid of function prototypes
* Use closure to pass $hook_data
* Use output filter instead of legacy Apache::SSI
* Doc changes
* Added normal configuration
* Added simple test suite (tests sample upload handler, but not meter)
(Developer release - unstable API)
###
0.99_05 : Jan  23, 2007
* Fix XSLT URL
* Fix output filter
* Fix popup window
###
0.99_12 : Jan  23, 2007
* Added needed use for Apache2::Connection and APR::Pool
* Use handlers to serve XSL/XSD files

META.yml  view on Meta::CPAN

--- #YAML:1.0
name:                Apache-UploadMeter
version:             0.9915
abstract:            Apache module which implements an upload meter for form-based uploads
license:             ~
generated_by:        ExtUtils::MakeMaker version 6.31
distribution_type:   module
requires:     
    Apache2::Request:              2.08
    Cache::Cache:                  0.09
    Date::Format:                  0.01
    mod_perl2:                     2.000003
    Number::Format:                0.01
meta-spec:

javascript.pod  view on Meta::CPAN

    UploadMeter.Responders.register({
        onCreate: function (meter) {
            Element.update(meter.desc, "Please wait...");
        }
    });
    
    // Create a new UploadMeter
    var um = new UploadMeter(el, meter_id, meter_url, {
        // Callback to be executed every time we get a status update
        onUpdate: function (status, last) {
            Element.update('file', "Now uploading: " + status.filename);
            Element.update('bytes', status.seen + "/" + status.total + "  bytes transfered (" + Util.formatDec(status.currentrate) + " bytes/sec)");
            Element.update('time', Util.formatTime(status.elapsed) + " elapsed (" + Util.formatTime(status.remaining) + " remaining)"); 
        },
        onFinished: function(status, last) {
        // Callback to be executed when we've detected a complete upload and stop the meter
            Element.show('closeme');
        }
    });
    
    // Start our uploadmeter - only do this once the corresponding upload has started (or is about to start)
    um.start();
    
    // Stop (or pause) a previouslky start()ed meter
    um.stop();
    
    // Un-register the default pop-up window behavior 
    Event.stopObserving(aum_el, 'submit', aum_popup);

=head1 DESCRIPTION

javascript.pod  view on Meta::CPAN


Although we aim to give maximum customizability, in order to keep a balance between
ease of initial set-up and basic usage, and customizability, the built-in UploadMeter
includes JS code and CSS rules for a simple graphical progress-bar.  At the
current moment, the constructor for the UploadMeter object requires a reference
to a DOM node as one of the parameters, to be used as the base for creating this
progress bar.  If you don't want to use the built-in progress-bar, but also don't
want to muck with the UploadMeter object to get around this, just create an empty
DIV on your page, set the style to hidden (eg, display: none), and pass that to
the UploadMeter object.  If you do wish to use this built-in object, ensure that
the CSS class of this div is "uploadmeter" (and don't hide it!)

Also, it is worth noting that the default behavior looks for an element class
named "uploadform" and attempts to add to the onSubmit code for it, to trigger
the bundled default pop-up window.  If you don't want this to happen, just run:

C<Event.stopObserving(aum_el, 'submit', aum_popup);>


=head1 API Documentation

=head3 UploadMeter Object

This is where most of the action happens.  The public interface to this object

javascript.pod  view on Meta::CPAN


=over

=item *
UploadMeter(I<Element>, I<Meter-Id>, I<Meter-URL>, I<options>)

This is the default constructor for a new UploadMeter instance.  It accepts 3
mandatory parameters and a hash of additional options.  The first parameter,
I<Element> is a DIV element under which to create a graphical progress-bar (see
L<DOM, JavaScript and Cascading StyleSheet rules> above).  The second parameter
is the unique identifier of the uploadmeter data you wish to use.  If you're using
MeterType JSON, this will be embedded in your JavaScript as I<meter_id>.  The
third parameter is the URL of the meter-status URL.  If you're using
MeterType JSON, this will be embedded in your JavaScript as I<meter_url>.

The final parameter is a hash of additional optional configuration directives and
callback routines.

=over

=item *

javascript.pod  view on Meta::CPAN

While this will likely eventually be fixed, as of the time of writing, it's not.

=back

=item *
Callback routines

The callback routines all contain zero, one or two parameters.  The parameter
order will always be I<status>, I<last>.

I<status> contains the current status of the upload.  I<last> always contains
the B<previous> status of the uploadmeter, such that on a repeating callback
such as onUpdate, the value of any given request's I<last> will always be the
same as the previous callback's I<status>.

The parameters contain the following information:

=over

=item *
meter_id

Contains the meter_id for the current upload

=item *
filename

Contains the filename (as supplied by the client) of the currently uploading file

=item *
finished

Contains a boolean value which will be set to 1 once the upload is complete

=item *
status

=over

=item *
timestamp

Current timestamp from server, as seconds since the epoch

=item * 
start

Timestamp (as seconds since the epoch) when upload was started

=item *
received

Number of bytes received so far

=item *
total

Total number of bytes in the upload (more accurately, of the upload B<request>
including other form information)

=back

=item *
total

This is a shortcut for C<status.total>

=item *
seen

This is a shortcut for C<status.received>

=item *
progress

A value between 0 and 100, representing the percentage of the upload that has
been completed.

=item *
currentrate

The approximate current upload rate (in bytes/second)

=item *
elapsed

The time (in seconds) which has elapsed since the upload started

=item *
remaining

The approximate time (in seconds) remaining in the upload

=back

The callbacks currently available are:

=over

=item *
onCreate(I<>)

javascript.pod  view on Meta::CPAN


=item *
onUpdate(I<status>, I<last>)

This callback is called every time data is updated from meter URL.  It can be
utilized to update other GUI elements, such as is done in the default pop-up.

=item *
onFinished(I<status>, I<last>)

This callback is called after onUpdate if the upload is determined to be complete
(eg, C<tatus.finished == 1>)

=back

=back

=back

=head3 UploadMeter.Responders

In addition to adding handlers to individual UploadMeter objects, as described
above, you can also add global callbacks which will be called for *every* uploadmeter
on the page.  This might be useful, for example, for Web 2.0 applications that
allow for multiple asynchronous uploads in separate requests.  In such a case,
rather than registering identical handlers for each UploadMeter instance,
you can register a single function globally and it will be called for the appropriate
callback for all UploadMeter instances running on the page.

Callbacks that are registered this way will receive, as the first parameter,
the UploadMeter object of the instance which is currently calling into it.

=head3 Util

The Util namespace is not an object, but rather a namespace to group some helper

lib/Apache/UploadMeter.pm  view on Meta::CPAN

my $MaxTime="+900";
my $TIMEOUT=15;

### Handlers
sub hook_handler {
    my $r = shift;
    my $hook_data = shift; # joes says libapreq2 should use perl closures for
                           # implementing $hook_data - who am i to argue?
    ### Upload hook handler
    return sub {
	my ($upload, $new_data)=@_;
	my $len = length($new_data);
        my $hook_cache=new Cache::FileCache(\%cache_options);
        unless ($hook_cache) {
	    $r->log_reason("[Apache::UploadMeter] Could not instantiate FileCache.", __FILE__.__LINE__);
	    return Apache2::Const::DECLINED; 
	}
	my $oldlen=$hook_cache->get($hook_data."len") || 0;
	$len=$len+$oldlen;
	if ($oldlen==0)
	{
	    $r->log->notice("[Apache::UploadMeter] Starting upload $hook_data");
	    $hook_cache->set($hook_data."starttime",time());
	}
        unless ($hook_cache->get($hook_data."name") eq $upload->upload_filename) {
            my $name = $upload->upload_filename;
            $r->log->debug("[Apache::UploadMeter] Updating cache: $hook_data NAME --> $name");
            $hook_cache->set($hook_data."name",$name);
        }
	$r->log->debug("[Apache::UploadMeter] Updating cache: $hook_data LEN --> $len");
        $hook_cache->set($hook_data."len",$len);
        
        if ($r->pnotes("finished_upload")) {
            # Our filter deteced EOS.  Update finished, size == len
            $hook_cache->set($hook_data."size",$len);
        }
    };
}

### Upload meter generator - Master process
sub u_handler
{
    my $r=shift;

lib/Apache/UploadMeter.pm  view on Meta::CPAN

    my $u_id = $req->args('meter_id') || undef;
    return Apache2::Const::HTTP_BAD_REQUEST unless defined($u_id);
    $r->pnotes("u_id" => $u_id);
    # Initialize cache
    my $hook_cache=new Cache::FileCache(\%cache_options);
    unless ($hook_cache) {
	$r->log_reason("[Apache::UploadMeter] Could not instantiate FileCache.", __FILE__.__LINE__);
        return Apache2::Const::SERVER_ERROR; 
    }
    # Initialize apreq
    $req->upload_hook(hook_handler($r, $u_id));
    my $rsize=$r->headers_in->{"Content-Length"};
    $hook_cache->set($u_id."size",$rsize);
    $r->log->notice("[Apache::UploadMeter] Initialized cache for $u_id");
    return Apache2::Const::DECLINED;
}

### Upload meter generator - Slave process
sub um_handler
{
    my $r=shift;

lib/Apache/UploadMeter.pm  view on Meta::CPAN

	    my $count=0;
	    my $i;
	    my $c=$r->connection;
	    for ($i=0;$i<$TIMEOUT;$i++)
	    {
		$len=$hook_cache->get($hook_id."len") || undef;
		if (defined($len)) {
		    $problem=0;
		    last;
		}
		$r->log->info("[Apache::UploadMeter] Waiting for upload cache $hook_id to initialize ($i / $TIMEOUT)...");
		sleep 1;
		last if $c->aborted;
	    }
	}
	if ($problem) {
	    $r->custom_response(Apache2::Const::NOT_FOUND, "This upload meter is either invalid, or has expired.");
            return Apache2::Const::NOT_FOUND;
	}
    }
    my $size=$hook_cache->get($hook_id."size") || "Unknown";
    my $fname=$hook_cache->get($hook_id."name") || "Unknown";
    
    # Get response format.  Favor legacy XML here
    # Reasoning: XML is more portable; that's one of the reasons we support it
    # Although I expect 95% of users to use the JSON response, those same 95%
    # of the users are going to be using the bundled JS code, or forking from

lib/Apache/UploadMeter.pm  view on Meta::CPAN

    $r->no_cache(1); # CRITICAL!  No caching allowed!
    $r->set_last_modified(time());
    $r->err_headers_out->add("Expires" => Apache2::Util::ht_time($r->pool));
    my $digest=Digest::SHA1::sha1_hex(time,(defined $r->subprocess_env('HTTP_HOST') ? $r->subprocess_env('HTTP_HOST') : 0),(defined $r->subprocess_env('HTTP_X_FORWARDED_FOR') ?$r->subprocess_env('HTTP_X_FORWARDED_FOR') : 0 ));
    $r->pnotes("u_id"=>$digest);
    return Apache2::Const::OK;
}

### Support handlers (for debugging)

# Simple response handler for displaying upload information
sub r_handler
{
    my $r=shift;
    my $req = APR::Request::Apache2->handle($r);
    $r->no_cache(1);
    my $uploads=$req->upload;
    $r->content_type('text/plain');
    return Apache2::Const::OK if $r->header_only;
    $r->print("Results:\n");
    while (my ($field, $upload) = each %$uploads) {
	$r->print("Parsed upload field $field:\n\tFilename: ".$upload->upload_filename());
	$r->print("\n\tSize: ".$upload->upload_size()."\n\n");
    }
    $r->print("Done\n");
    return Apache2::Const::OK;
}

### Output filters
sub f_xml_uploadform {
    my ($f, $bb) = @_;
    my $bb_ctx = APR::Brigade->new($f->c->pool, $f->c->bucket_alloc);
    unless ($f->ctx) {
        my $config = $f->r->pnotes("Apache::UploadMeter::Config");
        my $handler = $config->{"UploadHandler"} || undef;
        my $meter = $config->{"UploadMeter"} || undef;
        my $aum_id = $config->{"MeterName"} || undef;
        
        if (!(defined($handler) && defined($aum_id) && defined($meter))) {
              #&& $srv_cfg->{UploadMeter}->{aum_id}->{UploadForm} eq $uri)) {

lib/Apache/UploadMeter.pm  view on Meta::CPAN

	    $f->r->log_error("[Apache::UploadMeter] No u_id in pnotes table. Make sure you ran configure()");
	    $f->remove; # We can't do anything useful anymore
            return Apache2::Const::DECLINED;
	}
        $f->r->log->debug("[Apache::UploadMeter] Initialized XML $aum_id with instance $u_id");
	my $output=<<"EOF";
<script type="text/javascript">
// <![CDATA[
function openUploadMeter()
{
    uploadWindow=window.open(\"${meter}?meter_id=${u_id}\",\"_new\",\"toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=no,resizeable=no,width=450,height=240\");
}
// ]]>
</script>
<noscript>You must use a JavaScript-enabled browser to use this page properly</noscript>
<form action=\"${handler}?hook_id=${u_id}\" method=\"post\" enctype=\"multipart/form-data\" onSubmit=\"openUploadMeter()\">
EOF

	$f->ctx({leftover => undef, output => $output});
    }
  

lib/Apache/UploadMeter.pm  view on Meta::CPAN

            last;
        } elsif ($b->read(my $buf)) {
            my $outbuf = "";
            # We need an output buffer, since we can't copy string data going into buckets
            
            $buf = ${$f->ctx}{leftover}.$buf if defined(${$f->ctx}{leftover});
            while ($buf=~/^(.*?)(<.*?>)(.*)/ms) {
                my ($pre,$tag);
                ($pre,$tag,$buf) = ($1,$2,$3);
                $outbuf.=$pre;
                if ($tag=~/\<\!--\s*?#uploadform\s*?--\>/i) {
                    $tag = ${$f->ctx}{output};
                }                
                $outbuf.=$tag;
            }
            $bb_ctx->insert_tail(APR::Bucket->new($bb_ctx->bucket_alloc, $outbuf));

            ${$f->ctx}{leftover} = $buf || undef;
        } else {
            $bb_ctx->insert_tail($b);
        }
    }
    
    my $rv = $f->next->pass_brigade($bb_ctx);
    return $rv unless $rv == APR::Const::SUCCESS;
    return Apache2::Const::OK;
}

sub f_json_uploadform {
    my ($f, $bb) = @_;
    my $bb_ctx = APR::Brigade->new($f->c->pool, $f->c->bucket_alloc);
    unless ($f->ctx) {
        my $config = $f->r->pnotes("Apache::UploadMeter::Config");
        my $handler = $config->{"UploadHandler"} || undef;
        my $meter = $config->{"UploadMeter"} || undef;
        my $aum_id = $config->{"MeterName"} || undef;
        
        if (!(defined($handler) && defined($aum_id) && defined($meter))) {
              #&& $srv_cfg->{UploadMeter}->{aum_id}->{UploadForm} eq $uri)) {

lib/Apache/UploadMeter.pm  view on Meta::CPAN

        }

        $b->remove;
        $bb->insert_tail($b);
    }

    # If we've seen EOS, update the cache 
    if ($f->ctx) {
        my $req = APR::Request::Apache2->handle($f->r);
        my $u_id=$f->r->pnotes("u_id");
        $f->r->pnotes("finished_upload" => 1);
        my $hook_cache=new Cache::FileCache(\%cache_options);
        unless ($hook_cache) {
            $f->r->log_reason("[Apache::UploadMeter] Could not instantiate FileCache.", __FILE__.__LINE__);
            return Apache2::Const::DECLINED;
        }
        my $size=$hook_cache->get($u_id."size");
        $hook_cache->set($u_id."len",$size);
        $hook_cache->set($u_id."finished",1);
    }
    return Apache2::Const::OK;
}    

# Utility routines

sub __add_version_string {
    my $r = shift;
    $r->err_headers_out->add("X-Powered-By" => "Apache-UploadMeter/$VERSION");
}

sub upload_jit_handler($)
{
    my $r=shift;
    my $config = __lookup_config($r, "UploadHandler");
    unless ($config) {
        $r->log->warn("[Apache::UploadMeter] Couldn't find configuration data for url " . $r->uri);
        return Apache2::Const::DECLINED;
    }
    $r->pnotes("Apache::UploadMeter::Config" => $config);
    __add_version_string($r);
    $r->add_input_filter(\&f_ufu_handler);

lib/Apache/UploadMeter.pm  view on Meta::CPAN

    __add_version_string($r);
    my $config = __lookup_config($r, "UploadForm");
    unless ($config) {
        $r->log->warn("[Apache::UploadMeter] Couldn't find configuration data for url " . $r->uri);
        return Apache2::Const::DECLINED;
    }
    $r->pnotes("Apache::UploadMeter::Config" => $config);
    $r->push_handlers("PerlFixupHandler",\&uf_handler);
    my $format = $config->{'MeterType'};
    if ($format=~/^XML$/i) {
        $r->add_output_filter(\&f_xml_uploadform);
    } elsif ($format=~/^JSON$/i) {
        $r->add_output_filter(\&f_json_uploadform);
    } elsif ($format=~/^NONE$/i) {
        # Do nothing - user-experience will be managed externally
    } else {
        $r->log->warn("[Apache::UploadMeter] Invalid meter type $format");
    }
    return Apache2::Const::DECLINED;
}

sub __lookup_config {
    my $r = shift;

lib/Apache/UploadMeter.pm  view on Meta::CPAN

    
    $self->{'meters'}{$val} = $tmp;
    my ($UH, $UF, $UM, $TYPE) = ($tmp->{UploadHandler},
                                 $tmp->{UploadForm},
                                 $tmp->{UploadMeter},
                                 $tmp->{MeterType},
                                 );
    my $config = <<"EOC";
<Location $UH>
    Options +ExecCGI
    PerlInitHandler Apache::UploadMeter::upload_jit_handler
</Location>
<Location $UF>
    Options +ExecCGI
    PerlInitHandler Apache::UploadMeter::form_jit_handler
</Location>
<Location $UM>
    Options +ExecCGI
    PerlInitHandler Apache::UploadMeter::meter_jit_handler
</Location>
PerlModule Apache::UploadMeter::Resources::XML

lib/Apache/UploadMeter.pm  view on Meta::CPAN

    my ($self, $parms, $val) = @_;
    my $conf = $parms->info;
    die "Error: </UploadMeter> without opening <UploadMeter>";
}

1;
__END__

=head1 NAME

Apache::UploadMeter - Apache module which implements an upload meter for form-based uploads

=head1 SYNOPSIS

XML-based graphical meter
  (in httpd.conf)
  
  PerlLoadModule Apache::UploadMeter
  <UploadMeter MyUploadMeter>
      UploadForm    /form.html
      UploadHandler /perl/upload
      UploadMeter   /perl/meter
      MeterType     XML
  </UploadMeter>

  (in /form.html)
  <!--#uploadform-->
  <INPUT TYPE="FILE" NAME="theFile"/>
  <INPUT TYPE="SUBMIT"/>
  </FORM>

Web 2.0 JS-based graphical meter
  (in httpd.conf)
  
  PerlLoadModule Apache::UploadMeter
  <UploadMeter MyUploadMeter>
      UploadForm    /form.html
      UploadHandler /perl/upload
      UploadMeter   /perl/meter
      MeterType     JSON
  </UploadMeter>

  (in /form.html)
  <FORM ACTION="/perl/upload" ENCTYPE="multipart/form-data" METHOD="POST" class="uploadform">
  <INPUT TYPE="FILE" NAME="theFile"/>
  <INPUT TYPE="SUBMIT"/>
  </FORM>
  
  <DIV class="uploadmeter"></DIV>


=head1 ONLINE DEMO

An online demo of a (fairly) up-to-date version of the progress meter can be seen
at http://uploaddemo.beamartyr.net/  [To conserve bandwidth, this URL won't allow
more than 5MB of uploaded data.  An attempt to upload more than that will cause
the upload to be prematurely canceled, so try to ensure the total size of the
files to be uploaded there is less than 5MB]

=head1 DESCRIPTION

Apache::UploadMeter is a mod_perl module which implements a status-meter/progress-bar
to show realtime progress of uploads done using a form with enctype=multipart/form-data.

The software includes several built-in DHTML widgets to display the progress bar
out-of-the box, or alternatively you can create your own custom widgets.

To use the enclosed JavaScript powered widget, simply modify the E<lt>formE<gt> tag to
include class="uploadform".

To use the XML/XSL powered widget, simply replace the existing opening E<lt>FORME<gt>
tag, with the a special directive E<lt>!--#uploadform--E<gt>.

NOTE: To use this module, mod_perl MUST be built with StackedHandlers enabled.

=head1 CONFIGURATION

Configuration is done in httpd.conf using <UploadMeter> sections which contain
the URLs needed to manipulate each meter.  Currently multiple meters are supported
with the drawback that they must use distinct URLs (eg, you can't have 2 meters
with the same UploadMeter path).

=over

=item *

E<lt>UploadMeter I<MyMeter>E<gt>
Defines a new UploadMeter.  The I<MyMeter> parameter specifies a unique name
for this uploadmeter.  Currently, names are required and must be unique.

In a future version, if no name is given, a unique symbol will be generated
for the meter.

Each UploadMeter section requires at least 2 sub-parameters

=over

=item *
UploadForm

This should point to the URI on the server which contains the upload form with
the special E<lt>!--#uploadform--E<gt> tag.  Note that there should NOT be an
opening E<lt>FORME<gt> tag, but there SHOULD be a closing E<lt>/FORME<gt>
tag on the HTML page.

=item *
UploadHandler

This should point to the target (eg, ACTION) of the upload form.  The target
should already exist and do something useful.

=item *
UploadMeter

This should point to an unused URI on the server. This URI will be used to
provide the progress-meter data.  If legacy XML/XSL mode is used, this will also
provide the actual meter window.

=item *

lib/Apache/UploadMeter.pm  view on Meta::CPAN

=back

=head1 DATA FORMAT

Apache::UploadMeter currently provides 2 types of meters: JavaScript (JSON)
based, and XML-based.  The JSON is the new default; it's sexier, slicker, works
out-of-the-box with modern browsers, and with the magic of AJAX and DHTML, doesn't
even need a popup window.  XML is also still actively supported and is aimed at
users who wish to further customize the user-experience or provide a non-browser
based UploadMeter.  Both JSON and XML provide identical data; a formal XSL schema
can be seen at http://uploaddemo.beamartyr.net/demo/xml/meter/styles/xml/aum.xsd

=head1 BUILT-IN TYPES

Apache::UploadMeter comes pre-bundled with 2 DHTML-based graphical meters that
can be used as-is, or just as reference points for builing your own custom
meters.  Currently the 2 types can be selected by specifying I<JSON> or I<XML> in
the MeterType configuration directive.  Each of these will cause
Apache::UploadMeter to add relevant code to your upload form page.

=head1 CUSTOMIZATION

Additionally, I<NONE> can be specified, which will allow you to customize your
user-experience without using any of the built-in meters.  To use this, you
must define your own widget, and query the UploadMeter URL on your own.

The UploadMeter currently accepts the following parameter:

=over

lib/Apache/UploadMeter.pm  view on Meta::CPAN

format

This determines the data format that the meter will return.  Currently JSON can be
specified to return a JSON structure, otherwise an XML structure will be returned.
See L<DATA FORMAT>, above.

=item *
returned

This is a boolean (0 or 1) value used to help reduce race conditions when a new
upload is initiated.  If it is 0 or not defined, the server will cause the request
to block (for up to 15 seconds by default - overridable by setting
$Apache::UploadMeter::TIMEOUT) until the uploading content is detected by the
server and the meter's datastructure is initialized.  If it is 1, and the
I<meter_id> is not found on the server, a 404 error will be immediately returned.

=back

=head1 COMPATIBILITY

Beginning from version 0.99_01, this module is only compatible with
Apache2/mod_perl2 Support for Apache 1.3.x is discontinued, as it's too damn
complicated to configure in Apache 1.3.x  This may change in the future, but I

lib/Apache/UploadMeter/Resources/CSS.pm  view on Meta::CPAN

use Apache2::RequestIO ();
use Apache2::Response ();
use Apache2::Const -compile=>qw(:common);

sub json_css {
    my $r = shift;
    $r->content_type("text/css");
    $r->set_etag();
    return Apache2::Const::OK if $r->header_only();
    my $output=<<'CSS-END';
.uploadmeter {
    width: 200px;
    height: 1em;
    margin: 2px 0 2px 0;
    display: block;
    border: 1px blue solid;
}
.metercontent {
    text-align:center;
    display:inline;
}

lib/Apache/UploadMeter/Resources/HTML.pm  view on Meta::CPAN

var um;

UploadMeter.Responders.register({
    onCreate: function (meter) {
        Element.update(meter.desc, "Please wait...");
    }
});
    

var rules={
    '.uploadmeter':function(el) {
        um = new UploadMeter(el, meter_id, meter_url, {
            onUpdate: function (status, last) {
                Element.update('file', "Now uploading: " + status.filename);
                Element.update('bytes', status.seen + "/" + status.total + "  bytes transfered (" + Util.formatDec(status.currentrate) + " bytes/sec)");
                Element.update('time', Util.formatTime(status.elapsed) + " elapsed (" + Util.formatTime(status.remaining) + " remaining)"); 
            },
            onFinished: function(status, last) {
                Element.show('closeme');
            }
        });
        um.start();
    }
};
Behaviour.register(rules);

// ]]>
</script>
<title>Upload progress...</title>
</head>
<body>
<h1>Upload Status</h1>
<div class="uploadmeter"></div>
<div id="file" name="file"></div>
<div id="bytes" name="bytes"></div>
<div id="time" name="time"></div>
<input type="button" style="display: none" id="closeme" name="closeme" onclick="window.close()" value="Close window" />
</body>
</html>

EOF
    $r->print($output);
    return Apache2::Const::OK;

lib/Apache/UploadMeter/Resources/JavaScript.pm  view on Meta::CPAN

    ajax: undefined,
    options: {
        delay: 3.0 // Delay in seconds between requests (also almost duration of sliding effect for smoothest exerience)
    },

    // We can't seem to Element.extend our elements in a seperate window...  Dunno why yet
    // but it makes for uglier code :-(

    // Constructor - Parameters are:
    //               el: Outer div to bind widget to
    //               meter: uploadmeter id
    //               url: uploadmeter ajax url
    //               options: additional callbacks, etc
    initialize: function(el, meter, url, options) {
        this.url = url;
        this.meter = meter;
        this.main = $(el);
        Object.extend(this.options, options || {});
        this.desc = Builder.node( "div", {className:'metercontent'});
        this.main.appendChild(this.desc);
        this.desc = $(this.desc);
        Position.absolutize(this.desc);

lib/Apache/UploadMeter/Resources/JavaScript.pm  view on Meta::CPAN

    } catch (e) {}
}

function aum_popup() {
    var aum = window.open(meter_url + "/styles/aum_popup.html" ,"_new","toolbar=no,location=no,directories=no,status=yes,menubar=no,scrollbars=no,resizeable=no,width=450,height=240");
    // Pass our info to the child window's global obj
    Object.extend(aum, {'meter_id': meter_id, 'meter_url': meter_url});
}

var rules={
    '.uploadform':function(el) {
      el.action = addMeterURL(el.action);
      aum_el = $(el); // Put this in a global so we can unregister later, if needed
      Event.observe(aum_el, 'submit', aum_popup);
    }
};
Behaviour.register(rules);

AUM-END
    $r->print($output);
    return Apache2::Const::OK;

t/01load.t  view on Meta::CPAN

use Apache::TestRequest;

plan tests => 2;
# We can't use Apache::UploadMeter, since we can't call Apache2::Module::add from here
ok(1); # If we made it this far, we're ok.

my $file = "MANIFEST";
my $size = -s $file;
my $expected =<<"TEST1";
Results:
Parsed upload field filename:
	Filename: $file
	Size: $size

Done
TEST1

my $data = UPLOAD_BODY "/perl/upload?meter_id=1234", filename => $file;

ok t_cmp(
           $data,
           $expected,
           "simple upload test",
          );

t/conf/extra.conf.in  view on Meta::CPAN

PerlSwitches -I@ServerRoot@/../blib/lib
PerlLoadModule Apache::UploadMeter

<Location /perl/upload>
    SetHandler perl-script
    PerlResponseHandler  Apache::UploadMeter::r_handler
</Location>

<UploadMeter dummy_meter>
    UploadHandler /perl/upload
    UploadMeter   /perl/meter
    UploadForm    /form.html
</UploadMeter>



( run in 1.184 second using v1.01-cache-2.11-cpan-b16cb0d3907 )