(jcwren) RE: amelinda's problem
by jcwren (Prior) on Sep 30, 2000 at 04:37 UTC
|
I realize you said that you can't get someone to install a lot of modules, but libwww-perl is completely self-contained, as nearly as I can tell. And within said bundle would be the perfect module you're looking for, HTML::Form. This will allow you to submit forms, takes care of all the nastiness of making sure the headers are right, was written by Gisle Aas, and is well tested. There's even an example of using it here on the site, Homenode Updater (shameless self plug).
When I was playing with it earlier, I was using it to submit files, also. If you have any possibility of getting someone to install a module, this would be the way to go.
--Chris
e-mail jcwren | [reply] |
|
|
| [reply] |
|
|
| [reply] |
(jcwren) RE: amelinda's problem (I am a hardheaded SOB)
by jcwren (Prior) on Oct 03, 2000 at 01:14 UTC
|
And because I am a hardheaded S.O.B., I will still try to prove a point. Here's both the server and client side example of using HTML::Form to upload a file.
Put the first file in your cgi-bin directory, and set it to be executable. A good name would be 'htmlformtest.pl'. Make sure you can get to it with your web browser. Put the second file in your user directory. Change the '$site' variable to point to the script in the cgi-bin directory. Run it. You should find a file in your local directory called 'testfile.text, and a file in /tmp, called 'uploaded.file'. These two files should be indentical in content. It seems to work here.
Some of this code isn't pretty, doesn't do enough error checking, etc. It's demo code.
#!/usr/local/bin/perl -w
use strict;
use CGI;
use IO::File;
use POSIX qw (tmpnam);
my $finalname = '/tmp/uploaded.file';
{
my $tmpnam;
my $html = new CGI;
print $html->header;
if (!defined ($html->param ('uploadname')) || $html->param ('upload
+name') eq '')
{
print while (<DATA>);
print $html->end_html;
exit;
}
my $fn = $html->param ('uploadname');
my $fh = $html->upload ('uploadname');
my $fd = '';
if (!defined ($fh))
{
print "\$fh is not defined!\n";
print $html->end_html;
exit;
}
while ((length ($fd) <= (64 * 1024)) && read ($fh, my $buffer, 1024
+))
{
$fd .= $buffer;
}
if (length ($fd) == (64 * 1024))
{
print "File too big!";
print $html->end_html;
exit;
}
#
# Get a temporary file name we know is ours. The loop resolves th
+e race condition possibility.
#
for (;;)
{
$tmpnam = tmpnam ();
sysopen (TMP, $tmpnam, O_RDWR | O_CREAT | O_EXCL) && last;
}
close (TMP);
#
# Create the temporary input file for the size-getter and thumbnai
+l maker
#
if (open (SOURCE, ">$tmpnam"))
{
print SOURCE $fd;
close SOURCE;
}
else
{
print "Couldn't open $tmpnam for writing: $!";
print $html->end_html;
exit;
}
rename ($tmpnam, $finalname);
print "File uploaded OK, saved as $finalname";
exit;
}
__DATA__
<HTML>
<HEAD>
<TITLE>File Upload Test</TITLE>
</HEAD>
<BODY>
<FORM METHOD="POST" ENCTYPE="multipart/form-data">
<TABLE BORDER="0" ALIGN="CENTER">
<TR>
<TD ALIGN="CENTER">
<P>Select file to upload: <INPUT TYPE="FILE" NAME="uploadn
+ame"></P>
</TD>
</TR>
<TR>
<TD> </TD>
</TR>
<TR>
<TD ALIGN="CENTER">
<INPUT TYPE="SUBMIT" NAME="sendfile" CHECKED="CHECKED" VAL
+UE="Send me that file, Cowboy!">
</TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
#!/usr/local/bin/perl -w
use strict;
use Carp;
use LWP::UserAgent;
use LWP::Simple;
use HTML::Form;
my $site = 'http://linux/release/cgi-bin/htmlformtest.pl';
my $testfile = './testfile.txt';
#
#
#
{
if (!-e $testfile)
{
open (FH, ">$testfile") || die $!;
print FH "\nThis is a test file.\n";
print FH "It has been uploaded via HTML::Form\n";
print FH "And it has 5 lines in it.\n\n";
close FH;
}
my $req = get ($site);
die "Eeek! Request failed.\n" if !$req;
#
#
#
my $form = HTML::Form->parse ($req, $site);
if ($form->find_input ('uploadname'))
{
$form->value ('uploadname', [$testfile => [$testfile]]);
my $userAgent = LWP::UserAgent->new;
my $res = $userAgent->request ($form->click);
die sprintf ("Eeek! Request failed (%s)\n", $res->status_line) u
+nless ($res->is_success);
print "\n", $res->content, "\n";
print "I seem to have uploaded the file OK!\n\n";
}
else
{
die "Eeek! Whatever page we got, didn't have 'uploadname' as a
+field!\n";
}
}
--Chris
e-mail jcwren | [reply] [d/l] [select] |
|
|
Thanks for being persistent! This is exactly the kind of
thing I've been looking for as an example!
I find it kind of interesting that you get
around the thing I didn't see in HTML::Form by going and
getting the form and then searching it for the right thing
and filling it out blindly. I hadn't thought of doing that;
it would be good errorchecking - make sure you can get to
the site before submitting.
For reference, here is some code I wrote when I was still
trying to use libwww-perl (it didn't work, can you tell
me why? (serious query)):
#!/usr/bin/perl
use HTTP::Request::Common;
use LWP::UserAgent;
use CGI qw(header -no_debug);
my $URL = 'https://www.mydomain.com/upload.html';
my $req = POST $URL,
Content_Type => 'form-data',
Content => [
user => 'username',
pass => 'password',
FILE => ['./binaryfile'], # this file will be uploaded
];
my $res = LWP::UserAgent->new->request($req);
print header, $res->is_success ? $res->content :
$res->status_line;
Yes, yes, Carp, strict, -w and all that. Consider it read,
for conciseness' sake. Maybe I'll try it again using HTML::Form. | [reply] [d/l] |
|
|
Well, it passed the syntax check. Since I don't have a server that's configured to run https, I can't really test it. Perhaps you could describe the error in a little more detail.
--Chris
e-mail jcwren
| [reply] |
Re: amelinda's HTTP/MIME/file upload/not-a-cgi-but-a-client/minimal-module/perl problem
by amelinda (Friar) on Oct 06, 2000 at 03:32 UTC
|
Thank you everyone who helped me with this, especially
jcwren and fastolfe.
In the end, it turned out to be a combination of factors
involving UNIX/Windows CRLF issues, MIME encoding issues,
an important and missing piece of HTTP syntax, assumptions
by the cgi-script recieving the form, and general weirdness.
jcwren's working LWP code massively helped me decipher
the issues involved (especially that damned missing
Content-Length needed for the FILE parameter), to the
point where I could get my non-LWP code working and look at
the cgi-bin's output and go "WTF?" and figure out that it
was expecting it to be mimencoded and on top of that,
mimencoded in a Windows environment! But now the cgi's
chop;chop;$_ = "$_\n"; is
chomp;chomp;$_ = "$_\n"; instead
and all is well with the world. | [reply] [d/l] [select] |
Re: amelinda's HTTP/MIME/file upload/not-a-cgi-but-a-client/minimal-module/perl problem
by Fastolfe (Vicar) on Sep 30, 2000 at 03:07 UTC
|
Are you sure Content-length is just the length of each item of content? I was always under the impression that this specified the amount of data the server was going to have to read after you were done with your headers. If so, you have to include all of your additional MIME headers, boundaries, etc.
I'm not 100% certain about this, but it is consistent with your symptoms, so I thought I'd mention it. | [reply] [d/l] |
|
|
Right. That's why the next line is
$len += 514;. It accounts for those extra
bits (since they remain constant throughout all invocations
of the code).
| [reply] [d/l] |
|
|
We've been going back and forth in the Chatterbox for a bit, and I know you're pretty sure that 514 number is accurate, but I still think it isn't. I modified your code to append everything after your HTTP headers to $data, and added these two lines:
print "\$len=$len\n";
print "data length=" . length($data) . "\n";
Now in theory, these should be the same, but they aren't:
(fastolfe) eddie:~$ perl test user password test.file
$len=555
data length=580
Try adding 25 to your number and see if your problem goes away.. *shrug*. | [reply] [d/l] [select] |
|
|
|
|
|
|
|
|
| [reply] |