Loading ...
Sorry, an error occurred while loading the content.

Perl Phantom Variables in FastCGI

Expand Messages
  • johnlikeglass
    Take a look at the simple script below. $c should never show up, right? On FastCGI servers it often does! Try loading it, calling it, and hitting F5 enough,
    Message 1 of 4 , Sep 26, 2012
    • 0 Attachment
      Take a look at the simple script below. $c should never show up, right?
      On FastCGI servers it often does! Try loading it, calling it, and
      hitting F5 enough, and the text in $c gets displayed. Call them
      Phantom, or Zombie, but they live on after the script exits and may show
      up in the next script called. So, what's going on? Well....

      On a server configured for FastCGI, the perl operating system stays
      alive so that it does not need to be reloaded every time a script is
      called, improving performance. Unfortunately, if you are running your
      script on such a server, you have to take some extra precautions. Using
      reset 'a-z'; will clear your lower case variables, unfortunately, the
      upper case version will also clear the environmental variables which you
      may be using. One workaround on this is to kill the variables as the
      script exits, for example: reset 'a-z'; reset 'A-Z'; exit;

      There are other ways to do this for sure, but clearing on exit is an
      easy way to upgrade scripts you may already have written and recently
      began to misbehave.



      #!/usr/local/bin/perl

      $a = localtime();

      $test_file = 'test.txt';
      open DATA, ">>$test_file" or die "can't open $test_file $!";
      print DATA $a.'<br>';
      print DATA $c.'<br>';
      close (DATA);

      open DATA, "<$test_file" or die "can't open $test_file $!";
      @new_data = <DATA>;
      close (DATA);

      #output page
      print <<EOF ;
      Content-type: text/html

      <html><head>
      <META http-equiv="EXPIRES" CONTENT="0">
      <meta http-equiv="pragma" content="no-cache">
      </head><body>
      <p>@new_data</p>
      </body></html>
      EOF

      $c = 'This line should never show up';
      exit;



      [Non-text portions of this message have been removed]
    • Joe Pepersack
      In FastCGI, your program does not exit after it runs; the perl interpreter and your script stay in memory until the fastcgi server kills it. This is why
      Message 2 of 4 , Sep 26, 2012
      • 0 Attachment
        In FastCGI, your program does not exit after it runs; the perl
        interpreter and your script stay in memory until the fastcgi server
        kills it. This is why FastCGI is so much faster than regular CGI. It's
        doing what it's supposed to do.

        Try running ps on your webserver while it's running and observe the
        lifecycle of the perl process.

        If you're running FastCGI, I suggest using the CGI::Fast module.

        The basic syntax is:

        use CGI::Fast;
        use CGI::Carp;
        while ( my $cgi = CGI::Fast->new ) {
        print_your_page();
        }
        cleanup();

        This code sits idle until the page is hit, then calls
        print_your_page(). cleanup() is actually never called, because the
        while loop is effectively endless - the process never exits normally.
        If you want cleanup() to be called you have to use signal handling to
        catch SIGKILL.

        I wrote an article on using FastCGI to run HTML::Mason
        <http://joe.pepersack.net/blog/programming/mason_fastcgi.html> sites.
        The script attached to the article is well-commented and should serve as
        a non-trivial example of FastCGI in action.

        The CGI::Fast documentation is well worth reading.


        On 9/26/12 7:46 PM, johnlikeglass wrote:
        >
        > Take a look at the simple script below. $c should never show up, right?
        > On FastCGI servers it often does! Try loading it, calling it, and
        > hitting F5 enough, and the text in $c gets displayed. Call them
        > Phantom, or Zombie, but they live on after the script exits and may show
        > up in the next script called. So, what's going on? Well....
        >
        > On a server configured for FastCGI, the perl operating system stays
        > alive so that it does not need to be reloaded every time a script is
        > called, improving performance. Unfortunately, if you are running your
        > script on such a server, you have to take some extra precautions. Using
        > reset 'a-z'; will clear your lower case variables, unfortunately, the
        > upper case version will also clear the environmental variables which you
        > may be using. One workaround on this is to kill the variables as the
        > script exits, for example: reset 'a-z'; reset 'A-Z'; exit;
        >
        > There are other ways to do this for sure, but clearing on exit is an
        > easy way to upgrade scripts you may already have written and recently
        > began to misbehave.
        >
        > #!/usr/local/bin/perl
        >
        > $a = localtime();
        >
        > $test_file = 'test.txt';
        > open DATA, ">>$test_file" or die "can't open $test_file $!";
        > print DATA $a.'<br>';
        > print DATA $c.'<br>';
        > close (DATA);
        >
        > open DATA, "<$test_file" or die "can't open $test_file $!";
        > @new_data = <DATA>;
        > close (DATA);
        >
        > #output page
        > print <<EOF ;
        > Content-type: text/html
        >
        > <html><head>
        > <META http-equiv="EXPIRES" CONTENT="0">
        > <meta http-equiv="pragma" content="no-cache">
        > </head><body>
        > <p>@new_data</p>
        > </body></html>
        > EOF
        >
        > $c = 'This line should never show up';
        > exit;
        >
        > [Non-text portions of this message have been removed]
        >
        >



        [Non-text portions of this message have been removed]
      • Joe Pepersack
        My example below may not be entirely clear. Let s modify it to be: use CGI::Fast; use CGI::Carp; $SIG{PIPE} = sub { carp caught SIGPIPE }; $SIG{USR1} = sub {
        Message 3 of 4 , Sep 26, 2012
        • 0 Attachment
          My example below may not be entirely clear.

          Let's modify it to be:

          use CGI::Fast;
          use CGI::Carp;

          $SIG{PIPE} = sub { carp "caught SIGPIPE" };
          $SIG{USR1} = sub { carp "cleanup1"; cleanup(1) };
          $SIG{TERM} = sub { carp "cleanup2"; cleanup(2) };

          carp 'starting';
          while (my $cgi = CGI::Fast->new) {
          carp "printing page";
          print_your_page();
          }
          carp "cleanup3";
          cleanup(3);

          IF we run this as regular CGI and hit the page 3 times, the Apache
          error.log would look like:
          starting
          printing page
          cleanup3
          starting
          printing page
          cleanup3
          starting
          printing page
          cleanup3

          If we do the exact same exercise under FastCGI error.log would look like:
          starting
          printing page
          printing page
          printing page
          cleanup1


          Note that in the FastCGI run we don't see cleanup1 turn up for quite
          some time (potentially hours), and we never see cleanup3 because the
          while loop never terminates normally. Conversely in regular CGI we
          should never see the cleanup1 or cleanup2 messages unless there was
          something seriously wrong with the Apache daemon.

          See: http://www.fastcgi.com/docs/faq.html for more info on how the
          FastCGI works and how it differs from regular CGI. See perldoc perlipc
          to understand signal handling in Perl.

          If we don't use CGI::Fast (or the less-capable but largely equivalent
          FCGI module), I suspect the FastCGI server is effectively going to put
          an implicit loop around your script, which is why you're seeing the
          value of $c from the previous run showing up in subsequent runs.

          There's nothing "phantom" about it. FastCGI is doing exactly what it's
          supposed to be doing - persisting the Perl process between page hits.
          Your code has to be written properly to take this behavior into
          account. Get CGI::Fast or FCGI from CPAN. Reading the docs for CGI
          module is also highly recommended, since CGI::Fast inherits most of it's
          capabilities.

          On 9/26/12 8:02 PM, Joe Pepersack wrote:
          >
          > In FastCGI, your program does not exit after it runs; the perl
          > interpreter and your script stay in memory until the fastcgi server
          > kills it. This is why FastCGI is so much faster than regular CGI. It's
          > doing what it's supposed to do.
          >
          > Try running ps on your webserver while it's running and observe the
          > lifecycle of the perl process.
          >
          > If you're running FastCGI, I suggest using the CGI::Fast module.
          >
          > The basic syntax is:
          >
          > use CGI::Fast;
          > use CGI::Carp;
          > while ( my $cgi = CGI::Fast->new ) {
          > print_your_page();
          > }
          > cleanup();
          >
          > This code sits idle until the page is hit, then calls
          > print_your_page(). cleanup() is actually never called, because the
          > while loop is effectively endless - the process never exits normally.
          > If you want cleanup() to be called you have to use signal handling to
          > catch SIGKILL.
          >
          > I wrote an article on using FastCGI to run HTML::Mason
          > <http://joe.pepersack.net/blog/programming/mason_fastcgi.html> sites.
          > The script attached to the article is well-commented and should serve as
          > a non-trivial example of FastCGI in action.
          >
          > The CGI::Fast documentation is well worth reading.
          >
          > On 9/26/12 7:46 PM, johnlikeglass wrote:
          > >
          > > Take a look at the simple script below. $c should never show up, right?
          > > On FastCGI servers it often does! Try loading it, calling it, and
          > > hitting F5 enough, and the text in $c gets displayed. Call them
          > > Phantom, or Zombie, but they live on after the script exits and may show
          > > up in the next script called. So, what's going on? Well....
          > >
          > > On a server configured for FastCGI, the perl operating system stays
          > > alive so that it does not need to be reloaded every time a script is
          > > called, improving performance. Unfortunately, if you are running your
          > > script on such a server, you have to take some extra precautions. Using
          > > reset 'a-z'; will clear your lower case variables, unfortunately, the
          > > upper case version will also clear the environmental variables which you
          > > may be using. One workaround on this is to kill the variables as the
          > > script exits, for example: reset 'a-z'; reset 'A-Z'; exit;
          > >
          > > There are other ways to do this for sure, but clearing on exit is an
          > > easy way to upgrade scripts you may already have written and recently
          > > began to misbehave.
          > >
          > > #!/usr/local/bin/perl
          > >
          > > $a = localtime();
          > >
          > > $test_file = 'test.txt';
          > > open DATA, ">>$test_file" or die "can't open $test_file $!";
          > > print DATA $a.'<br>';
          > > print DATA $c.'<br>';
          > > close (DATA);
          > >
          > > open DATA, "<$test_file" or die "can't open $test_file $!";
          > > @new_data = <DATA>;
          > > close (DATA);
          > >
          > > #output page
          > > print <<EOF ;
          > > Content-type: text/html
          > >
          > > <html><head>
          > > <META http-equiv="EXPIRES" CONTENT="0">
          > > <meta http-equiv="pragma" content="no-cache">
          > > </head><body>
          > > <p>@new_data</p>
          > > </body></html>
          > > EOF
          > >
          > > $c = 'This line should never show up';
          > > exit;
          > >
          > > [Non-text portions of this message have been removed]
          > >
          > >
          >
          > [Non-text portions of this message have been removed]
          >
          >



          [Non-text portions of this message have been removed]
        • Shlomi Fish
          Hi John, a few comments on your code: On Thu, 27 Sep 2012 00:46:13 -0000 ... Always add use strict; and use warnings; :
          Message 4 of 4 , Sep 27, 2012
          • 0 Attachment
            Hi John,

            a few comments on your code:

            On Thu, 27 Sep 2012 00:46:13 -0000
            "johnlikeglass" <js_dziel@...> wrote:

            > Take a look at the simple script below. $c should never show up,
            > right? On FastCGI servers it often does! Try loading it, calling it,
            > and hitting F5 enough, and the text in $c gets displayed. Call them
            > Phantom, or Zombie, but they live on after the script exits and may
            > show up in the next script called. So, what's going on? Well....
            >
            > On a server configured for FastCGI, the perl operating system stays
            > alive so that it does not need to be reloaded every time a script is
            > called, improving performance. Unfortunately, if you are running your
            > script on such a server, you have to take some extra precautions.
            > Using reset 'a-z'; will clear your lower case variables,
            > unfortunately, the upper case version will also clear the
            > environmental variables which you may be using. One workaround on
            > this is to kill the variables as the script exits, for example:
            > reset 'a-z'; reset 'A-Z'; exit;
            >
            > There are other ways to do this for sure, but clearing on exit is an
            > easy way to upgrade scripts you may already have written and recently
            > began to misbehave.
            >
            >
            >
            > #!/usr/local/bin/perl
            >

            Always add "use strict;" and "use warnings;":

            http://perl-begin.org/tutorials/bad-elements/#no-strict-and-warnings

            > $a = localtime();
            >

            Declare the variable using "my" and don't call it "$a":

            http://perl-begin.org/tutorials/bad-elements/#vars-a-and-b

            > $test_file = 'test.txt';
            > open DATA, ">>$test_file" or die "can't open $test_file $!";

            1. Use three-args open.

            2. Use lexical file handles

            See:

            http://perl-begin.org/tutorials/bad-elements/#open-function-style

            3. The *DATA file handle has a special meaning in Perl, and should not
            be over-rided.

            > print DATA $a.'<br>';
            > print DATA $c.'<br>';
            > close (DATA);
            >
            > open DATA, "<$test_file" or die "can't open $test_file $!";
            > @new_data = <DATA>;
            > close (DATA);
            >
            > #output page
            > print <<EOF ;

            Always use <<'EOF' or <<"EOF" for avoiding ambiguity:

            http://perl-begin.org/tutorials/bad-elements/#string-notation

            > Content-type: text/html
            >
            > <html><head>
            > <META http-equiv="EXPIRES" CONTENT="0">
            > <meta http-equiv="pragma" content="no-cache">
            > </head><body>
            > <p>@new_data</p>
            > </body></html>
            > EOF
            >

            If you're going to interpolate @new_data into a string, you should slurp it
            as a string using File::Slurp or whatever.

            > $c = 'This line should never show up';
            > exit;

            Well, with package-scope variables, no wonder why FastCGI preserves them.

            Regards,

            Shlomi Fish

            --
            -----------------------------------------------------------------
            Shlomi Fish http://www.shlomifish.org/
            List of Portability Libraries - http://shlom.in/port-libs

            Knuth is not God! Typing “God” into Google and pressing “I’m Feeling Lucky”
            will not lead you to his homepage.

            Please reply to list if it's a mailing list post - http://shlom.in/reply .
          Your message has been successfully submitted and would be delivered to recipients shortly.