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

I have a simple script being called from a webpage that grabs a couple fields of information and should put it into a .csv file.

Here's the code:

#!/usr/bin/perl # consent.cgi use strict; use warnings; use CGI qw(:standard); use CGI::Carp qw(fatalsToBrowser); use Fcntl ':flock'; use POSIX; #VARIABLES my $sys_time = POSIX::strftime("%D %T", localtime); my $data_path = "/home/account/cgi-bin/asewk"; my $jump_url = "http://mysite.com/ase-workkeys/consent-confirm.html"; my ($which_form, $consent, $user_name, $company, $user_email, @flatfie +lds, $flatfile); #SCRIPT &setValues; &writeCSVfile($which_form, $flatfile); print redirect($jump_url); exit; #SUBROUTINES sub setValues { #get values from form $which_form = param('which_form'); $consent = param('consent'); $user_name = param('name'); $company = param('company'); $user_email = param('email'); #build line for csv flatfile @flatfields = ("$sys_time", "$consent", "$user_name", "$company", +"$user_email"); $flatfile = join(",", map { local $_ = $_; s/"/""/g; qq("$_") } @f +latfields); } sub writeCSVfile { my($filename, $linename) = @_; #name subroutine variables my $log_file = "$data_path/$filename\.csv"; open (LO, ">>$log_file") or die "Could not open $log_file: $!"; flock LO, LOCK_EX; #exclusive lock print LO "$linename\n"; close LO; }

perl -c consent.cgi comes back OK.

This is a new system for me, running a 5.8 flavor of perl (I was previously on 5.004 *shudder*), and initially I was getting this error
Could not open /home/account/cgi-bin/asewk/employer.csv: Permission denied at /home/account/cgi-bin/asewk/consent.cgi line 42.

I chmod'ed all I knew to chmod and then got in touch with my network guys. His response was:

The problem appears to have been caused due to the site running as the 'apache' user, which didn't have write permissions. I modified Apache to run the site as the 'account' user which does have the proper credentials. The CGI runs now, but gives an Internal Server Error, and the logs don't show much. Can you add some debugging to the code to see if the problem is related to something with the server, or if it's code related?

The error logs just show Premature end of script headers: consent.cgi, referer: http://mysite.com/ase-workkeys/employerconsent.html.
Such a non-informative message.

My questions are:

  1. Is there something glaring (like a typo) that I'm missing in my code to throw this error?
  2. If not, then what should I put in for debugging to find out more information?

Thank you!

UPDATE:
After looking in the suexec.log and giving that error to the network admin with my server hosting, he came back with this "solution."

It seems that the issue is that suexec REQUIRES that all executing CGI's be run from (or underneath) /var/www. This means that your current directory organization, eg /home/<something>, etc would have to be moved to something like /var/www/sites/<something> (as an example).

So it was a permissions thing, and not my perl code (though it can admittedly be improved upon.)


I learn more and more about less and less until eventually I know everything about nothing.

