You are viewing a plain text version of this content. The canonical link for it is here.
Posted to apreq-dev@httpd.apache.org by "Keith C. Perry" <ne...@vcsn.com> on 2004/07/30 09:08:18 UTC

Problem use Apache::Upload

I was hoping someone would be able to point me in the right direction here.  I'm
been wrestling for the last couple of days with creating a simple file upload
page with mod_perl.

After trying to get this going on a 2.0.47 build, I decided to start from
scratch to make sure everything was clean, thus my environment now is:

Apache 2.0.50
mod_perl 1.99_15-dev      (build from CVS)
Apache::Request 2.04-dev  (built from CVS libapreq)


What is happening is that none of the method seem to be found so if I have a
script snippet...

use Apache::Upload;
use strict;

my $r=Apache->request;
my $req = Apache::Request->new($r);
my $upload = $req->upload();
my $fname  = $upload->filename();
my $io = $upload->io();
$r->print while <$io>;


I get error like this for filename() in the server error log...

[Fri Jul 30 02:25:54 2004] [error] Can't locate object method "filename" via
package "Apache::Upload::Table" at /www/local/upload.mpl line 18.


Even when I user mod_perl 1.99_14 and Apache::Request 2-2.03-dev, I get similar
"can't locate object" errors.  There seems to be a number of things on the net
detailing how to do file uploads using the Apache::Request module so I can't
understand why the object just simply aren't there.  BTW, I did not upgrade APR
from cvs, I'm using whatever came with the .50 release of httpd (0.9.5?).


-- 
Keith C. Perry, MS E.E.
Director of Networks & Applications
VCSN, Inc.
http://vcsn.com
 
____________________________________
This email account is being host by:
VCSN, Inc : http://vcsn.com

Re: Problem use Apache::Upload

Posted by "Keith C. Perry" <ne...@vcsn.com>.
Quoting Randy Kobes <ra...@theoryx5.uwinnipeg.ca>:

> On Fri, 30 Jul 2004, Keith C. Perry wrote:
> 
> [ ... ]
> > Now, I tried...
> >
> > my $upload = $req->upload('sentfile');
> > my $fname  = $upload->filename('origname');
> >
> > I get this error...
> >
> > [Fri Jul 30 09:40:12 2004] [error] Can't call method
> > "filename" on an undefined value at /www/local/upload.mpl
> > line 18.\n
> 
> It seems then that $req isn't getting created. I take
> it that this is a ModPerl::Registry script? Here's an
> example for your form
> 
> ==============================================================
> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
>  "http://www.w3.org/TR/html4/loose.dtd">
> <html>
> <head>
> <title>File Upload</title>
> </head>
> <body>
> <form name="uploadform"
>    action="/perl/upload.pl?method=fh;has_md5=1"
>    method="post" enctype="multipart/form-data"><br>
> <input name="sentfile" type="file">
> <input value="Send File" type="submit">
> </form>
> </body>
> </html>
> ==============================================================
> where /perl is handled by ModPerl::Registry, and the script
> upload.pl (adapted from upload.pm in the httpd-apreq-2 test
> in glue/perl/t/response/TestApReq/) takes a "method" arg
> (one of slurp, fh, tempname, link, or io) which chooses
> how you want to handle the upload:
> ===============================================================
> # file upload.pl
> use strict;
> use warnings FATAL => 'all';
> 
> use Apache::RequestRec;
> use Apache::RequestIO;
> use Apache::Request ();
> use Apache::Upload;
> use File::Spec;
> require File::Basename;
> 
> my $r = shift;
> my $req = Apache::Request->new($r);
> my $temp_dir = File::Spec->tmpdir;
> 
> my $method  = $req->args('method');
> my $has_md5  = $req->args('has_md5');
> require Digest::MD5 if $has_md5;
> my $upload = $req->upload('sentfile');
> my $type = $upload->type;
> my $basename = File::Basename::basename($upload->filename);
> my ($data, $fh);
> 
> if ($method eq 'slurp') {
>     $upload->slurp($data);
> }
> elsif ($method eq 'fh') {
>     read $upload->fh, $data, $upload->size;
> }
> elsif ($method eq 'tempname') {
>     my $name = $upload->tempname;
>     open $fh, "<", $name or die "Can't open $name: $!";
>     binmode $fh;
>     read $fh, $data, $upload->size;
>     close $fh;
> }
> elsif ($method eq 'link') {
>     my $link_file = File::Spec->catfile($temp_dir, "linkfile");
>     unlink $link_file if -f $link_file;
>     $upload->link($link_file) or die "Can't link to $link_file: $!";
>     open $fh, "<", $link_file or die "Can't open $link_file: $!";
>     binmode $fh;
>     read $fh, $data, $upload->size;
>     close $fh;
>     unlink $link_file if -f $link_file;
> }
> elsif ($method eq 'io') {
>     read $upload->io, $data, $upload->size;
> }
> else  {
>     die "unknown method: $method";
> }
> 
> my $temp_file = File::Spec->catfile($temp_dir, $basename);
> unlink $temp_file if -f $temp_file;
> open my $wfh, ">", $temp_file or die "Can't open $temp_file: $!";
> binmode $wfh;
> print $wfh $data;
> close $wfh;
> my $cs = $has_md5 ? cs($temp_file) : 0;
> 
> $req->content_type('text/plain');
> my $size = -s $temp_file;
> $r->print(<<END);
> 
> type: $type
> size: $size
> filename: $basename
> md5: $cs
> END
> 
> unlink $temp_file if -f $temp_file;
> 
> sub cs {
>     my $file = shift;
>     open my $fh, '<', $file or die qq{Cannot open "$file": $!};
>     binmode $fh;
>     my $md5 = Digest::MD5->new->addfile($fh)->hexdigest;
>     close $fh;
>     return $md5;
> }
> ===================================================================
> 
> -- 
> best regards,
> randy kobes
> 

Whoa, Randy thanks a lot man.  I'm going to hold onto this script since more
functional.  Much appreciated!

-- 
Keith C. Perry, MS E.E.
Director of Networks & Applications
VCSN, Inc.
http://vcsn.com
 
____________________________________
This email account is being host by:
VCSN, Inc : http://vcsn.com

Re: Problem use Apache::Upload

Posted by Randy Kobes <ra...@theoryx5.uwinnipeg.ca>.
On Fri, 30 Jul 2004, Keith C. Perry wrote:

[ ... ]
> Now, I tried...
>
> my $upload = $req->upload('sentfile');
> my $fname  = $upload->filename('origname');
>
> I get this error...
>
> [Fri Jul 30 09:40:12 2004] [error] Can't call method
> "filename" on an undefined value at /www/local/upload.mpl
> line 18.\n

It seems then that $req isn't getting created. I take
it that this is a ModPerl::Registry script? Here's an
example for your form

==============================================================
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>File Upload</title>
</head>
<body>
<form name="uploadform"
   action="/perl/upload.pl?method=fh;has_md5=1"
   method="post" enctype="multipart/form-data"><br>
