in reply to How to handle an external process from CGI?

I have a CGI script calling an external client to gather data from a remote SQL server.

First of all, in general, this is a very dangerous thing to do, and especially so if you haven't properly sanitized all of those variables that you're passing to the external command. It's very easy to get the cleanup wrong. See also perlsec.

I'm also a bit confused by the code style... if your open fails, it looks like the code will continue on and try to run the while loop, which seems kind of pointless, and should also generate warnings. I do hope you're using strict and warnings?

Anyway, IPC::Run supports calling external commands with timeouts, so you might want to look at that. I'd also recommend splitting up the command into a list instead of a string (i.e. ($UNID_CLIC,$Host,$Port,...) instead of "$UNID_CLIC $Host $Port ...") because in that case, open* as well as IPC::Run won't pass it to the shell, and you have one less thing to worry about - I wrote about that some more (including some of the possible security risks) here.

* Update: Except on Perl versions before 5.22 on Win32 (perldelta).

Replies are listed 'Best First'.
Re^2: How to handle an external process from CGI?
by emilbarton (Scribe) on Jun 21, 2019 at 22:32 UTC
    Many thanks for your answer, I think there's no <MYPIPE> if open fails (I'll check it) but IPC::Run is probably exactly what I need. I'll read your advice in detail.
      I think there's no <MYPIPE> if open fails

      Yes and no: the first <MYPIPE> does return undef, so the while loop never runs, but you should also be getting a warning "readline() on closed filehandle", indicating that something is wrong. A failed open doesn't have to be fatal, there are plenty of ways to handle the control flow:

      if ( open my $fh, ... ) { while (<$fh>) { ... } close $fh; } else { warn "open: $!" } # - or - sub foo { open my $fh, ... or do { warn "open: $!"; return }; while (<$fh>) { ... } close $fh; } # - or - FILE: for my $file (@files) { open my $fh, ... or do { warn "skipping $file: $!"; next FILE }; while (<$fh>) { ... } close $fh; } # - or - use Try::Tiny; try { open my $fh, ... or die $!; while (<$fh>) { ... } close $fh; } catch { warn "error: $_"; }; # same thing, but without the module: eval { open my $fh, ... or die $!; ... ;1 } or do { warn "error: $@"; };

      The fourth and fifth examples are different in that they catch any fatal error inside the block, which may or may not be desired.

      Update: Added the third example, from this thread.