8

I have a script that I wrote that can either be used on the command line or as a CGI script, and need to determine how the script was called so I can output a content-type header for web requests (and maybe some anti-cache headers too). My first thought is to check for the existance of http environment variables:

my $js = build_javascript();

if ( exists $ENV{HTTP_HOST} ) {
   print "Content-type: text/javascript\n\n";
}
print $js;

Is there a better way?

Stephen Sorensen
  • 11,455
  • 13
  • 33
  • 46

3 Answers3

18

According to the CGI specification in RFC3875 (section 4.1.4.), the GATEWAY_INTERFACE environment variable would be the authoritative thing to check whether you are running in a CGI context:

4.1.4. GATEWAY_INTERFACE

The GATEWAY_INTERFACE variable MUST be set to the dialect of CGI being used by the server to communicate with the script.

Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
VoidPointer
  • 17,651
  • 15
  • 54
  • 58
  • I suppose because there could possibly be other types of interfaces that are not CGI which might set a `HTTP_HOST` environment variable. – friedo Dec 16 '09 at 15:02
  • 1
    There are other variables that MUST be set. But HTTP_HOST, indeed, is not one of them. – innaM Dec 16 '09 at 18:36
  • 1
    That still doesn't really help because you can set any environment variables you like from the command line. – brian d foy Dec 16 '09 at 19:45
  • 2
    brian, by setting GATEWAY_INTERFACE you are saying "I'm a CGI host and all programs that care should behave accordingly". I don't see any reason for "accidentally" setting this in the environment. Otherwise, no solution would ever be valid because I could confuse the program by attaching a debugger and mess around with information the implementation relies on. – VoidPointer Jan 14 '10 at 10:00
8

There's really no way good way to tell if your script was started by a web server or from the command line. Any of the environment variables can be set in both situations. I often run CGI programs straight from the command line to test them, for instance.

Knowing that, if you want to pick one environment variable to use, it just has to be one that you won't set in the other situation, or one that you set in both but give different values to. In that case, choose any environment variable that you like.

If you want to get more sophisicated, you can use something like IO::Interactive to determine if you're connected to a terminal. If you aren't, the filehanandle that is_interactive returns is a null filehandle and the output goes nowhere:

 print { is_interactive() } $http_header;

If you don't like how IO::Interactive decides, you can reimplement is_interactive. It's a very short piece of code and the higher-level interface is very nice.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
3

I usually do a little trick at the beginning of my module:

exit run(@ARGV) unless caller();   # run directly if called from command line

sub run
{
    process_options(@_);
    ...
}

sub process_options {
    @ARGV = @_;
    my  %opts;
    GetOptions(\%opts,
    ...
}

The module does not have to be named "run".

ЯegDwight
  • 24,821
  • 10
  • 45
  • 52
Peter
  • 31
  • 2
  • Welcome to StackOverflow. If you've changed your mind about an answer, please click the "delete" button and it will disappear for everyone else. – Deanna Oct 04 '12 at 08:50