<input name="sentfile" type="file">
<input value="Send File" type="submit">
</form>
</body>
</html>
==============================================================
where /perl is handled by ModPerl::Registry, and the script
upload.pl (adapted from upload.pm in the httpd-apreq-2 test
in glue/perl/t/response/TestApReq/) takes a "method" arg
(one of slurp, fh, tempname, link, or io) which chooses
how you want to handle the upload:
===============================================================
# file upload.pl
use strict;
use warnings FATAL => 'all';

use Apache::RequestRec;
use Apache::RequestIO;
use Apache::Request ();
use Apache::Upload;
use File::Spec;
require File::Basename;

my $r = shift;
my $req = Apache::Request->new($r);
my $temp_dir = File::Spec->tmpdir;

my $method  = $req->args('method');
my $has_md5  = $req->args('has_md5');
require Digest::MD5 if $has_md5;
my $upload = $req->upload('sentfile');
my $type = $upload->type;
my $basename = File::Basename::basename($upload->filename);
my ($data, $fh);

if ($method eq 'slurp') {
    $upload->slurp($data);
}
elsif ($method eq 'fh') {
    read $upload->fh, $data, $upload->size;
}
elsif ($method eq 'tempname') {
    my $name = $upload->tempname;
    open $fh, "<", $name or die "Can't open $name: $!";
    binmode $fh;
    read $fh, $data, $upload->size;
    close $fh;
}
elsif ($method eq 'link') {
    my $link_file = File::Spec->catfile($temp_dir, "linkfile");
    unlink $link_file if -f $link_file;
    $upload->link($link_file) or die "Can't link to $link_file: $!";
    open $fh, "<", $link_file or die "Can't open $link_file: $!";
    binmode $fh;
    read $fh, $data, $upload->size;
    close $fh;
    unlink $link_file if -f $link_file;
}
elsif ($method eq 'io') {
    read $upload->io, $data, $upload->size;
}
else  {
    die "unknown method: $method";
}

my $temp_file = File::Spec->catfile($temp_dir, $basename);
unlink $temp_file if -f $temp_file;
open my $wfh, ">", $temp_file or die "Can't open $temp_file: $!";
binmode $wfh;
print $wfh $data;
close $wfh;
my $cs = $has_md5 ? cs($temp_file) : 0;

$req->content_type('text/plain');
my $size = -s $temp_file;
$r->print(<<END);

type: $type
size: $size
filename: $basename
md5: $cs
END

unlink $temp_file if -f $temp_file;

sub cs {
    my $file = shift;
    open my $fh, '<', $file or die qq{Cannot open "$file": $!};
    binmode $fh;
    my $md5 = Digest::MD5->new->addfile($fh)->hexdigest;
    close $fh;
    return $md5;
}
===================================================================

-- 
best regards,
randy kobes

Re: Problem use Apache::Upload

Posted by Randy Kobes <ra...@theoryx5.uwinnipeg.ca>.
On Fri, 30 Jul 2004, Markus Wichitill wrote:

> You could try adding $req->parse() before accessing the
> uploads. It's not really documented anymore, but seems to
> be still necessary for big uploads.  I'm not sure if the
> API is still in flux, if only the docs are unfinished, or
> if this is a bug.

Hi Markus,
   Do you have an example script and configuration where
$req->parse() is necessary? I just tried uploading a
32 MB file without it, and it went through OK ...

-- 
best regards,
randy

Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Randy Kobes <ra...@theoryx5.uwinnipeg.ca> writes:

>      if (req->body == NULL)
> -        req->body = apr_table_make(req->env, APREQ_NELTS);
> +        req->body = apr_table_make(apreq_env_pool(req->env), APREQ_NELTS);

Thanks Randy!  That whole thing is a sloppy hack
I recently added, just to give the Request.pod tests 
a body table to work with.  I'll eventually remove 
it once I figure out a better way to fake up some 
parse data for the doc tests, but in the meantime 
here's my +1 to commit your patch.

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Randy Kobes wrote:
> I get a similar error now when I move the parse() line
> under new() - the following:
> 
> ================================================================
> Index: glue/perl/xsbuilder/Apache/Request/Apache__Request.h
> ===================================================================
> RCS file: /home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Apache__Request.h,v
> retrieving revision 1.50
> diff -u -r1.50 Apache__Request.h
> --- glue/perl/xsbuilder/Apache/Request/Apache__Request.h	29 Jul 2004 16:22:32 -0000	1.50
> +++ glue/perl/xsbuilder/Apache/Request/Apache__Request.h	31 Jul 2004 20:51:51 -0000
> @@ -415,7 +415,7 @@
>      while (s == APR_INCOMPLETE);
> 
>      if (req->body == NULL)
> -        req->body = apr_table_make(req->env, APREQ_NELTS);
> +        req->body = apr_table_make(apreq_env_pool(req->env), APREQ_NELTS);
> 
>      if (GIMME_V != G_VOID)
>          XSRETURN_IV(s);
> 
> =================================================================
> fixes it for me - does it also for you?

Yep.

Re: Problem use Apache::Upload

Posted by Randy Kobes <ra...@theoryx5.uwinnipeg.ca>.
On Sat, 31 Jul 2004, Markus Wichitill wrote:

