Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

using CGI on HTTP::Request from HTTP::Daemon

by gregor-e (Beadle)
on Oct 24, 2003 at 23:35 UTC ( [id://302003]=perlquestion: print w/replies, xml ) Need Help??

gregor-e has asked for the wisdom of the Perl Monks concerning the following question:

An easy one (I hope) - how does one process the parameters from an HTTP::Request they have received using HTTP::Daemon? I'm hoping there's a way to create a CGI object, initialized with the HTTP::Request, like:
use HTTP::Daemon; use CGI qw/:standard/; my $httpd = new HTTP::Daemon(LocalPort => 8765); while (my $connection = $httpd->accept()) { # spawn child to deal with this request fork() && next; while (my $request = $connection->get_request()) { ### I wish this would work. ### my $query = new CGI($request); ... process CGI parms in the usual way
Is there a way to feed an HTTP::Request object into CGI like that? Otherwise, how do people normally process HTTP::Requests?

Replies are listed 'Best First'.
Re: using CGI on HTTP::Request from HTTP::Daemon
by chromatic (Archbishop) on Oct 24, 2003 at 23:49 UTC

    Ugh, that's trickier than it looks. The easiest way I've found is to tie a filehandle (wait, come back!), handle the reading and buffering yourself, and be very sure to read only the headers from the incoming request. It's a little messy, but it works.

    I have working code that does this in evserver, though POST doesn't work with CGI. I've asked Lincoln about it, but haven't heard back. (CGI::Simple does work now, though, thanks to tachyon.)

      I was trying to get multipart/form-data (file uploads) working with CGI::Simple when I noticed that it's looking for the boundary in $ENV{CONTENT_TYPE}, which is there in the request. This will get it working with CGI, but not CGI::Simple (it hangs). You can omit all your HTTP::Daemon::ClientConn->overload stuff
      sub serve_everything { my ($conn, $req) = @_; ... $ENV{CONTENT_TYPE} = join('; ', $req->content_type) || ''; ... local *main::STDIN = $conn; use CGI; my $cgi = CGI->new();

      MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
      I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
      ** The third rule of perl club is a statement of fact: pod is sexy.

        This snippet of code:

        my($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\";,]+)\"?/;

        Is common to both CGI and CGI::Simple. Do you have a complete test case that generates the hang? That would make it easier to debug.....

        cheers

        tachyon

Re: using CGI on HTTP::Request from HTTP::Daemon
by lachoy (Parson) on Oct 25, 2003 at 13:32 UTC
    I have some code to do this in OpenInteract2. See the code from CPAN, in particular the '_parse_request()' routine. I haven't tested it extensively (boo!), but GET is easy, POST (without uploads) seems easy, and POST (with uploads) is done manually.

    I can't take credit for it, I just cribbed most (all?) of this from the OpenFrame project :-)

    Chris
    M-x auto-bs-mode

Re: using CGI on HTTP::Request from HTTP::Daemon
by tachyon (Chancellor) on May 26, 2004 at 07:52 UTC

    Don't have time tonight - dinner and family beckon but if you replace these two subs with the code below it works fine (you can also delete the _read_data() sub which is dead. Have not had time to test it properly yet but this seems to do the trick. BTW uploads are disabled by default so you will need to $CGI::Simple::DISABLE_UPLOADS = 0;

    sub _parse_multipart { my $self = shift; my ($boundary) = $ENV{'CONTENT_TYPE'} =~ /boundary=\"?([^\";,]+)\" +?/; unless ($boundary) { $self->cgi_error( '400 No boundary supplied for multipart/form +-data' ); return 0; } # BUG: IE 3.01 on the Macintosh uses just the boundary, forgetting + the -- $boundary = '--'.$boundary unless $ENV{'HTTP_USER_AGENT'} =~ m/MSI +E\s+3\.0[12];\s*Mac/i; $boundary = quotemeta $boundary; my $got_data = 0; my $data = ''; my $length = $ENV{'CONTENT_LENGTH'} || 0; my $CRLF = $self->crlf; READ: while ( $got_data < $length ) { last READ unless sysread( STDIN, my $buffer, 4096 ); $data .= $buffer; $got_data += length $buffer; BOUNDARY: while ( $data =~ m/^$boundary$CRLF/ ) { next READ unless $data =~ m/^([\040-\176$CRLF]+?$CRLF$CRLF)/ +o; my $header = $1; (my $unfold = $1) =~ s/$CRLF\s+/ /og; my ($param) = $unfold =~ m/form-data;\s+name="?([^\";]*)"? +/; my ($filename) = $unfold =~ m/name="?\Q$param\E"?;\s+filen +ame="?([^\"]*)"?/; if (defined $filename ) { my ($mime) = $unfold =~ m/Content-Type:\s+([-\w\/]+)/i +o; $data =~ s/^\Q$header\E//; ( $got_data, $data, my $fh, my $size ) = $self->_save_ +tmpfile( $boundary, $filename, $got_data, $data ); $self->_add_param( $param, $filename ); $self->{'.filehandles'}->{$filename} = $fh if $fh; $self->{'.tmpfiles'}->{$filename} = {'size'=>$size, 'm +ime'=>$mime } if $size; next BOUNDARY; } next READ unless $data =~ s/^\Q$header\E(.*?)$CRLF(?=$bounda +ry)//s; $self->_add_param( $param, $1 ); } } return $got_data; } sub _save_tmpfile { my ( $self, $boundary, $filename, $got_data, $data ) = @_; my $fh; my $CRLF = $self->crlf; my $length = $ENV{'CONTENT_LENGTH'} || 0; my $file_size = 0; if ( $self->{'.globals'}->{'DISABLE_UPLOADS'} ) { $self->cgi_error("405 Not Allowed - File uploads are disabled" +); } elsif ( $filename ) { eval { require IO::File }; $self->cgi_error("500 IO::File is not available $@") if $@; $fh = new_tmpfile IO::File; $self->cgi_error("500 IO::File can't create new temp_file") un +less $fh; } # read in data until closing boundary found. buffer to catch split + boundary # we do this regardless of whether we save the file or not to read + the file # data from STDIN. if either uploads are disabled or no file has b +een sent # $fh will be undef so only do file stuff if $fh is true using $fh + && syntax $fh && binmode $fh; while ( $got_data < $length ) { my $buffer = $data; last unless sysread( STDIN, $data, 4096 ); # fixed hanging bug if browser terminates upload part way thro +ugh # thanks to Brandon Black unless ( $data ) { $self->cgi_error('400 Malformed multipart, no terminating +boundary'); undef $fh; return $got_data; } $got_data += length $data; if ( "$buffer$data" =~ m/$boundary/ ) { $data = $buffer.$data; last; } # we do not have partial boundary so print to file if valid $f +h $fh && print $fh $buffer; $file_size += length $buffer; } $data =~ s/^(.*?)$CRLF(?=$boundary)//s; $fh && print $fh $1; # print remainder of file if valid $fh $file_size += length $1; return $got_data, $data, $fh, $file_size; }

    cheers

    tachyon

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://302003]
Approved by HyperZonk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (7)
As of 2024-04-18 08:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found