Replies are listed 'Best First'.
Re: a classic : 'Premature end of script headers' problem
by ikegami (Patriarch) on Sep 19, 2007 at 18:01 UTC
    You could try adding BEGIN { print "Content-Type: text/plain\n\n" } after the shebang (#!) line to see what the server is seeing.
      Where would I see what the server is seeing?
      I added that line and I saw no difference, either in the output or in the error logs.


      I learn more and more about less and less until eventually I know everything about nothing.

      Make that BEGIN { $|= 1; print "Content-Type: text/plain\r\n\r\n"; }, the $|= 1 part being important, the \r's likely not important (that part of the RFC is rarely a sticking point, thankfully).

      - tye        

Re: a classic : 'Premature end of script headers' problem
by leocharre (Priest) on Sep 19, 2007 at 18:19 UTC
    Here's one thing to help with getting debug info right away
    #!/usr/bin/perl # consent.cgi BEGIN { use CGI::Carp 'fatalsToBrowser'; } use strict; use warnings; use CGI qw(:standard); use Fcntl ':flock'; # ...... # as a curiosity also.. my $iam = `whoami`; open(STDERR, '>>', '/home/myself/errlog') or die($!); warn("I am [$iam]");
    Can you log into the machine via ssh?? Then..
    bash # tail -f /home/myself/errlog
    

    After that hold the shell window on one side, and run the script on the other to see the output real time

      use already executes at the same time as BEGIN. So while moving CGI::Carp higher is good, there's no need to use BEGIN.
      #!/usr/bin/perl # consent.cgi use CGI::Carp 'fatalsToBrowser'; use strict; use warnings; use CGI qw(:standard); use Fcntl ':flock'; ...
Re: a classic : 'Premature end of script headers' problem
by scorpio17 (Canon) on Sep 19, 2007 at 19:18 UTC
    Is your new system running SELinux? If so, in addition to setting the correct permissions with "chmod", you'll need to set the correct security contexts with "chcon" - someone else on here had a similar problem recently.
Re: a classic : 'Premature end of script headers' problem
by Joost (Canon) on Sep 19, 2007 at 19:03 UTC
    The first argument you're passing to writeCSVfile does not appear to be what you're expecting in that subroutine.

    Or at least it looks like you're mixing up $flatfile, $filename and $linename in several places.

    also a couple of useless things that are in your code:

    @flatfields = ("$sys_time", "$consent", "$user_name", "$company", "$u +ser_email");
    is the same as
    @flatfields = ($sys_time, $consent, $user_name, $company, $user_email +);
    since those values are already strings (and even if they weren't, perl will convert them for you when you treat them as strings anyway).

    And map{} does a local $_ already, so there's no need to do an explicit local $_ in your code.

    So taking all that in account, you may want

    $linename = join(",", map { s/"/""/g; qq("$_") } $sys_time, $consent, +$user_name, $company, $user_email);
    instead.
Re: a classic : 'Premature end of script headers' problem
by leocharre (Priest) on Sep 19, 2007 at 18:26 UTC

    And what are the permissions of /home/account/cgi-bin/asewk ?

    And owner.group ?

    Lastly, consider getting a hosting account that runs suexec Here's one of my fav: http://angryhosting.com

      What should they be? I'm just learning about apache permissions. This isn't a hosting account. These are my own dedicated servers. I am root (but I still do have tech support).

      I learn more and more about less and less until eventually I know everything about nothing.
        the script should be executable for the webserver. But, AFAIK if isn't, you won't get that error.

        also: when you get the "premature end of headers" error, the webserver's error log can contain additional useful information (like what is received when it expects the header - generally the error is triggered by code that sends out messages/content before/while sending the header block)

        update: you should never use &subname; without parentheses to call a subroutine unless you know why that's a special case, and if you're using parentheses it's always safe to leave off the &, so IMO it's generally a good habit leave off the & and use parentheses where it makes sense, like subname()

        oh wow.. ok .. you've got it easy on one hand because you have full access.. and hard on another because you have full access.

        do this instead.. vim /usr/bin/debughttp (as root)

        #!/bin/sh # this is just an example #tail -f /var/log/httpd/error_log tail -f /var/log/httpd/ssl_error_log | sed 's/^.\+0.41\]\|\, referer.\ ++\.cgi\|\?rm=\w\+//g' # or just # tail -f /var/log/httpd/error_log
        (you know how to set perms on that? chmod 0700, just you everything, everyone else nothing)

        Open a terminal and # debughttp forget the CGI::Carp 'fatalsToBrowser' crap.. get rid of all that, get rid of the open(STDERR, '>>' .. all that.

        Make sure you have the right path to your httpd error log

        call the script from your browser and enjoy the wonder that is POSIX.

Re: a classic : 'Premature end of script headers' problem
by scorpio17 (Canon) on Sep 20, 2007 at 02:23 UTC
    Regarding your update: the default cgi-bin directory (for apache) is /var/www/cgi-bin, but you can change this. Read about the "scriptalias" directive in the apache docs, or just modify the httpd.conf file and change /var/www/cgi-bin to whatever you want it to be. Just be careful - you'll have to change it in more than one place. Be sure to search for them all.
Re: a classic : 'Premature end of script headers' problem
by Gangabass (Vicar) on Sep 20, 2007 at 01:43 UTC

    This error means that your script does't write correct HTTP header (mostly because it's terminates before writing any header).

    Possible reasons:

    • you did't
      print "Content-Type: text/plain\n\n";
      But you said it does't help
    • Sometimes (in my experience) the shebang string get corrupted. I mean some bad (invisible) symbols occur in it (at the end). Try to rewrite shebang string.
    • Also it maybe permission problem

    So one way to find the problem is try to run your script at shell and show us script output. It will be perfect if you run script from your webserver user account.