> Markus Wichitill wrote:
> > Randy Kobes wrote:
> >> Perhaps the template below would illustrate your problem? In
> >> here, I put in a POST_MAX of 555555, and tried uploading a
> >> file larger than that - this was specified by the alias
> >> /getfiles-binary-too_big in glue/perl/t/conf/extra.conf.in.
> >> I then called $req->parse(), and returned
> >> Apache::SERVER_ERROR unless $req->parse() was APR::SUCCESS.
> >> Is this more or less what's happening? You should just be
> >> able to change the /getfiles-binary-too_big alias in
> >> glue/perl/t/conf/extra.conf.in from D:/test.xml (a 10 MB
> >> file on my system) to whatever you want to test this; for
> >> me, on Win32, these tests still pass, but perhaps this isn't
> >> the same configuration as you?
> >
> > It passes, but crashes if I move the parse() line directly under new():
>
> Heh, while I did get Windows' application error popup* like in my own
> modified test, the test continues "successfully" after I kill Apache by
> pressing OK (and it's really gone according to Process Explorer). I guess
> that's because the test doesn't differentiate between a genuine 500 from
> Apache and a failed connection?
>
> * Translated back from m$-DE is says something like "The commmand in
> 0xdeadbeef points to memory in 0xdecafbad. The action 'written' couldn't be
> performed on the memory".

I get a similar error now when I move the parse() line
under new() - the following:

================================================================
Index: glue/perl/xsbuilder/Apache/Request/Apache__Request.h
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/xsbuilder/Apache/Request/Apache__Request.h,v
retrieving revision 1.50
diff -u -r1.50 Apache__Request.h
--- glue/perl/xsbuilder/Apache/Request/Apache__Request.h	29 Jul 2004 16:22:32 -0000	1.50
+++ glue/perl/xsbuilder/Apache/Request/Apache__Request.h	31 Jul 2004 20:51:51 -0000
@@ -415,7 +415,7 @@
     while (s == APR_INCOMPLETE);

     if (req->body == NULL)
-        req->body = apr_table_make(req->env, APREQ_NELTS);
+        req->body = apr_table_make(apreq_env_pool(req->env), APREQ_NELTS);

     if (GIMME_V != G_VOID)
         XSRETURN_IV(s);

=================================================================
fixes it for me - does it also for you?

-- 
best regards,
randy

Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Markus Wichitill wrote:
> Randy Kobes wrote:
>> Perhaps the template below would illustrate your problem? In
>> here, I put in a POST_MAX of 555555, and tried uploading a
>> file larger than that - this was specified by the alias
>> /getfiles-binary-too_big in glue/perl/t/conf/extra.conf.in.
>> I then called $req->parse(), and returned
>> Apache::SERVER_ERROR unless $req->parse() was APR::SUCCESS.
>> Is this more or less what's happening? You should just be
>> able to change the /getfiles-binary-too_big alias in
>> glue/perl/t/conf/extra.conf.in from D:/test.xml (a 10 MB
>> file on my system) to whatever you want to test this; for
>> me, on Win32, these tests still pass, but perhaps this isn't
>> the same configuration as you?
> 
> It passes, but crashes if I move the parse() line directly under new():

Heh, while I did get Windows' application error popup* like in my own 
modified test, the test continues "successfully" after I kill Apache by 
pressing OK (and it's really gone according to Process Explorer). I guess 
that's because the test doesn't differentiate between a genuine 500 from 
Apache and a failed connection?

* Translated back from m$-DE is says something like "The commmand in 
0xdeadbeef points to memory in 0xdecafbad. The action 'written' couldn't be 
performed on the memory".

Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Randy Kobes wrote:
> Perhaps the template below would illustrate your problem? In
> here, I put in a POST_MAX of 555555, and tried uploading a
> file larger than that - this was specified by the alias
> /getfiles-binary-too_big in glue/perl/t/conf/extra.conf.in.
> I then called $req->parse(), and returned
> Apache::SERVER_ERROR unless $req->parse() was APR::SUCCESS.
> Is this more or less what's happening? You should just be
> able to change the /getfiles-binary-too_big alias in
> glue/perl/t/conf/extra.conf.in from D:/test.xml (a 10 MB
> file on my system) to whatever you want to test this; for
> me, on Win32, these tests still pass, but perhaps this isn't
> the same configuration as you?

It passes, but crashes if I move the parse() line directly under new():

>  sub handler {
>      my $r = shift;
> -    my $req = Apache::Request->new($r);
> +    my $req = Apache::Request->new($r, POST_MAX => 555555);
> +    my $status = $req->parse();
> +    return Apache::SERVER_ERROR unless ($status == APR::SUCCESS);
>      my $temp_dir = File::Spec->tmpdir;
> 
>      my $method  = $req->args('method');
>      my $has_md5  = $req->args('has_md5');
>      require Digest::MD5 if $has_md5;
>      my $upload = $req->upload(($req->upload)[0]);


> By the way, if you don't want to go through all the
> tests via 'nmake test', and just test this one, what
> you could do is install the Perl modules (so as to
> not bother with adding blib/ - this assumes your
> Win32 is just a test box), and then, within glue/perl,
>    perl t/TEST --config
> which generates the new t/conf/httpd.conf and
> t/conf/extra.conf, based on extra.conf.in), and then
>    perl t/TEST -v apreq/upload
> to run just the upload tests.
> 

I use "perl t/TEST -verbose t/apreq/upload.t" without any manual --config or 
blib-adding, that seems to be included in TEST.

Re: Problem use Apache::Upload

Posted by Randy Kobes <ra...@theoryx5.uwinnipeg.ca>.
On Fri, 30 Jul 2004, Markus Wichitill wrote:

> Randy Kobes wrote:
> > On Fri, 30 Jul 2004, Markus Wichitill wrote:
> >>Sorry, no test patch since my modifications to upload.t
> >>are too ugly (a copy of the second foreach loop with a
> >>hardcoded filename basically). That "getfiles-binary"
> >>stuff in there is so obscure that I can't figure out how
> >>to properly add another bigger file to @names.
> >
> > The /getfiles-binary-(perl|httpd) is defined by Apache-Test
> > just to be an alias to the (perl|httpd) binary on the system
> > (see httpd.conf). What you might try is adding a similar
> > alias in httpd.conf to another file and then adding that to
> > @names (making sure when running the tests that you don't
> > regenerate httpd.conf).
>
> I tried that, but httpd.conf is generated every time from
> apache_test_config.pm I guess, which in turn is generated
> from whoknowswhat, and that's where I stopped.

Perhaps the template below would illustrate your problem? In
here, I put in a POST_MAX of 555555, and tried uploading a
file larger than that - this was specified by the alias
/getfiles-binary-too_big in glue/perl/t/conf/extra.conf.in.
I then called $req->parse(), and returned
Apache::SERVER_ERROR unless $req->parse() was APR::SUCCESS.
Is this more or less what's happening? You should just be
able to change the /getfiles-binary-too_big alias in
glue/perl/t/conf/extra.conf.in from D:/test.xml (a 10 MB
file on my system) to whatever you want to test this; for
me, on Win32, these tests still pass, but perhaps this isn't
the same configuration as you?

===============================================================
Index: glue/perl/t/conf/extra.conf.in
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/t/conf/extra.conf.in,v
retrieving revision 1.2
diff -u -r1.2 extra.conf.in
--- glue/perl/t/conf/extra.conf.in	11 Jun 2004 03:13:30 -0000	1.2
+++ glue/perl/t/conf/extra.conf.in	31 Jul 2004 16:17:07 -0000
@@ -8,3 +8,4 @@
    Options None
 </Directory>

+Alias /getfiles-binary-too_big "D:/test.xml"
Index: glue/perl/t/response/TestApReq/upload.pm
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/t/response/TestApReq/upload.pm,v
retrieving revision 1.3
diff -u -r1.3 upload.pm
--- glue/perl/t/response/TestApReq/upload.pm	23 Jul 2004 23:52:14 -0000	1.3
+++ glue/perl/t/response/TestApReq/upload.pm	31 Jul 2004 16:17:07 -0000
@@ -9,16 +9,20 @@
 use Apache::Upload;
 use File::Spec;
 require File::Basename;
+use APR::Const -compile => qw(SUCCESS);
+use Apache::Const -compile => qw(OK SERVER_ERROR);

 sub handler {
     my $r = shift;
-    my $req = Apache::Request->new($r);
+    my $req = Apache::Request->new($r, POST_MAX => 555555);
     my $temp_dir = File::Spec->tmpdir;

     my $method  = $req->args('method');
     my $has_md5  = $req->args('has_md5');
     require Digest::MD5 if $has_md5;
     my $upload = $req->upload(($req->upload)[0]);
+    my $status = $req->parse();
+    return Apache::SERVER_ERROR unless ($status == APR::SUCCESS);
     my $type = $upload->type;
     my $basename = File::Basename::basename($upload->filename);
     my ($data, $fh);
@@ -71,7 +75,7 @@
 md5: $cs
 END
     unlink $temp_file if -f $temp_file;
-    return 0;
+    return Apache::OK;
 }

 sub cs {
Index: glue/perl/t/apreq/upload.t
===================================================================
RCS file: /home/cvs/httpd-apreq-2/glue/perl/t/apreq/upload.t,v
retrieving revision 1.2
diff -u -r1.2 upload.t
--- glue/perl/t/apreq/upload.t	23 Jul 2004 05:46:48 -0000	1.2
+++ glue/perl/t/apreq/upload.t	31 Jul 2004 16:17:07 -0000
@@ -3,14 +3,17 @@

 use Apache::Test;
 use Apache::TestUtil;
-use Apache::TestRequest qw(UPLOAD_BODY GET_BODY_ASSERT);
+use Apache::TestRequest qw(UPLOAD_BODY UPLOAD GET_BODY_ASSERT);
 use Cwd;
 require File::Basename;

 my $cwd = getcwd();
 my $location = "/TestApReq__upload";

+my $server = join ':', Apache::Test::vars(qw(servername port));
+
 my %types = (perl => 'application/octet-stream',
+             too_big => 'application/octet-stream',
              httpd => 'application/octet-stream',
              'perltoc.pod' => 'text/x-pod',
              'perlport.pod' => 'text/x-pod');
@@ -19,15 +22,14 @@

 plan tests => @names * @methods, have_lwp;

+use LWP::Simple qw(getstore is_success);
 foreach my $name (@names) {
     my $url = ( ($name =~ /\.pod$/) ?
         "getfiles-perl-pod/" : "/getfiles-binary-" ) . $name;
-    my $content = GET_BODY_ASSERT($url);
-    my $path = File::Spec->catfile($cwd, 't', $name);
-    open my $fh, ">", $path or die "Cannot open $path: $!";
-    binmode $fh;
-    print $fh $content;
-    close $fh;
+     my $store = File::Spec->catfile($cwd, 't', $name);
+     unless (is_success(getstore("http://$server/$url", $store)) ) {
+        die "Cannot fetch $server$url to $store";
+     }
 }

 eval {require Digest::MD5;};
@@ -39,8 +41,13 @@
     my $basename = File::Basename::basename($file);

     for my $method ( @methods) {
-        my $result = UPLOAD_BODY("$location?method=$method;has_md5=$has_md5",
+        my $result = UPLOAD("$location?method=$method;has_md5=$has_md5",
                                  filename => $file);
+        if ($file =~ /too_big/) {
+            ok t_cmp($result->code, 500, "upload max exceeded");
+            next;
+        }
+        my $content = $result->content;
         my $expected = <<END;

 type: $types{$basename}
@@ -48,7 +55,7 @@
 filename: $basename
 md5: $cs
 END
-        ok t_cmp($result, $expected, "$method test for $basename");
+        ok t_cmp($content, $expected, "$method test for $basename");
     }
     unlink $file if -f $file;
 }

=================================================================

I used getstore() here to fetch the file to be
uploaded, as it was quicker.

By the way, if you don't want to go through all the
tests via 'nmake test', and just test this one, what
you could do is install the Perl modules (so as to
not bother with adding blib/ - this assumes your
Win32 is just a test box), and then, within glue/perl,
   perl t/TEST --config
which generates the new t/conf/httpd.conf and
t/conf/extra.conf, based on extra.conf.in), and then
   perl t/TEST -v apreq/upload
to run just the upload tests.

-- 
best regards,
randy

Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Randy Kobes wrote:
> On Fri, 30 Jul 2004, Markus Wichitill wrote:
>>Sorry, no test patch since my modifications to upload.t
>>are too ugly (a copy of the second foreach loop with a
>>hardcoded filename basically). That "getfiles-binary"
>>stuff in there is so obscure that I can't figure out how
>>to properly add another bigger file to @names.
> 
> The /getfiles-binary-(perl|httpd) is defined by Apache-Test
> just to be an alias to the (perl|httpd) binary on the system
> (see httpd.conf). What you might try is adding a similar
> alias in httpd.conf to another file and then adding that to
> @names (making sure when running the tests that you don't
> regenerate httpd.conf).

I tried that, but httpd.conf is generated every time from 
apache_test_config.pm I guess, which in turn is generated from whoknowswhat, 
and that's where I stopped.

Re: Problem use Apache::Upload

Posted by Randy Kobes <ra...@theoryx5.uwinnipeg.ca>.
On Fri, 30 Jul 2004, Markus Wichitill wrote:

[ ... ]
> On Win32 however, posting a big upload > POST_MAX and then
> calling parse()  to get the status will crash Apache. I
> can reproduce that by using a 4MB file in upload.t,
> setting POST_MAX=1MB and calling parse() in upload.pm.
>
> Sorry, no test patch since my modifications to upload.t
> are too ugly (a copy of the second foreach loop with a
> hardcoded filename basically). That "getfiles-binary"
> stuff in there is so obscure that I can't figure out how
> to properly add another bigger file to @names.

The /getfiles-binary-(perl|httpd) is defined by Apache-Test
just to be an alias to the (perl|httpd) binary on the system
(see httpd.conf). What you might try is adding a similar
alias in httpd.conf to another file and then adding that to
@names (making sure when running the tests that you don't
regenerate httpd.conf).

-- 
best regards,
randy

Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

> Joe Schaefer wrote:
> > That looks like memory corruption, not a parser failure.  I see
> > your problem now- see if this patch fixes it:
> 
> Yes, it seems to be fixed, thanks.
> 
> On Windows I couldn't reproduce the problem anymore today, even
> without the patch, but I guess that's the nature of memory
> corruption issues. 

Right- it's a very hard bug to tickle out.  What was 
happening is this: when the param's headers fall on a 
separate brigade from the param's value, the transient 
bucket that was holding the param name gets setaside, 
which morphs it into a pool bucket (and, undesirably, 
copies the bucket's data).  Once that bucket is 
destroyed by the parser, the copied bucket data 
(which now represents the param's name) is reclaimed.

The correct fix is to use immortal buckets in place of 
the transient buckets in the mfd parser.  I've committed
the change now.

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Joe Schaefer wrote:
> That looks like memory corruption, not a parser failure.  I see
> your problem now- see if this patch fixes it:

Yes, it seems to be fixed, thanks.

On Windows I couldn't reproduce the problem anymore today, even without the 
patch, but I guess that's the nature of memory corruption issues.

Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

> [Mon Aug 02 13:20:29 2004] [error] [forum] [client 192.168.0.1] key =
> <autht-Disposition: form-data;

[...]

> --\r\n>, val => <1283460750>
> 

That looks like memory corruption, not a parser failure.  I see
your problem now- see if this patch fixes it:

Index: src/apreq_parsers.c
===================================================================
RCS file: /home/cvs/httpd-apreq-2/src/apreq_parsers.c,v
retrieving revision 1.59
diff -u -r1.59 apreq_parsers.c
--- src/apreq_parsers.c 31 Jul 2004 23:56:40 -0000      1.59
+++ src/apreq_parsers.c 2 Aug 2004 15:19:25 -0000
@@ -948,7 +948,7 @@

             case APR_SUCCESS:
                 /* part has no body- return CRLF to front */
-                e = apr_bucket_transient_create(CRLF, 2,
+                e = apr_bucket_immortal_create(CRLF, 2,
                                                 ctx->bb->bucket_alloc);
                 APR_BRIGADE_INSERT_HEAD(ctx->in,e);
                 break;
@@ -975,7 +975,7 @@

             if (s != APR_SUCCESS) {
                 name = apr_pstrmemdup(pool, name, nlen);
-                e = apr_bucket_transient_create(name, nlen,
+                e = apr_bucket_immortal_create(name, nlen,
                                                 ctx->bb->bucket_alloc);
                 APR_BRIGADE_INSERT_HEAD(ctx->bb,e);
                 ctx->status = MFD_PARAM;


-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Joe Schaefer wrote:
> Ok- looks like the mfd parser is running to a succesful completion,
> so *it* thinks it parsed the full mfd data.  I can't reproduce
> the bug here, so we need to figure out where the last param 
> wound up.  Try dumping the body table with something like
> 
>   my $t = $req->body;
>   print "key = <$a>, val => <$b>" while ($a, $b) = each %$t;

[Mon Aug 02 13:20:29 2004] [error] [forum] [client 192.168.0.1] key = 
<file>, val => <test.dat>
[Mon Aug 02 13:20:29 2004] [error] [forum] [client 192.168.0.1] key = 
<attach>, val => <Upload>
[Mon Aug 02 13:20:29 2004] [error] [forum] [client 192.168.0.1] key = <pid>, 
val => <11381>
[Mon Aug 02 13:20:29 2004] [error] [forum] [client 192.168.0.1] key = <ori>, 
val => <>
[Mon Aug 02 13:20:29 2004] [error] [forum] [client 192.168.0.1] key = 
<autht-Disposition: form-data; 
name="pid"\r\n\r\n11381\r\n-----------------------------2921238217421\r\nContent-Disposition: 
form-data; 
name="ori"\r\n\r\n\r\n-----------------------------2921238217421\r\nContent-Disposition: 
form-data; 
name="auth"\r\n\r\n1283460750\r\n-----------------------------2921238217421
--\r\n>, val => <1283460750>

Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

[...]

> parse() is always 0, otherwise the init code I posted would stop the
> request early. body_status() see below.

Ok- looks like the mfd parser is running to a succesful completion,
so *it* thinks it parsed the full mfd data.  I can't reproduce
the bug here, so we need to figure out where the last param 
wound up.  Try dumping the body table with something like

  my $t = $req->body;
  print "key = <$a>, val => <$b>" while ($a, $b) = each %$t;

Double-check that the 'ori' parameter value is really empty.

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Joe Schaefer wrote:
> OK, could you show us some status codes for the failed request?
> Foe example, what do these report?
> 
>   $req->parse
>   $req->body_status

parse() is always 0, otherwise the init code I posted would stop the request 
early. body_status() see below.

> and set your LogLevel to Debug, so we can see what mod_apreq
> and the mfd parser are doing.

First with discard_request_body() enabled for all mp2 requests:

[Sun Aug 01 23:11:10 2004] [debug] worker.c(1631): AcceptMutex: sysvsem 
(default: sysvsem)
*** Successful upload on first request after restart:
[Sun Aug 01 23:11:13 2004] [error] [forum] [client 192.168.0.1] body_status 
after new(): 70022
[Sun Aug 01 23:11:13 2004] [error] [forum] [client 192.168.0.1] body_status 
after discard(): 0
[Sun Aug 01 23:11:13 2004] [error] [forum] [client 192.168.0.1] body_status 
after parse(): 0
[Sun Aug 01 23:11:13 2004] [debug] mod_apreq.c(591): [client 192.168.0.1] 
removing filter (1)
*** Next upload, missing auth param:
[Sun Aug 01 23:12:27 2004] [error] [forum] [client 192.168.0.1] body_status 
after new(): 70022
[Sun Aug 01 23:12:28 2004] [error] [forum] [client 192.168.0.1] body_status 
after discard(): 0
[Sun Aug 01 23:12:28 2004] [error] [forum] [client 192.168.0.1] body_status 
after parse(): 0
[Sun Aug 01 23:12:28 2004] [error] [forum] [client 192.168.0.1] Request 
authentication failed.

Now discard_request_body() only for GET requests:

[Sun Aug 01 23:17:22 2004] [debug] worker.c(1631): AcceptMutex: sysvsem 
(default: sysvsem)
*** First upload after restart ok
[Sun Aug 01 23:17:35 2004] [error] [forum] [client 192.168.0.1] body_status 
after new(): 70022
[Sun Aug 01 23:17:35 2004] [debug] mod_apreq.c(349): [client 192.168.0.1] 
prefetching 262144 bytes
[Sun Aug 01 23:17:35 2004] [debug] mod_apreq.c(349): [client 192.168.0.1] 
prefetching 262144 bytes
[Sun Aug 01 23:17:35 2004] [error] [forum] [client 192.168.0.1] body_status 
after parse(): 0
[Sun Aug 01 23:17:35 2004] [debug] mod_apreq.c(591): [client 192.168.0.1] 
removing filter (1)
*** Next upload ok, too
[Sun Aug 01 23:18:47 2004] [error] [forum] [client 192.168.0.1] body_status 
after new(): 70022
[Sun Aug 01 23:18:47 2004] [debug] mod_apreq.c(349): [client 192.168.0.1] 
prefetching 262144 bytes
[Sun Aug 01 23:18:48 2004] [debug] mod_apreq.c(349): [client 192.168.0.1] 
prefetching 262144 bytes
[Sun Aug 01 23:18:48 2004] [error] [forum] [client 192.168.0.1] body_status 
after parse(): 0
[Sun Aug 01 23:18:48 2004] [debug] mod_apreq.c(591): [client 192.168.0.1] 
removing filter (1)

Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

> Joe Schaefer wrote:
> > It's basically a lower-level description of what the RequestIO
> > docs mean by
> >   "This helper routine tests for and reads any message body in the
> > request, simply discarding whatever it receives."
> 
> Well, to me that sounds more like the mp1 behaviour, where it really
> completely discards the request body so that apreq can't access the
> data anymore. 

In mp1, Apache::Request takes the data away from the content-handler.
In mp2, it leaves the data alone.  That's why you can/should discard 
it in your mp2 content-handler, but not in your mp1 handler.

> 
> >>I just want to make sure, because I'm getting upload errors with
> >> files of a specific size that I'm not getting without
> >> discard_request_body(). If the code should make sense, I'll post
> >> details about that.
> > Please do.
> 
> This won't be easy to reproduce.

[...]

OK, could you show us some status codes for the failed request?
Foe example, what do these report?

  $req->parse
  $req->body_status

and set your LogLevel to Debug, so we can see what mod_apreq
and the mfd parser are doing.
-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Joe Schaefer wrote:
> It's basically a lower-level description of what the RequestIO
> docs mean by
> 
>   "This helper routine tests for and reads any message body in 
>   the request, simply discarding whatever it receives."

Well, to me that sounds more like the mp1 behaviour, where it really 
completely discards the request body so that apreq can't access the data 
anymore.

>>I just want to make sure, because I'm getting upload errors with
>>files of a specific size that I'm not getting without 
>>discard_request_body(). If the code should make sense, I'll post
>>details about that. 
> 
> Please do.

This won't be easy to reproduce.

What I do is I send the POST request shown below to my forum application. 
It's basically one file upload of 302680 bytes (size matters, contents 
don't) followed by a few parameters. POST_MAX is 1MB, well above that.

The problem is that the last param ("auth") is undefined if the script is 
run under mod_perl (mp2 and apreq2 current CVS, Apache 2.0.50, Linux/WinXP, 
Worker/NT MPM).

This doesn't happen:
- if I don't call discard_request_body() for POST requests.
- on the first request of a freshly started server, only subsequent ones.
- under CGI.
- if I remove the obsolete and always empty "ori" parameter.
- if the file is a few hundred bytes smaller.


POST /forum/post_attach.pl HTTP/1.1
Host: red.mshome.net
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) 
Gecko/20040626 Firefox/0.9.1
Accept: application/xhtml+xml,application/xml,*/*
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: mwf_login=1-secret
Content-Type: multipart/form-data; 
boundary=---------------------------19568103730103
Content-Length: 303279
-----------------------------19568103730103
Content-Disposition: form-data; name="file"; filename="test.dat"
Content-Type: application/octet-stream

xxxxxxxxxxxxxxxxxx [302680 bytes]
-----------------------------19568103730103
Content-Disposition: form-data; name="attach"

Upload
-----------------------------19568103730103
Content-Disposition: form-data; name="pid"

11380
-----------------------------19568103730103
Content-Disposition: form-data; name="ori"


-----------------------------19568103730103
Content-Disposition: form-data; name="auth"

1234567890
-----------------------------19568103730103--


HTTP/1.x 200 OK
Date: Sun, 01 Aug 2004 17:37:14 GMT
Server: Apache/2.0.50 (Unix) mod_perl/1.99_15-dev Perl/v5.8.5 DAV/2 SVN/1.0.5
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: private
Connection: close
Transfer-Encoding: chunked
Content-Type: application/xhtml+xml; charset=iso-8859-1


Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

> Joe Schaefer wrote:
>
> > The way to think of the discard_request_body call is
> >   "my content handler does not need the raw POST data,
> >    so tell apache to pull it through the input    filters via
> > ap_get_brigade(), and then delete    all the resulting buckets."
> 
> That sounds different from the RequestIO docs.

It's basically a lower-level description of what the RequestIO
docs mean by

  "This helper routine tests for and reads any message body in 
  the request, simply discarding whatever it receives."

> So does the following make sense then?

[...]

Looks good to me.

> I just want to make sure, because I'm getting upload errors with
> files of a specific size that I'm not getting without 
> discard_request_body(). If the code should make sense, I'll post
> details about that. 

Please do.

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Joe Schaefer wrote:
> In your case (a content-handler using Apache::Request) 
> you should always call discard_request_body (not just for GET).
> The way to think of the discard_request_body call is
> 
>   "my content handler does not need the raw POST data,
>    so tell apache to pull it through the input 
>    filters via ap_get_brigade(), and then delete 
>    all the resulting buckets."

That sounds different from the RequestIO docs. So does the following make 
sense then?

[...]
if (MP) {
   $apr = Apache::Request->new($ap,
     POST_MAX => $cfg->{maxAttachLen},
     TEMP_DIR => $cfg->{attachFsPath},
   );

   $ap->discard_request_body() == 0
     or error("discard_request_body() failed.")
     if MP2;

   $apr->parse() == 0
     or error("Input exceeds maximum allowed size or is corrupted.")
     if $ap->method eq 'POST';
}
elsif (CGIAPR) {
   my $pool = APR::Pool->new();
   $apr = Apache::Request->new($pool,
     POST_MAX => $cfg->{maxAttachLen},
     TEMP_DIR => $cfg->{attachFsPath},
   );

   $apr->parse() == 0
     or error("Input exceeds maximum allowed size or is corrupted.")
     if $method eq 'POST';
}
elsif (CGI) {
[...]

I just want to make sure, because I'm getting upload errors with files of a 
specific size that I'm not getting without discard_request_body(). If the 
code should make sense, I'll post details about that.

Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

[...]

> my $apr = Apache::Request->new($ap,
>    POST_MAX => $cfg->{maxAttachLen},
>    TEMP_DIR => $cfg->{attachFsPath},
> );
> if ($ap->method eq 'GET') {
>    $ap->discard_request_body() == 0

In your case (a content-handler using Apache::Request) 
you should always call discard_request_body (not just for GET).
The way to think of the discard_request_body call is

  "my content handler does not need the raw POST data,
   so tell apache to pull it through the input 
   filters via ap_get_brigade(), and then delete 
   all the resulting buckets."

[...]

> [error] [client 127.0.0.1] (70022)There is no error, this value
> signifies an initialized error code: 

Blech- I'll change this APR_EINIT to an APR_EGENERAL.

> Content-Length header (4959211) exceeds configured max_body limit
> (1000000)


Are you certain the server is segfaulting there?
Is there anything in the error log after this message?

In any case, I see there are a few problems with the way
we're currently reporting and checking errors for the POST data.
Originally all error reporting was the parser's responsibility,
however it made more sense to move some of the configuration 
checks (like POST_MAX) into the environment (mod_apreq) instead.

This means POST data errors can be generated by either the 
environment module or the parser itself.  We may need a body_status 
field in apreq_request_t to allow the parser and environment module 
to communicate their combined state to the user.

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Joe Schaefer wrote:
> Markus Wichitill <ma...@gmx.de> writes:
>>So is parse() still the recommended way of checking for upload errors?
> 
> Yes, if you're really demanding a final status (versus a current one),
> and you're not writing a content-handler.

Well, my applications usually need all their parameters anyway, so I don't 
really see the point of delayed parsing. Also, if the input is too big, 
incomplete or otherwise corrupted, I want to exit early, since there's no 
point in working with incomplete or even corrupted data.

This is what I currently do during initialization in mwForum, my 
CGI/mod_perl hybrid forum application (registry scripts using the mp1/mp2 
API instead of CGI stuff when running under mod_perl):

my $apr = Apache::Request->new($ap,
   POST_MAX => $cfg->{maxAttachLen},
   TEMP_DIR => $cfg->{attachFsPath},
);
if ($ap->method eq 'GET') {
   $ap->discard_request_body() == 0
     or error("discard_request_body() failed.");
}
elsif ($ap->method eq 'POST') {
   $apr->parse() == 0
     or error("Input exceeds maximum allowed size or is corrupted.");
}
else {
   $ap->status(405);
   exit;
}

>>On Win32 however, posting a big upload > POST_MAX and then calling parse() to
>>get the status will crash Apache. I can reproduce that by using a 4MB file in
>>upload.t, setting POST_MAX=1MB and calling parse() in upload.pm.
> 
> parse() in void context is supposed to croak in that case, but it 
> shouldn't ever crash the server (as a last resort mod_perl should 
> catch the exception, so eg. the tempfiles should still get cleaned up).
> 
> Can you please show us, explicitly, what happens?

Getting a stacktrace on Win32 would mean I have to swap my ASF and 
ActiveState binaries with self-compiled debug builds, which would take a 
while. So I had hoped that maybe Randy can reproduce the segfaults with a 
modified test, before I go to all the trouble.

strace on Linux may show somewhat useful output even without debug builds, 
but on Windows I'v never seen anything useful in VC6 with release builds.

Without a stacktrace, there isn't much to see:

# Failed test 21 in t\apreq\upload.t at line 71
# testing : fh test for ff.exe
# expected:
# type: application/octet-stream
# size: 4959023
# filename: ff.exe
# md5: 65e0f588c3a8b44b0f575363995c1ff5
# received: 500 Unknown error
not ok 21
# Failed test 22 in t\apreq\upload.t at line 71 fail #2
# testing : io test for ff.exe
# expected:
# type: application/octet-stream
# size: 4959023
# filename: ff.exe
# md5: 65e0f588c3a8b44b0f575363995c1ff5
# received: 500 Can't connect to localhost:8529 (connect: Unknown error)
not ok 22
[...]

[error] [client 127.0.0.1] (70022)There is no error, this value signifies an 
initialized error code: Content-Length header (4959211) exceeds configured 
max_body limit (1000000)

Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

> So is parse() still the recommended way of checking for upload errors?

Yes, if you're really demanding a final status (versus a current one),
and you're not writing a content-handler.

> I've tried body_status(), however that only returns 70008 (APR_TIMEUP?
> huh?)

70008 is APR_INCOMPLETE (APR_OS_START_STATUS + 8),
which means the parser still hasn't seen some of the post data.
This is *not* an error status.

> Ok, I think I got the wrong impression that it's required because small
> parameters after file uploads that are bigger than POST_MAX are cut off,

If the post data exceeds POST_MAX, the parser should enter an error
state and refuse to parse any more data.  Some of the post data
beyond POST_MAX may wind up getting parsed, and more of it does
when you call $req->parse than when you don't.  But that's not by
design, so it's not a behavior you can rely on in an application.  
Someday someone may fix this by ensuring that absolutely nothing 
after POST_MAX ever gets parsed.

[...]

> On Win32 however, posting a big upload > POST_MAX and then calling parse() to
> get the status will crash Apache. I can reproduce that by using a 4MB file in
> upload.t, setting POST_MAX=1MB and calling parse() in upload.pm.

parse() in void context is supposed to croak in that case, but it 
shouldn't ever crash the server (as a last resort mod_perl should 
catch the exception, so eg. the tempfiles should still get cleaned up).

Can you please show us, explicitly, what happens?

> Sorry, no test patch since my modifications to upload.t are too ugly
> (a copy of the second foreach loop with a hardcoded filename basically).

For bug reporting this is certainly ok by me.  All we can
reasonably expect is to be able to reproduce the bug. It's 
IMO the committers' responsibility to turn your bug report into
a regression test (although it certainly helps a lot if you're
able to do that yourself).

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Joe Schaefer wrote:
> Markus Wichitill <ma...@gmx.de> writes:
>>You could try adding $req->parse() before accessing the uploads. It's not
>>really documented anymore, 
> 
> Sorry about that, parse() should be documented

So is parse() still the recommended way of checking for upload errors? I've 
tried body_status(), however that only returns 70008 (APR_TIMEUP? huh?) for 
me while doing small valid uploads.

>>but seems to be still necessary for big uploads. 
> 
> this should never be the case, because the libapreq2 C library
> will parse the request as necessary.  If calling $req->parse()
> is somehow required for you, that's a bug.

Ok, I think I got the wrong impression that it's required because small 
parameters after file uploads that are bigger than POST_MAX are cut off, 
leading to confusing error messages in my application. Don't ask me why it 
has helped Keith...

On Win32 however, posting a big upload > POST_MAX and then calling parse() 
to get the status will crash Apache. I can reproduce that by using a 4MB 
file in upload.t, setting POST_MAX=1MB and calling parse() in upload.pm.

Sorry, no test patch since my modifications to upload.t are too ugly (a copy 
of the second foreach loop with a hardcoded filename basically). That 
"getfiles-binary" stuff in there is so obscure that I can't figure out how 
to properly add another bigger file to @names.


Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
Markus Wichitill <ma...@gmx.de> writes:

[...]

> You could try adding $req->parse() before accessing the uploads. It's not
> really documented anymore, 

Sorry about that, parse() should be documented, but...

> but seems to be still necessary for big uploads. 

this should never be the case, because the libapreq2 C library
will parse the request as necessary.  If calling $req->parse()
is somehow required for you, that's a bug.

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by Joe Schaefer <jo...@sunstarsys.com>.
"Keith C. Perry" <ne...@vcsn.com> writes:

[...]

> Well good news, the $req->parse in my case seem to be needed.  Here
> is what I was finally able to get going...
> 
> my $r=Apache->request;
> my $req = Apache::Request->new($r, TEMP_DIR => "/www/tmp");
> my $upload = $req->upload('sentfile');
> my $fname;
> 
> if ($upload) {
>  $req->parse;
>  $fname  = $upload->filename();
> }
> 
> $r->content_type('text/html');
> $r->send_http_header;
> 
> if ( $fname && $fname ne "" ) {
>  $r->print("Thank you for uploading <b>$fname</b><br>\n");
>  $upload->link("/www/tmp/$fname");
>  exit;
> }

It makes absolutely no sense to me that your above invocation
of $req->parse makes the slightest difference, because
the conditional guarantees that the $upload was already found!

So exactly what happens if you comment out your $req->parse call?

-- 
Joe Schaefer


Re: Problem use Apache::Upload

Posted by "Keith C. Perry" <ne...@vcsn.com>.
Quoting Markus Wichitill <ma...@gmx.de>:

> Keith C. Perry wrote:
> > I thought that might had been it but I tried a couple of things while I
> was
> > waiting.  First here is the form:
> > 
> > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
> "http://www.w3.or
> > g/TR/html4/loose.dtd">
> > <html>
> > <head>
> > <title>File Upload</title>
> > </head>
> > <body>
> > <form name="uploadform" action="upload.mpl?1" method="post"
> enctype="multipart/f
> > orm-data"><br>
> > <input name="sentfile" type="file">
> > <input value="Send File" type="submit">
> > </form>
> > </body>
> > </html>
> > 
> > Now, I tried...
> > 
> > my $upload = $req->upload('sentfile');
> > my $fname  = $upload->filename('origname');
> > 
> > I get this error...
> > 
> > [Fri Jul 30 09:40:12 2004] [error] Can't call method "filename" on an
> undefined
> > value at /www/local/upload.mpl line 18.\n
> 
> Aside from the 'origname' which shouldn't be there, this is how it should 
> work. I can't tell from the example why apreq doesn't see the uploaded file 
> and returns undef.
> 
> You could try adding $req->parse() before accessing the uploads. It's not 
> really documented anymore, but seems to be still necessary for big uploads. 
> I'm not sure if the API is still in flux, if only the docs are unfinished, 
> or if this is a bug.

Well good news, the $req->parse in my case seem to be needed.  Here is what I
was finally able to get going...

my $r=Apache->request;
my $req = Apache::Request->new($r, TEMP_DIR => "/www/tmp");
my $upload = $req->upload('sentfile');
my $fname;

if ($upload) {
 $req->parse;
 $fname  = $upload->filename();
}

$r->content_type('text/html');
$r->send_http_header;

if ( $fname && $fname ne "" ) {
 $r->print("Thank you for uploading <b>$fname</b><br>\n");
 $upload->link("/www/tmp/$fname");
 exit;
}


Now, I just have to move this back to my production server  :)

> > BTW, you used curly braces in your example to me but I'm assuming that was
> a
> > typo.  :)  For my own sanity I tried
> > 
> > my $upload = $req->upload{'sentfile'};
> > 
> > and it does give me a syntax error.
> 
> I didn't write $req->upload{'sentfile'}, I wrote $table->{'sentfile'}, which
> 
> uses the tied hash interface of the table class.
> 

Oh, my bad for over looking that.  Thanks for all your help.

-- 
Keith C. Perry, MS E.E.
Director of Networks & Applications
VCSN, Inc.
http://vcsn.com
 
____________________________________
This email account is being host by:
VCSN, Inc : http://vcsn.com

Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Keith C. Perry wrote:
> I thought that might had been it but I tried a couple of things while I was
> waiting.  First here is the form:
> 
> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.or
> g/TR/html4/loose.dtd">
> <html>
> <head>
> <title>File Upload</title>
> </head>
> <body>
> <form name="uploadform" action="upload.mpl?1" method="post" enctype="multipart/f
> orm-data"><br>
> <input name="sentfile" type="file">
> <input value="Send File" type="submit">
> </form>
> </body>
> </html>
> 
> Now, I tried...
> 
> my $upload = $req->upload('sentfile');
> my $fname  = $upload->filename('origname');
> 
> I get this error...
> 
> [Fri Jul 30 09:40:12 2004] [error] Can't call method "filename" on an undefined
> value at /www/local/upload.mpl line 18.\n

Aside from the 'origname' which shouldn't be there, this is how it should 
work. I can't tell from the example why apreq doesn't see the uploaded file 
and returns undef.

You could try adding $req->parse() before accessing the uploads. It's not 
really documented anymore, but seems to be still necessary for big uploads. 
I'm not sure if the API is still in flux, if only the docs are unfinished, 
or if this is a bug.

> BTW, you used curly braces in your example to me but I'm assuming that was a
> typo.  :)  For my own sanity I tried
> 
> my $upload = $req->upload{'sentfile'};
> 
> and it does give me a syntax error.

I didn't write $req->upload{'sentfile'}, I wrote $table->{'sentfile'}, which 
uses the tied hash interface of the table class.


Re: Problem use Apache::Upload

Posted by "Keith C. Perry" <ne...@vcsn.com>.
Quoting Markus Wichitill <ma...@gmx.de>:

> Keith C. Perry wrote:
> > Quoting Markus Wichitill <ma...@gmx.de>:
> >>If you want an Apache::Upload object, you need to pass a field name:
> >>my $upload = $req->upload('foo');
> >>
> >>
>
http://cvs.apache.org/~joes/libapreq2-2.04-dev/docs/html/group__apreq__xs__request.html#upload
> > 
> > I saw that but the way the docs read, its sounds like you don't need a
> parameter
> > there.  
> 
> It says if you don't pass a name, you get an Apache::Upload::Table object in
> 
> scalar context.
> 
> my $uploads = $req->upload();
> my $upload = $uploads->{'foo'};

Ok, I see

> This is different from the apreq1 API, but passing the name works for both 
> versions.
> 
>  > Also when you say field name... field name to what? Is this arbitary?
> 
> The name you gave the HTML form field.
> 
> <input type='file' name='foo'>
> 

I thought that might had been it but I tried a couple of things while I was
waiting.  First here is the form:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.or
g/TR/html4/loose.dtd">
<html>
<head>
<title>File Upload</title>
</head>
<body>
<form name="uploadform" action="upload.mpl?1" method="post" enctype="multipart/f
orm-data"><br>
<input name="sentfile" type="file">
<input value="Send File" type="submit">
</form>
</body>
</html>


Now, I tried...

my $upload = $req->upload('sentfile');
my $fname  = $upload->filename('origname');

I get this error...

[Fri Jul 30 09:40:12 2004] [error] Can't call method "filename" on an undefined
value at /www/local/upload.mpl line 18.\n


BTW, you used curly braces in your example to me but I'm assuming that was a
typo.  :)  For my own sanity I tried

my $upload = $req->upload{'sentfile'};

and it does give me a syntax error.

-- 
Keith C. Perry, MS E.E.
Director of Networks & Applications
VCSN, Inc.
http://vcsn.com
 
____________________________________
This email account is being host by:
VCSN, Inc : http://vcsn.com

Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Keith C. Perry wrote:
> Quoting Markus Wichitill <ma...@gmx.de>:
>>If you want an Apache::Upload object, you need to pass a field name:
>>my $upload = $req->upload('foo');
>>
>> http://cvs.apache.org/~joes/libapreq2-2.04-dev/docs/html/group__apreq__xs__request.html#upload
> 
> I saw that but the way the docs read, its sounds like you don't need a parameter
> there.  

It says if you don't pass a name, you get an Apache::Upload::Table object in 
scalar context.

my $uploads = $req->upload();
my $upload = $uploads->{'foo'};

This is different from the apreq1 API, but passing the name works for both 
versions.

 > Also when you say field name... field name to what? Is this arbitary?

The name you gave the HTML form field.

<input type='file' name='foo'>

Re: Problem use Apache::Upload

Posted by "Keith C. Perry" <ne...@vcsn.com>.
Quoting Markus Wichitill <ma...@gmx.de>:

> Keith C. Perry wrote:
> > use Apache::Upload;
> > use strict;
> > 
> > my $r=Apache->request;
> > my $req = Apache::Request->new($r);
> > my $upload = $req->upload();
> > my $fname  = $upload->filename();
> > my $io = $upload->io();
> > $r->print while <$io>;
> > 
> > I get error like this for filename() in the server error log...
> > 
> > [Fri Jul 30 02:25:54 2004] [error] Can't locate object method "filename"
> via
> > package "Apache::Upload::Table" at /www/local/upload.mpl line 18.
> 
> If you want an Apache::Upload object, you need to pass a field name:
> my $upload = $req->upload('foo');
> 
>
http://cvs.apache.org/~joes/libapreq2-2.04-dev/docs/html/group__apreq__xs__request.html#upload
> 

I saw that but the way the docs read, its sounds like you don't need a parameter
there.  Also when you say field name... field name to what? Is this arbitary?

-- 
Keith C. Perry, MS E.E.
Director of Networks & Applications
VCSN, Inc.
http://vcsn.com
 
____________________________________
This email account is being host by:
VCSN, Inc : http://vcsn.com

Re: Problem use Apache::Upload

Posted by Markus Wichitill <ma...@gmx.de>.
Keith C. Perry wrote:
> use Apache::Upload;
> use strict;
> 
> my $r=Apache->request;
> my $req = Apache::Request->new($r);
> my $upload = $req->upload();
> my $fname  = $upload->filename();
> my $io = $upload->io();
> $r->print while <$io>;
> 
> I get error like this for filename() in the server error log...
> 
> [Fri Jul 30 02:25:54 2004] [error] Can't locate object method "filename" via
> package "Apache::Upload::Table" at /www/local/upload.mpl line 18.

If you want an Apache::Upload object, you need to pass a field name:
my $upload = $req->upload('foo');

http://cvs.apache.org/~joes/libapreq2-2.04-dev/docs/html/group__apreq__xs__request.html#upload