Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the CGI CPAN distribution.

Report information
The Basics
Id: 22992
Status: resolved
Priority: 0/
Queue: CGI

People
Owner: LDS [...] cpan.org
Requestors: drfrench [...] gmail.com
MARKSTOS [...] cpan.org
william [...] knowmad.com
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: (no value)
Fixed in: (no value)



Subject: uploadInfo method produces different results on subsequent calls
CGI.pm version: 3.05 Perl version: v5.8.5 built for i386-linux-thread-multi OS: Fedora Linux 2.6.10 Issue: '.tmpfiles' information is not saved across object instantiations although other information (like .fieldnames and .parameters are). Example 1 =-=-=-=-=- #!/bin/perl -w use strict; use CGI qw/:standard/; my $foo = param('bar'); // Call class method first my $query = new CGI(); // Instantiate new CGI obj second my $fh = $query->param('excel_file'); // Call class method print STDERR $query->uploadInfo($fh)->{'Content-Type'}; // undefined error exit; Example 2 =-=-=-=-=- #!/bin/perl -w use strict; use CGI qw/:standard/; my $query = new CGI(); // Instantiate new CGI obj first my $foo = param('bar'); // Call class method second my $fh = $query->param('excel_file'); // Call class method print STDERR $query->uploadInfo($fh)->{'Content-Type'}; // Prints ' application/vnd.ms-excel' exit; Solution: The save_request method of CGI.pm specifically plays with package globals in order to provide access to information across multiple instantiations of CGI objects. The .tmpfiles information however is not saved. Saving this information would fix the bug. The following code snippets are suggested changes to version 3.05... Add after line 117: undef %QUERY_TMPFILES; Add after line 676: %QUERY_TMPFILES = %{$self->{'.tmpfiles'}}; Add after line 457: $self->{'.tmpfiles'} = {%QUERY_TMPFILES};
[guest - Tue Mar 15 20:34:41 2005]: my $fh = $query->param('excel_file'); // Call class method should be my $fh = $query->param('excel_file'); // Call object method Show quoted text
> CGI.pm version: 3.05 > Perl version: v5.8.5 built for i386-linux-thread-multi > OS: Fedora Linux 2.6.10 > > Issue: > > '.tmpfiles' information is not saved across object instantiations > although other information (like .fieldnames and .parameters are). > > Example 1 > =-=-=-=-=- > #!/bin/perl -w > > use strict; > use CGI qw/:standard/; > > my $foo = param('bar'); // Call class method first > my $query = new CGI(); // Instantiate new CGI obj second > my $fh = $query->param('excel_file'); // Call class method > print STDERR $query->uploadInfo($fh)->{'Content-Type'}; // undefined > error > exit; > > Example 2 > =-=-=-=-=- > #!/bin/perl -w > > use strict; > use CGI qw/:standard/; > > my $query = new CGI(); // Instantiate new CGI obj first > my $foo = param('bar'); // Call class method second > my $fh = $query->param('excel_file'); // Call class method > print STDERR $query->uploadInfo($fh)->{'Content-Type'}; // Prints ' > application/vnd.ms-excel' > exit; > > Solution: > > The save_request method of CGI.pm specifically plays with package > globals in order to provide access to information across multiple > instantiations of CGI objects. The .tmpfiles information however is > not saved. Saving this information would fix the bug. The following > code snippets are suggested changes to version 3.05... > > Add after line 117: > undef %QUERY_TMPFILES; > > Add after line 676: > %QUERY_TMPFILES = %{$self->{'.tmpfiles'}}; > > Add after line 457: > $self->{'.tmpfiles'} = {%QUERY_TMPFILES};
Subject: uploadInfo() method fails if CGI instantiated twice
I have found that if I instantiate a CGI object twice from the same request, the second time it is instantiated, the uploadInfo method fails to return data. I am still able to read the file unless the first object is deleted in which case I receive the following error: Use of uninitialized value in ref-to-glob cast at (eval 22) line 3. Use of uninitialized value in hash element at (eval 22) line 3. I didn't see a troubleshooting section that covers this issue so thought it would be useful to report as the error message is not very clear as to the actual problem. Thanks, William
From: markstos [...] cpan.org
This looks related to, if not the same thing as this bug: http://rt.cpan.org/NoAuth/Bug.html?id=11895 Mark
From: MARKSTOS [...] cpan.org
On Tue Mar 15 20:34:41 2005, guest wrote: Show quoted text
> CGI.pm version: 3.05 > Perl version: v5.8.5 built for i386-linux-thread-multi > OS: Fedora Linux 2.6.10 > > Issue: > > '.tmpfiles' information is not saved across object instantiations > although other information (like .fieldnames and .parameters are). > > Example 1 > =-=-=-=-=- > #!/bin/perl -w > > use strict; > use CGI qw/:standard/; > > my $foo = param('bar'); // Call class method first > my $query = new CGI(); // Instantiate new CGI obj second > my $fh = $query->param('excel_file'); // Call class method > print STDERR $query->uploadInfo($fh)->{'Content-Type'}; // undefined > error > exit; > > Example 2 > =-=-=-=-=- > #!/bin/perl -w > > use strict; > use CGI qw/:standard/; > > my $query = new CGI(); // Instantiate new CGI obj first > my $foo = param('bar'); // Call class method second > my $fh = $query->param('excel_file'); // Call class method > print STDERR $query->uploadInfo($fh)->{'Content-Type'}; // Prints ' > application/vnd.ms-excel' > exit; > > Solution: > > The save_request method of CGI.pm specifically plays with package > globals in order to provide access to information across multiple > instantiations of CGI objects. The .tmpfiles information however is > not saved. Saving this information would fix the bug. The following > code snippets are suggested changes to version 3.05... > > Add after line 117: > undef %QUERY_TMPFILES; > > Add after line 676: > %QUERY_TMPFILES = %{$self->{'.tmpfiles'}}; > > Add after line 457: > $self->{'.tmpfiles'} = {%QUERY_TMPFILES};
I have confirmed this bug exists with CGI.pm 3.25. I've created a test for it in a new t/uploadInfo.t, and used your suggestions above to create a patch to fix it, which worked. I'll be submitting the result shortly, although perhaps through a different ticket.
On Tue Sep 06 19:11:58 2005, guest wrote: Show quoted text
> I have found that if I instantiate a CGI object twice from the same > request, the second time it is instantiated, the uploadInfo method > fails to return data. I am still able to read the file unless the > first object is deleted in which case I receive the following > error: > > Use of uninitialized value in ref-to-glob cast at (eval 22) line 3. > Use of uninitialized value in hash element at (eval 22) line 3. > > I didn't see a troubleshooting section that covers this issue so > thought it would be useful to report as the error message is not > very clear as to the actual problem.
This bug report can be merged into 11895 as a dupe. Incidently, a patch with code and tests will be forthcoming shortly, and the bug can be resolved.
Subject: PATCH: filehandle position not reset on fresh objects, uploadInfo fix
When calling new() a second time, it's expected that a completely fresh object is delivered. The attached code, test and doc updates address two cases where this was not happening where file uploading was concerned. 1. The filehandle position was not being reset. It could have very well been changed if one of the phase of the code does form validation of the uploads, and a second phase actually processes them. Further, I've documented the suggestion to call seek($fh,0,0) to further protect yourself, in case 'upload()' has already been called previously on the /same/ object, and changed the file handle position. 2. Code and tests are provided for uploadInfo(), which was not working /at all/ on subsequent objects. This was reported in at least a couple of other CPAN bugs, including 11895. The upload post data is included as its own file in addition to the main patch, since it contains binary data. Mark
Subject: upload_post_text.txt
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������တ��������Ⰰ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������񀠂��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������တ��������Ⰰ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
Subject: upload_reset.patch
Sat Nov 11 12:13:44 EST 2006 Mark Stosberg <mark@summersault.com> * two bug fixes: 1. The position of file handles is now reset to zero when CGI->new is called. (Mark Stosberg) 2. uploadInfo() now works across multiple object instances. Also, the first tests for uploadInfo() were added as part of the fix. (CPAN bug 11895, with contributions from drfrench and Mark Stosberg). diff -rN -u CGI.pm-3.25-old/CGI.pm CGI.pm-3.25-new/CGI.pm --- CGI.pm-3.25-old/CGI.pm 2006-11-11 12:16:22.000000000 -0500 +++ CGI.pm-3.25-new/CGI.pm 2006-11-11 12:04:53.000000000 -0500 @@ -119,6 +119,7 @@ undef %EXPORT; undef $QUERY_CHARSET; undef %QUERY_FIELDNAMES; + undef %QUERY_TMPFILES; # prevent complaints by mod_perl 1; @@ -504,12 +505,20 @@ # ourselves from the original query (which may be gone # if it was read from STDIN originally.) if (defined(@QUERY_PARAM) && !defined($initializer)) { - foreach (@QUERY_PARAM) { - $self->param('-name'=>$_,'-value'=>$QUERY_PARAM{$_}); - } - $self->charset($QUERY_CHARSET); - $self->{'.fieldnames'} = {%QUERY_FIELDNAMES}; - return; + for my $name (@QUERY_PARAM) { + my $val = $QUERY_PARAM{$name}; # always an arrayref; + $self->param('-name'=>$name,'-value'=> $val); + if (defined $val and ref $val eq 'ARRAY') { + for my $fh (grep {defined(fileno($_))} @$val) { + seek($fh,0,0); # reset the filehandle. + } + + } + } + $self->charset($QUERY_CHARSET); + $self->{'.fieldnames'} = {%QUERY_FIELDNAMES}; + $self->{'.tmpfiles'} = {%QUERY_TMPFILES}; + return; } $meth=$ENV{'REQUEST_METHOD'} if defined($ENV{'REQUEST_METHOD'}); @@ -719,6 +728,7 @@ } $QUERY_CHARSET = $self->charset; %QUERY_FIELDNAMES = %{$self->{'.fieldnames'}}; + %QUERY_TMPFILES = %{$self->{'.tmpfiles'}}; } sub parse_params { @@ -4139,7 +4149,10 @@ $query = new CGI; This will parse the input (from both POST and GET methods) and store -it into a perl5 object called $query. +it into a perl5 object called $query. + +Any filehandles from file uploads will have their position reset to +the beginning of the file. =head2 CREATING A NEW QUERY OBJECT FROM AN INPUT FILE @@ -5848,6 +5861,12 @@ This is the recommended idiom. +For robust code, consider reseting the file handle position to beginning of the +file. Inside of larger frameworks, other code may have already used the query +object and changed the filehandle postion: + + seek($fh,0,0); # reset postion to beginning of file. + When a file is uploaded the browser usually sends along some information along with it in the format of headers. The information usually includes the MIME content type. Future browsers may send diff -rN -u CGI.pm-3.25-old/Changes CGI.pm-3.25-new/Changes --- CGI.pm-3.25-old/Changes 2006-11-11 12:16:22.000000000 -0500 +++ CGI.pm-3.25-new/Changes 2006-11-11 12:09:35.000000000 -0500 @@ -1,3 +1,9 @@ + 1. The position of file handles is now reset to zero when CGI->new is called. + (Mark Stosberg) + 2. uploadInfo() now works across multiple object instances. Also, the first tests + for uploadInfo() were added as part of the fix. (CPAN bug 11895, + with contributions from drfrench and Mark Stosberg). + Version 3.25 1. Fixed the link to the Netscape frames page. 2. Added ability to specify an alternate stylesheet. diff -rN -u CGI.pm-3.25-old/MANIFEST CGI.pm-3.25-new/MANIFEST --- CGI.pm-3.25-old/MANIFEST 2006-11-11 12:16:22.000000000 -0500 +++ CGI.pm-3.25-new/MANIFEST 2006-11-11 12:04:53.000000000 -0500 @@ -53,6 +53,7 @@ t/request.t t/switch.t t/upload.t +t/uploadInfo.t t/upload_post_text.txt t/util.t t/util-58.t diff -rN -u CGI.pm-3.25-old/t/uploadInfo.t CGI.pm-3.25-new/t/uploadInfo.t --- CGI.pm-3.25-old/t/uploadInfo.t 1969-12-31 19:00:00.000000000 -0500 +++ CGI.pm-3.25-new/t/uploadInfo.t 2006-11-11 12:04:53.000000000 -0500 @@ -0,0 +1,76 @@ +#!/usr/local/bin/perl -w + +################################################################# +# Emanuele Zeppieri, Mark Stosberg # +# Shamelessly stolen from Data::FormValidator and CGI::Upload # +################################################################# + +# Due to a bug in older versions of MakeMaker & Test::Harness, we must +# ensure the blib's are in @INC, else we might use the core CGI.pm +use lib qw(. ./blib/lib ./blib/arch); + +use strict; + +use Test::More 'no_plan'; + +use CGI; + +#----------------------------------------------------------------------------- +# %ENV setup. +#----------------------------------------------------------------------------- + +%ENV = ( + %ENV, + 'SCRIPT_NAME' => '/test.cgi', + 'SERVER_NAME' => 'perl.org', + 'HTTP_CONNECTION' => 'TE, close', + 'REQUEST_METHOD' => 'POST', + 'SCRIPT_URI' => 'http://www.perl.org/test.cgi', + 'CONTENT_LENGTH' => 3285, + 'SCRIPT_FILENAME' => '/home/usr/test.cgi', + 'SERVER_SOFTWARE' => 'Apache/1.3.27 (Unix) ', + 'HTTP_TE' => 'deflate,gzip;q=0.3', + 'QUERY_STRING' => '', + 'REMOTE_PORT' => '1855', + 'HTTP_USER_AGENT' => 'Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)', + 'SERVER_PORT' => '80', + 'REMOTE_ADDR' => '127.0.0.1', + 'CONTENT_TYPE' => 'multipart/form-data; boundary=xYzZY', + 'SERVER_PROTOCOL' => 'HTTP/1.1', + 'PATH' => '/usr/local/bin:/usr/bin:/bin', + 'REQUEST_URI' => '/test.cgi', + 'GATEWAY_INTERFACE' => 'CGI/1.1', + 'SCRIPT_URL' => '/test.cgi', + 'SERVER_ADDR' => '127.0.0.1', + 'DOCUMENT_ROOT' => '/home/develop', + 'HTTP_HOST' => 'www.perl.org' +); + +#----------------------------------------------------------------------------- +# Simulate the upload (really, multiple uploads contained in a single stream). +#----------------------------------------------------------------------------- + +my $q; + +{ + local *STDIN; + open STDIN, '<t/upload_post_text.txt' + or die 'missing test file t/upload_post_text.txt'; + binmode STDIN; + $q = CGI->new; +} + +{ + my $test = "uploadInfo: basic test"; + my $fh = $q->upload('300x300_gif'); + is( $q->uploadInfo($fh)->{'Content-Type'}, "image/gif", $test); +} + +my $q2 = CGI->new; + +{ + my $test = "uploadInfo: works with second object instance"; + my $fh = $q2->upload('300x300_gif'); + is( $q2->uploadInfo($fh)->{'Content-Type'}, "image/gif", $test); +} + Files CGI.pm-3.25-old/t/upload_post_text.txt and CGI.pm-3.25-new/t/upload_post_text.txt differ diff -rN -u CGI.pm-3.25-old/t/upload.t CGI.pm-3.25-new/t/upload.t --- CGI.pm-3.25-old/t/upload.t 2006-11-11 12:16:22.000000000 -0500 +++ CGI.pm-3.25-new/t/upload.t 2006-11-11 12:04:53.000000000 -0500 @@ -1,7 +1,7 @@ #!/usr/local/bin/perl -w ################################################################# -# Emanuele Zeppieri # +# Emanuele Zeppieri, Mark Stosberg # # Shamelessly stolen from Data::FormValidator and CGI::Upload # ################################################################# @@ -11,7 +11,7 @@ use strict; -use Test::More tests => 8; +use Test::More 'no_plan'; use CGI; @@ -26,7 +26,7 @@ 'HTTP_CONNECTION' => 'TE, close', 'REQUEST_METHOD' => 'POST', 'SCRIPT_URI' => 'http://www.perl.org/test.cgi', - 'CONTENT_LENGTH' => 3129, + 'CONTENT_LENGTH' => 3285, 'SCRIPT_FILENAME' => '/home/usr/test.cgi', 'SERVER_SOFTWARE' => 'Apache/1.3.27 (Unix) ', 'HTTP_TE' => 'deflate,gzip;q=0.3', @@ -64,17 +64,73 @@ # Check that the file names retrieved by CGI are correct. #----------------------------------------------------------------------------- -is( $q->param('hello_world') , 'hello_world.txt' , 'filename_1' ); is( $q->param('does_not_exist_gif'), 'does_not_exist.gif', 'filename_2' ); -is( $q->param('100x100_gif') , '100x100.gif' , 'filename_3' ); +is( $q->param('100;100_gif') , '100;100.gif' , 'filename_3' ); is( $q->param('300x300_gif') , '300x300.gif' , 'filename_4' ); +{ + my $test = "multiple file names are handled right with same-named upload fields"; + my @hello_names = $q->param('hello_world'); + is_deeply(\@hello_names, [ 'goodbye_world.txt','hello_world.txt' ], $test); +} + #----------------------------------------------------------------------------- # Now check that the upload method works. #----------------------------------------------------------------------------- -ok( defined $q->upload('hello_world') , 'upload_basic_1' ); ok( defined $q->upload('does_not_exist_gif'), 'upload_basic_2' ); -ok( defined $q->upload('100x100_gif') , 'upload_basic_3' ); +ok( defined $q->upload('100;100_gif') , 'upload_basic_3' ); ok( defined $q->upload('300x300_gif') , 'upload_basic_4' ); +{ + my $test = "file handles have expected length for multi-valued field. "; + my ($goodbye_fh,$hello_fh) = $q->upload('hello_world'); + + # Go to end of file; + seek($goodbye_fh,0,2); + # How long is the file? + is(tell($goodbye_fh), 15, "$test..first file"); + + # Go to end of file; + seek($hello_fh,0,2); + # How long is the file? + is(tell($hello_fh), 13, "$test..second file"); + +} + + + +{ + my $test = "300x300_gif has expected length"; + my $fh1 = $q->upload('300x300_gif'); + is(tell($fh1), 0, "First object: filehandle starts with position set at zero"); + + # Go to end of file; + seek($fh1,0,2); + # How long is the file? + is(tell($fh1), 1656, $test); +} + +my $q2 = CGI->new; + +{ + my $test = "Upload filehandles still work after calling CGI->new a second time"; + $q->param('new','zoo'); + + is($q2->param('new'),undef, + "Reality Check: params set in one object instance don't appear in another instance"); + + my $fh2 = $q2->upload('300x300_gif'); + is(tell($fh2), 0, "...so the state of a file handle shouldn't be carried to a new object instance, either."); + # Go to end of file; + seek($fh2,0,2); + # How long is the file? + is(tell($fh2), 1656, $test); +} + +{ + my $test = "multi-valued uploads are reset properly"; + my ($dont_care, $hello_fh2) = $q2->upload('hello_world'); + is(tell($hello_fh2), 0, $test); +} +
My patch for this has been posted here: http://rt.cpan.org/Ticket/Display.html?id=22992 Mark
Lincoln, Thanks for all your work maintaining CGI.pm. This is just a friendly reminder that this ticket as a complete, ready-to-go patch for an important issue. Mark
From: MARKSTOS [...] cpan.org
Lincoln, I see that another CGI.pm release has just gone by. This is just a friendly reminder that this ticket has a complete, ready-to-go patch for an important issue. Thanks, Mark
Patch will appear in 3.29. Next time, just send me the patch via email. I don't use the RT system.
Sorry, that sounded ungrateful. Thank you very much for the patch and doc fixes. It saves me a lot of time.
I'm afraid I have to reopen this bug report and roll back the source code to pre-patch state. The posted patch causes a slew of regression test failures.
I suspect that the upload_post_test.txt file posted here is not what is intended, as it does not correspond to a MIME-encoded file. Please send the correct file to my email address. Lincoln On Fri Mar 30 16:03:04 2007, MARKSTOS wrote: Show quoted text
> > Lincoln, > > I see that another CGI.pm release has just gone by. > > This is just a friendly reminder that this ticket has a complete, > ready-to-go patch for an important issue. > > Thanks, > > Mark
I'm just confirming that I believe this patch was released with 3.29, and this bug can be marked as resolved. Mark