Donnie has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks ! I have spent most of my day in the archives here trying to find a way to "call" another cgi from the end of the "first" cgi. Nothing is working for me - the one's I've found there either don't run at all or give "InFernal Server Errors. Any ideas? There is a wealth of info here but I can make none of these work. The one that seems to come closest to doing something I've posted below. At least this one activates my browser, but ends up not doing the job. Thank you for your time.
<meta http-equiv="refresh" content="0;url=http://redirect.url.here?any + cgi=options&here=too">;

Replies are listed 'Best First'.
Re: Calling a cgi with another cgi
by LTjake (Prior) on Oct 16, 2002 at 01:16 UTC
    I'm not sure you know what you want :)

    But, to do a redirect try this:
    use CGI; use strict; my $q = new CGI; print $q->redirect( -uri => 'http://www.perlmonks.org/' );
    Other than that, I'd need a better description of your problem.

    --
    Rock is dead. Long live paper and scissors!
Re: Calling a cgi with another cgi
by jarich (Curate) on Oct 16, 2002 at 08:55 UTC
    When you call the other cgi, are you trying to get data? Where does the other cgi exist? On another machine? In the same directory? What are you trying to do by calling it?

    Your meta tag tells the browser to go to the next script. If your initial cgi say, takes a form submission, massages/corrects the data and then redirects to the next page that should be fine. If, instead you want it to take the form submission, massage or correct/validate the data and then call another script if it's good or the previous script if it's bad there might be better options.

    Of course, you've probably realised now that you haven't given us enough information.

    Here might be some answers to your question, note that in each I only call one script. It shouldn't be too hard for you to throw conditionals around stuff if that's what you need to do:

    #!/usr/bin/perl -wT # don't forget -T for cgi scripts ##### First some setup use CGI; use strict; my $cgi = CGI->new; # some sort of processing on incomming arguments my %args; foreach my $arg (qw/surname firstname dob pet_name/) { my $tainted = $cgi->param($arg) || ""; ($args{$arg}) = ($tainted =~ m!([\w _/.-]+)!; # pick your sa +fe # input charac +ters } print $cgi->header; ##### Now some options/interpretations #### # a) call fish.cgi with these results and display it's output. # this script may be on another server: { use LWP::UserAgent; $SIG{ALRM} = sub {die "LWP request timed out."}; my $url = "http://www.somewhere.com.au/fish.cgi"; # add any query string you want here ie: my $clean_surname = $cgi->escape($args{surname}); $url .= "?surname=$clean_surname"; # Create a user agent object my $ua = new LWP::UserAgent; # create the request object (POST or GET) my $req = new HTTP::Request ("POST" => $url); # Set the POSTed input (if necessary) # I'm certain there's a better way to do this. my $input; foreach my $value (keys(%args)) { my $clean_value = $cgi->escape($args{$value}); $input .= "$value=$clean_value\n"; } # Set the content type if necessary $req->content_type('application/x-www-form-urlencoded'); # Give the request object the POSTed input $req->content($input); my $content; eval { alarm(60); # time out after 1 minute # Pass request to the user agent and get a response ba +ck my ($code, $msg, $headers); my $res = new HTTP::Response ($code, $msg, $headers, $ +content); $res = $ua->request($req); # Get our content $content = $res->content(); ### Finished call to the other script, so cancel the a +larm alarm(0); }; # Check for error if($@ =~ /timed out/) { die $@; } # else do something with $content print $content; } #### # b) Call a script from some directory directly (without LWP) # and grab the results { my $otherscript = "/some/directory/somewhere/script.pl"; # pretend we're using CGI in this script and that # we've set it up (different for different versions) t +o # be okay with stuff like: surname=foo etc my $input; $input = "surname=$args{surname} firstname=$args{firstname}"; # etc, the foreach above is better than this of course +. # if you want results here to be an array of lines, # where the first element of the array is the first li +ne # returned and the second is the second line returned +etc # s/\$results/@results/ and it'll behave that way my $results = qx/$otherscript $input/; # do something with our results: print $results; } #### # c) Call another script from some directory directly # and have it take over things from here: { my $otherscript = "/some/directory/somewhere/script.pl"; my $input; $input = "surname=$args{surname} firstname=$args{firstname}"; exec($otherscript, $input); # the end, this script won't come back from here. }
    The blocks around each option are more for visual distinction and are not strictly necessary (except for the fact that I do my $otherscript twice etc.

    If you go with the first idea I also suggest moving the use LWP::UserAgent; to the top of your script up near use strict; because it'll make more sense to your scripts maintainer.

    If you have any questions about these answers feel free to ask. If you want to have another go at trying to ask your question that might be a good idea too. ;) You can most easily do this by replying to your original post here with the answers the the questions we've asked you.

    Hope it helps.

    jarich

