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

I am trying to make a script that check for a cookie and redirects the user to one page if it does not exists. If it exists I don't want the script to do anything so the reset of the HTML page that calls it (via SSI) loads. Problem is I can't figure out how to make the redirect happen. Can anyone help me? The code I have is:
#!perl -w use strict; use CGI q~:standard~; use DBI; use CGI::Cookie; use CGI::Carp q~fatalsToBrowser~; my(%Cookies, @Values, $Username, $Password, $Error, $DBH, $STH); print "Content-type: text/html\n\n"; %Cookies = fetch CGI::Cookie; if ($Cookies{'FFAdmin0229'}) { @Values = $Cookies{'FFAdmin0229'} -> value; $Username = $Values[0]; $Password = $Values[1]; } else { print redirect(-location => 'http://admin.ffinfo.com/'); }
The redirect code works on the login check script but when I use it here it just prints "Status: 302 Found Location: http://admin.ffinfo.com/" The HTML code I am using is this
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ +/www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!--#exec cgi="/ssi/checkcookie.pl"--> <html xmlns="http://www.w3.org/1999/xhtml">

Replies are listed 'Best First'.
Re: Need help with redirect
by almut (Canon) on Jun 02, 2009 at 00:36 UTC
    here it just prints "Status: 302 ...

    This is because you've already output

    print "Content-type: text/html\n\n";

    before issuing the redirect.  (It must be the first thing output by the script, otherwise - if you print it after the header section - it will be treated as regular content.)

      That makes sense. I moved the print content type line and now I get a big "Object Moved This Document can be found here" message, still no redirect.

        I think what you're trying to do (using a HTTP redirection header with SSI) isn't going to work that way. I don't usually use SSI, but I think the additional magic in the handling of content vs. headers that would be required here simply isn't implemented with most web servers.

        Essentially, there are three ways to redirect:

        • HTTP redirect (what you're trying)
        • HTML <meta http-equiv="refresh" content="0;url=http://..." />
        • JavaScript

        You could try method 2, though, if you really need to embed the script's output into some HTML page via SSI.  Using <meta http-equiv="refresh" ...>, the redirect instruction becomes part of the HTML page, which you've already begun outputting, when the SSI instruction is being encountered.

        Update: I didn't clue in that you were launching the script via SSI. In SSI includes, the header is apparently ignored (which makes sense cause you can't send multiple headers). See almut's reply instead.


        It works fine for me

        #!/usr/bin/perl -w use strict; use CGI q~:standard~; use DBI; use CGI::Cookie; use CGI::Carp q~fatalsToBrowser~; print redirect(-location => 'http://admin.ffinfo.com/');

        But I could see it failing if the script was fetched executed using POST instead of GET.

        If the 302 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

        You may want a 303.

        The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource. This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource.

        If you can't get it to work, execute the script from the prompt and show us what you get. You may also want to find out what the browser is receiving using a browser plugin or a packet sniffer.

        That is called a redirect -- you can configure browsers to ignore redirects
Re: Need help with redirect
by scorpio17 (Canon) on Jun 02, 2009 at 12:47 UTC

    I would suggest not using SSI at all. Instead, create a script in your cgi-bin directory that does the following:

    1. Checks for the cookie.
    2. If cookie exists, generate "admin output".
    3. Else, if cookie does not exist, generate other output.

    HTML::Template may be useful here, especially if there is stuff common to both pages.

    Your URL will now point to this cgi script directly, rather than to an html file that invokes it via SSI. And you eliminate the redirect as well.

    If you really want an HTML file, create a file that contains a frameset with a single frame, and point the source of the frame to the cgi-script.

    Alternatively, If you're using Apache, you could also use mod_rewrite to map one URL to another.

      The reason I wanted to use SSI is because I know no other way of doing this. I am creating a huge admin site to control the content of another site and the only way I could think of doing this is via SSI for the cookie checking. THis is the first time I have ever tried to make a "member's only" type area. I have looked at HTML::Template but I just don't see how it would work in my case. I guess this project is beyond my abilites and I will have to scrap it. I just can't figure out a good way of protecting LOTS of HTML pages behind a login setup.
        Are you using Apache? If so, try googling for htpasswd. This is a way to protect directories of html files using "basic authentication". You'll just need to develop a way of putting approved users (and passwords) into the .htpasswd file.