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

Very Respected Revealers of Wisdom (and Tricks),
In the following script for password protecting a page (just a light password protect) that will then shoot the visitor through to another page (myview.cgi, which is in the same directory as this script), the redirect will not work. The redirect instructions get printed out to the display screen, they do not end up in the browser as the new URL. You'll see that I have not included a $query->new_HTML line in order to try to remedy the problem. Still doesn't work. Any monk eyes out there to spot the problem?
#!/usr/bin/perl use CGI; $query = new CGI; print $query->header; print $query->start_form; print "Enter the password: ",$query->textfield('pass',$default_name,10 +),"\n"; &submit_parameters($query) if $query->param('action') eq +'Submit'; print $query->submit('action','Submit'); print $query->end_form; sub submit_parameters { local($query) = @_; local($filename) = &check_name($query->param('pass')); if($filename) { print $query->redirect(-target => 'ResultWindow', -expires + => 'now', -uri=>'http://lauragarcia.wso.net/CGI/mySQLeditor/myview.cgi'); } } sub check_name { $password="muppets"; local($name) = @_; unless ($name eq $password) { print "<P>Try it again!"; return; } return "$name"; }
Eternally grateful! laura.guimauve

Replies are listed 'Best First'.
Re: Redirect page (newbie)
by Masem (Monsignor) on May 04, 2001 at 20:42 UTC
    The redirect must happen instead of the header (as it's basically a special HTTP header), which means that you can't call it after you've printed the CGI header. The easy way to fix it in your script is move the call to submit_parameters just before the cgi->header line.
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
      Perfect! (muchas thanks).
      Now I would never have dreamed of moving the submit_parameters line before the cgi->header line because I assume the form itself won't print to the screen if cgi->header has not been processed first. Ouch: I don't understand why this fix works!

      laura.guimauve

        First, ever web page that is sent, static or dynamic, must begin with the HTTP editor, typcially as simple as:
        Content-Type: text/html
        (eg, ending with two \n\n); this tells the browser how to 'render' the given page. If you were sending, say, a PDF file, the server should send "Content-Type: application/pdf\n\n", and the browser says "Hey, that's a PDF file, let me launch the PDF plug-in". The HTTP header is a way for content negotiation. But also, if you want to redirect the user without using META commands, you can use the HTTP header line "Redirect: <url>" (I believe that's the format), instead of sending a Content-Type, so that the browser recognizes that you want to send the user elsewhere. If the browser saw the Content-Type line first, it will ignore the Redirect, since it's expecting only data from here out. (The header also contains any other negotiated data that might be sent, such as cookies to be retrieved, or cookies to be sent). Thus, you can only print the HTTP header once, whether it be a Content-Type, a Redirect, or the other limited forms that HTTP standards allow.

        CGI.pm of course makes this easy to do since it provides ->header() and ->redirect() functions. But the same logic applies: you can only call any one of these once for a given page; once it's printed, further header functions will have no effect.

        So in your case, you only want the header to print if the login is (still) invalid, otherwise you will redirect the user. So the logic that you almost had correct would be to check the login first, then if validated, print the ->redirect(), otherwise, print the ->header() and the login form again. In either case, you only use one header function during the printing of the page, and that will be the first thing printed, triggering the right effects at the end browser.


        Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
Re: Redirect page (newbie)
by chipmunk (Parson) on May 04, 2001 at 20:46 UTC
    By the time you're ready to print the redirect, you've already printed an HTTP header at the top of the script: print $query->header; You need to determine whether you're displaying the form or doing a redirect before you print anything. Do the parameter check first, then print the redirect if every checks out, or print the form otherwise.
Re: Redirect page (newbie)
by deryni (Beadle) on May 04, 2001 at 21:15 UTC
    I'm writing a similar program and I have this code:
    #!/usr/local/bin/perl -w use strict; use CGI; my $q = CGI::new(); $q->use_named_parameters(); open (PASSWD, ".PASSWORD") or die "Couldn't open file"; my $matched= 0; my $queried_user = $q->param(-name=>"user"); my $queried_pass = $q->param(-name=>"pass"); while (<PASSWD>) { my ($user,$pass) = split(/\s/,$_); if (($queried_user eq $user) and ($queried_pass eq $pass)) { $matched = 1; $q->redirect("works.html"); } } if (!$matched) { print $q->header() . $q->start_html; print "Bad Username/Password combination<br>"; print $q->end_html; }
    but every time I try to run it I get an internal server error it's not
    my system so I can't easily check the server logs for the specific error
    Any ideas?

    both .PASSWORD and works.html are in the same directory as the script

    one more question, when I run this program in interactive
    mode from the command line am I supposed to be seeing the
    redirected website print out or what? right now I get nothing

    Thanks for the help

    -Etan
      Make sure you print the redirect,

      print $q->redirect("works.html");
      Also do not forget to close the password file.

      -= Ozzy =-
        Thanks -= Ozzy =-, I'm not sure how I missed that.
        I still need help with the Internal Server Error though.


        -Etan

        P.S. code is as above but "$q->redirect("works.html");" changed to
        "print $q->redirect("works.html");"
        and added "close PASSWD;" after the end of the while loop
      Try a print in front of the redirect().
Re: Redirect page (newbie)
by Anonymous Monk on May 04, 2001 at 21:09 UTC
    The redirect isn't working because you have already printed a webpage. When you redirect you must print the redirect header as the only output of the script and then exit with no other output. You should either print the form OR call the submit_parameters function.

      Actually, you can (and, perhaps, "should") print a web page after a Redirect. The *original* reason was for ancient browsers which might not understand the redirection command. Nowadays, that's mostly limited to a few "dumb" robots and so forth, so the page will generally be ignored. The idea is that the HTML should say something like:


      Sorry, you're at the wrong place. Click me to get where you want to be.
        Some webservers send out their own headers for cgi. This problem bit me on a win32 based webserver once. You may want to telnet to port 80 and GET /path/to/your/script.pl and check what headers are returned.
Re: Redirect page (newbie)
by DrZaius (Monk) on May 04, 2001 at 21:47 UTC
    You've already printed the header. This means you are getting two headers.

    If you want to redirect, you have to only print the redirect header.

    Why are constructing your html with perl? You could make your setup infinitely better by turning this script into two parts. First, put your login form in a static html page and then have your cgi script do the validating and redirecting.

    For example, you go to login.html which you put your username/password in. When you submit your form, you go to cgi-bin/login.cgi which authenticates your credentials and redirects to myview.cgi.

    Also, how is your myview.cgi authenticating? Can I bypass your security by going staight to myview.cgi?

      I'm constructing the html with perl because once I discovered one could it seemed more efficient. Until now, when a problem like this pops up and shows a good reason for not doing so.

      As for your thornier question about authentication (which I'm grateful for by the way), my shameful answer is yes--one can go straight to myview.cgi anyway. I know: this is ridiculous. But as a newbie, I'm overcoming programming hurdles step by step. It's going to be a long road...

      So, what should I be looking up here at the site to find out everything I need to know about authentication?

      laura.guimauve

        Well, my best advice is to read the manuals for your webserver software. Generally, they have authentication mechanisms built into them.

        If you are using Apache, go to apache.org and search around for 'AuthBasic' .. there are more authentication schemes available that use cookies, databases and other goodies as well.

        enjoy.

        Oh hey - another comment that may help you. If you want to password protect a web page on a Unix based system, you should read about htpasswd.

        Here is one explanation of how to set it up.

        It's really simple to set up, and is quite secure. No worries about someone bypassing authentication and loading a web page they shouldn't see.

Re: Redirect page (newbie)
by Galen (Beadle) on May 04, 2001 at 23:43 UTC
    Give this a try....an easy way to redirect.
    print "Location:myview.cgi";
Re: Redirect page (newbie)
by Anonymous Monk on May 06, 2001 at 23:37 UTC

    The "redirect" instruction forms a HTTP header, but you're already printing an HTTP header in your script, before you check the password value. perldoc CGI says:

    # The redirect() function redirects the browser to a
    # different URL.  If you use redirection like this, you
    # should not print out a header as well.

    I suggest you move the &submit_parameters routine up to just below $query = new CGI. Bear in mind that you're invoking the script srice, once to print what's effectively a static page, and once to process the result; you might want to consider using a static HTML page to contain the form, and restricting your script's functionality to input-checking and redirection

    Hope this is of some help.

    Roger Burton West

Re: Redirect page (newbie)
by mattr (Curate) on May 07, 2001 at 16:42 UTC
    When I'm debugging something like this (just did a biggy) I print "Content-type; text/html\n\n"; at the top of the program even before "use" statements. Then you can see what is getting printed.

    One problem you may see if you follow this track long enough is that cookies and redirecting don't like each other. Another headers problem. My solutions were,
    1) keep track of how many times you print $q->header
    2) to keep sane, slurp in a file and print it out instead of redirecting to it, if you are going insane
    3) do cookies in Javascript.. and write variables into the javascript at runtime by using a template which you've actually slurped in with (2) above.
    4) if you must do cookies in perl, get all your functions that do cookies and put them all together into a couple of functions like doallmycookies(). Or better yet stick everything inside one cookie. I got away with a heavily javascripting page that opens up first and finds out who's knocking on the door, but that's only because a client asked for lots of functions that wanted to use cookies at the end of the project..

    I believe you can even roll your own comlicated headers in text but I prefer CGI to keep sane.. maybe you want to read the RFC if you get really into it.

    P.S. If anyone knows about a non-mod_perl way to do clickpath tracking, so that the cookie gets into the apache log file, I'm interested! (no to webbugs..) I've done mod_perl but this is for a server where it isn't so easy to turn it on and off and shake it around in the air.

    Hope this helps.