Re: Calling a cgi with another cgi
by true (Pilgrim) on Oct 16, 2002 at 01:57 UTC
    Here's a one line solution to redirect a cgi to another cgi.
    #Your Perl Program here print "Location:http://www.perlmonks.org\n\n";
    Don't output a content-type header in your cgi.
    The Location tag is a redirect ala http & apache.
    Just output the Location call above and you
    will be redirected on the server.

    jtrue

      Actually, no.

      Sorry, but that doesn't work. I've just tried the following script:

      #!/usr/bin/perl use warnings; use strict; print "Location:http://www.perlmonks.org/\n\n";

      And it failed - no redirection, just the string "Location:http://www.perlmonks.org/\n\n" in my browser.

      The reason it failed on my machine is because (IIRC) Apache looked at the first few lines of output of the script, didn't see a header, and so added the header itself (specifying plain text) before sending the output of the script.

      You can make yours work by adding the line

      print "HTTP/1.1 302 Moved\n";

      above the existing print() line.

      I've also just tried the following:

      #!/usr/bin/perl use warnings; use strict; use CGI; my $q = new CGI; print $q->redirect( -uri => 'http://www.perlmonks.org/' );
      Which outputs:
      Status: 302 Moved location: http://www.perlmonks.org/
      When called on the command line.

      When called by the webserver, it outputs a valid, correct, and working header that redirects the client.

      I'm not completely against printing the headers yourself for such a simple task, but I am against printing headers wrongly. Using the CGI module saves you from having to read the RFCs to find out why your script didn't work, and will save time: it took about 5 seconds to produce the CGI.pm method, and closer to 5 minutes for me to make your version work1

      When there's a monastery full of monks suggesting 'use CGI;', perhaps they're onto something

      Please Note:
      This isn't intended to be a telling-off: I did honestly want to see if your version worked.
      Cheers.


      1: - I'm not good at creating HTTP headers, so I don't claim that to be a good comparison.
      davis
      Is this going out live?
      No, Homer, very few cartoons are broadcast live - it's a terrible strain on the animator's wrist

      Update: After an interesting ChatterBox discussion with true, and some playing around with webserver configs, I've come to the following conclusion (for apache):

      true's solution works, if:

      1. You're not using modperl, or
      2. You are using modperl, but you've got "PerlSendHeader On" in your httpd.conf, or
      3. You play around with it to add the correct HTTP headers yourself

      The CGI.pm solution works whatever because it checks to see if modperl's running, and whether the header's been sent.

      References: the modperl guide, and Writing Apache Modules with Perl and C.

        Thanks for the info and input.
        I know CGI.pm is cool.
        This does redirect on my apache 1.3.6 webserver.
        I tried it again to be sure.
        #!/usr/bin/perl -w use strict; #Your Perl Program here print "Location:http://www.perlmonks.org\n\n"; exit;

        FYI
        I also tried to add your 302 tag but it failed.
        #!/usr/bin/perl -w use strict; ##Your Perl Program here print "HTTP/1.1 302 Moved\n"; print "Location:http://www.perlmonks.org\n\n"; exit;
        The httpd log reports:"...malformed header from script. Bad header=HTTP/1.1 302 Moved:..."

        cheers,
        jtrue
        First off, thanks to davis, your time has been very valuable.
        I should have clarified my current non-modperl status
        in my earlier post.
        Sadly i can't test under mod_perl right now.
        But, if anybodies is curious, I tested
        the code below successfully on
        Win2k apache and linux apache.
        Running perl 5.005 sans mod_perl
        #!/usr/bin/perl -w use strict; print "Location:http://www.google.com\n\n"; exit;
        Also, note on both platforms,
        adding the line
        print "HTTP/1.1 302 Moved\n";
        causes a mal-formed header error.

        The Motto of the story...
        use da CGI module!

        jtrue

        <edit:made grammar edit
      jtrue: It looks like your scheme would work - however, there is a problem. If I DO NOT use the header "print "Content-type: text/html\n\n";" this script will not run. Just gives the dreaded "Internal Server Error" message. Maybe I cannot redirect from a script that uses this header - because it just won't run without it?? Should I just abandon the idea?

        Donnie, Don't give up just yet. Make sure you don't print anything to STDOUT before you output the Location redirect. Try this code on your server as is, then add your code, avoid printing to STDOUT.

        #!/usr/bin/perl -w use strict; #!/usr/bin/perl #Your Perl Program here #DO NOT output anything to STDOUT print "Location:http://www.google.com/search?q=perl\n\n"; #OUTPUT ANYTHING OR NOTHING ##Your Perl Program here exit;

        Things you probably know anyway.

      • Apache is the guy doing the work here.
      • Perl doesn't know you are 'redirecting' it anywhere.
      • HTTP HTTP/1.x is a protocal in and of itself.
      • Read about the HTTP Location Header here
      • The above code works on Apache 1.3.6 with perl5.005
      • Here's a working link to prove it.
      • http://perl.to/d.cgi?pm=Donnie

        jtrue
