http://qs321.pair.com?node_id=586338

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

I'm really at a loss why I am getting a 500 error when I attempt to execute the following script via a Web browser and the following error in my error log:
[Mon Nov 27 13:49:00 2006] [error] [client 64.233.172.2] Premature end + of script headers: /home/www/cgi-bin/testing.pl
The script WORKS fine on a server that has HTTP::Request::Common, but the error occurs on a machine where this module is not available. I added the eval assuming that it would effectively test if this module was available, and, if not, the error would be displayed on the Web browser (or I could suppress it entirely), and then I can continue doing other things without using the module. Here is the script...
#!/usr/bin/perl print "Content-type: text/html\n\n"; print "here we go again..."; eval { require LWP::UserAgent; use HTTP::Request::Common; my $ua = LWP::UserAgent->new; my %post; my $content = $ua->request(POST "http://www.cnn.com", [%post]) +->as_string; print $content; }; if (@$) { print "ERROR: @$"; } print "more stuff would happen here";
My questions are: 1) why doesn't the use of eval successfully suppress the premature EOS error? 2) is there a better way to test if the module is available, and, if not, then don't use it, and do other things? Basically this script will execute on a few servers and I want to test if the modules are available, and, if so, then use them and do some things, BUT if they aren't, then don't use them and do some other things... WITHOUT causing 500 errors... help? Thanks!

Replies are listed 'Best First'.
Re: Why am I getting "premature end of script header"?
by ikegami (Patriarch) on Nov 27, 2006 at 22:19 UTC

    That error means something (such as an error message) was printed before the header was printed. In this case, an error is printed before compilation of the script is done, and the header is only outputed after the script is done compiling.

    The content of eval BLOCK is compiled when the rest of the script is compiled, so the use in the eval BLOCK (and anything in the used file) will be executed before you send the header.

    You could send the header sooner (using BEGIN), or you could use eval EXPR instead of eval BLOCK.

    The following executes everything in the same order as if the error checking wasn't there (i.e. modules are loaded before CHECK is called), but dies gracefully if a module can't be loaded.

    #!/usr/bin/perl BEGIN { eval (" use LWP::UserAgent; use HTTP::Request::Common; "); if ($@) { print "500 Internal Server Error\n"; print "Content-type: text/plain\n"; print "\n"; print $@ die($@); # For the log file. } } print "Content-type: text/html\n\n"; my $ua = LWP::UserAgent->new; my %post = (...); my $response = $ua->request(POST "http://www.example.com/", [ %post ]) +; print $response->as_string;

    By the way, it's $@, not @$.

      Thanks very much... I appreciate your help. So the following would be a fine way to test if a module is available and either use it or not use it accordingly?
      print "Content-type: text/html\n\n"; print "here we go again..."; &a; sub a { BEGIN { eval ("use fakemodule;"); if ($@) { print "error happened $@"; } else { print "error didnt happen, do some stuff"; } } }

        My solution already does exactly that. Just replace the body of if ($@) with whatever you want.

        What you have there is the same as

        eval ("use fakemodule;"); if ($@) { print "error happened $@"; } else { print "error didnt happen, do some stuff"; } print "Content-type: text/html\n\n"; print "here we go again..."; &a; sub a {}
Re: Why am I getting "premature end of script header"? - eval { use }
by imp (Priest) on Nov 27, 2006 at 22:23 UTC
    use is evaluated at compile time, which eval can't catch. There are a few ways around this:
    # Option 1 - string eval, test $@ eval "use HTTP::Request::Common"; if ($@) { # Missing } # Option 2 - string eval with return value of 1 if (eval "use HTTP::Request::Common; 1;") { # Loaded, good } else { # Missing } # Option 3 - require and import eval { require HTTP::Request::Common; HTTP::Request::Common->import; }; if ($@) { # Not found }
    If I recall correctly option #2 is preferred.
      I just tried #2, or my interpretation of #2 and it didn't work... here is the code I used:
      #!/usr/bin/perl print "Content-type: text/html\n\n"; print "here we go again..."; if (eval "require LWP::UserAgent; use HTTP::Request::Common; 1 +;") { my $ua = LWP::UserAgent->new; my %post; my $content = $ua->request(POST "http://www.cnn.com", +[%post])->as_string; print $content; } else { print "didnt work"; }
      And here is the error I got:
      ./networktest.pl String found where operator expected at ./networktest.pl line 10, near + "POST "http://www.cnn.com"" (Do you need to predeclare POST?) syntax error at ./networktest.pl line 10, near "POST "http://www.cnn.c +om"" Execution of ./networktest.pl aborted due to compilation errors.

        You must use parens around the arguments of a function call when the call is compiled before the function being called has been loaded.

        My solution doesn't suffer from that problem. It loads the function (i.e. the module) before the call to the function is compiled.

        So either add parens around the arguments for POST (and suffer from the loss of prototypes on all imported functions), or use what I already posted.

        This would be sufficient:
        BEGIN { if( eval "use fakemodule; 1;") { print STDERR "Loaded fakemodule"; } else { print STDERR "Couldn't load fakemodule."; } }
        Don't put BEGIN blocks inside a subroutine, they won't do what you want.

        Don't print in the BEGIN block, it will come before the Content-type header

        Calling a subroutine with the '&a' syntax has the following effects, from perlsub:

        • &NAME(LIST); # Circumvent prototypes.
        • &NAME; # Makes current @_ visible to called subroutine.
        In your code you used the &a; form, which would make the current @_ visible to the called subroutine. For example:
        first(1,2,3); sub first { &second; } sub second { print for @_; } # Output is 123
        Although it isn't relevant for this particular case it is still good to be aware of the prototype circumvention behaviour. Here is an example:
        use strict; use warnings; use Data::Dumper; sub pro(\@) { print Dumper \@_; } my @list = (1,2,3); pro(@list); &pro(@list);
        Output:
        $VAR1 = [ [ 1, 2, 3 ] ]; $VAR1 = [ 1, 2, 3 ];
Re: Why am I getting "premature end of script header"?
by reneeb (Chaplain) on Nov 28, 2006 at 07:22 UTC
    Why don't you use use CGI::Carp qw(fatalsToBrowser);?

      Showing the world your error messages is not the best idea, especially when the OP can see the messages just fine in his error log.

      The problem is that the OP wants to load a module if it's present, and take some alternate action if it's not.

Re: Why am I getting "premature end of script header"?
by Anonymous Monk on Nov 28, 2006 at 12:06 UTC
    #!/usr/bin/perl print "Content-type: text/html\n\n"; print "here we go again..."; eval { require LWP::UserAgent; require HTTP::Request::Common; import HTTP::Request::Common; my $ua = LWP::UserAgent->new; my %post; my $content = $ua->request(POST "http://www.cnn.com", [%post]) +->as_string; print $content; }; if (@$) { print "ERROR: @$"; } print "more stuff would happen here";
      A reply falls below the community's threshold of quality. You may see it by logging in.