Re: Calling a cgi with another cgi
by belg4mit (Prior) on Oct 16, 2002 at 02:07 UTC
    A dirty trick I sometimes use (there are many caveats associated with this) is to do the second CGI from the first. This has the advantage of not spawning another perl process, and (usually) perpetuating your form data. It also prevents browser history clutter.

    --
    perl -wpe "s/\b;([mnst])/'$1/g"

Re: Calling a cgi with another cgi
by nutshell (Beadle) on Oct 16, 2002 at 01:29 UTC
    Maybe this:
    use LWP::Simple; print get('http://redirect.url.here?anycgi=options&here=too');
    (include onto your page the contents of 'http://redirect.url.here?anycgi=options&here=too')

    --nutshell

Re: Calling a cgi with another cgi
by Donnie (Acolyte) on Oct 16, 2002 at 20:01 UTC
    Just a little more insight into what may be happening. After trying most of your fine suggestions, it seems these ideas would work except fot the header I use: "print "Content-type: text/html\n\n";" However, this script will not run without that header in place. Just errors out with: Internal Server Error. So - it's looking like I have to abandon the idea of doing a redirect from this particular script, unless I can find a replacement for that header that will still allow the script to run.
      Donnie you haven't shown us any of your code yet, but perhaps you're getting the "Internal Server Error" because the script you're redirecting to doesn't print out the required http header itself?

      For example:

      #!/usr/local/bin/perl -w ##### file1.cgi use CGI; use strict; my $q = new CGI; print $q->redirect( -uri => 'file2.cgi' ); exit; ##### cut here ##### #!/usr/local/bin/perl -w ##### file2.cgi print "foo"; exit;
      will cause an internal server error because we're not printing out the required HTTP header. Our webserver doesn't care what script prints out that header, but it does expect that it'll be printed out before anything else is. If we change file2.cgi to be:
      #!/usr/local/bin/perl -w ##### file2.cgi use CGI; use strict; my $cgi = new CGI; print $cgi->header(); print "foo"; exit;
      we don't get any error.

      Perhaps that is something you need to check.

      jarich