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

Hello Monks,

is it a bug in Browser::Open or a 'bug' in my module understanding? The following doesn't work on Windows 10:

my $url='https://www.google.com/search?q=finance&source=lnms&tbm=isch' +; my $ok = open_browser($url);

It breaks after shell metacharacters (in this case &) which Windows is trying to use as commands. Should I pass $url in a different way?

Replies are listed 'Best First'.
Re: Browser::Open Windows metacharacters
by Athanasius (Archbishop) on Dec 09, 2018 at 12:00 UTC

    Hello IB2017,

    The Browser::Open module determines an OS-sppropriate value for $cmd and then executes a call to system($cmd, $url);. So if the equivalent call fails on your OS when invoked directly, it will fail similarly via a call to open_browser. For example, on my system (Windows 8.1, 64-bit, Perl 5.28.0):

    21:47 >perl -wE "system('start', 'https://www.google.com/search?q=fina +nce&source=lnms&tbm=isch');" 'source' is not recognized as an internal or external command, operable program or batch file. 'tbm' is not recognized as an internal or external command, operable program or batch file. 21:53 >

    But changing the query delimiter from & to ; fixes the problem for me:

    21:53 >perl -wE "system('start', 'https://www.google.com/search?q=fina +nce;source=lnms;tbm=isch');" 21:54 >

    — and the equivalent:

    use strict; use warnings; use Browser::Open qw( open_browser ); my $url = 'https://www.google.com/search?q=finance;source=lnms;tbm=isc +h'; my $ok = open_browser($url); printf "\$ok = >%s<: %s\n", $ok, !defined($ok) ? 'no recognised command found' : $ok == 0 ? 'command found and executed' : 'command found, error while executing';

    works correctly:

    21:58 >perl 1952_SoPW.pl $ok = >0<: command found and executed 21:58 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Thank you, Athanasius

      Your suggestions does not work as expected, since the url needs to retain "&" to be correctly interpreted. Your solution, at least on my machine, produce a google search for the string "finance;source=lnms;tbm=isch" (instead of just "finance", being the rest parameters for the Google query).

      I actually thought that the module would also take care for OS specific metacharacters. If this is not the case, I need to do it myself, meaning checking for the OS and modifying the url accordingly.

Re: Browser::Open Windows metacharacters
by aitap (Curate) on Dec 09, 2018 at 16:39 UTC

    Browser::Open tries to use the list form of system to spawn a browser. The problem is that start is a cmd command and not a real executable, so Perl has to fall back to using the shell to launch it - and it doesn't quote the command line correctly in process. This makes Browser::Open a shell injection on Windows.

    A proper solution would be either to use Win32::ShellQuote or something similar to build a proper cmd.exe command line on Windows, use Perl version of ShellExecute from WinAPI (is there such a module?) or to fall back to launching browsers directly by their paths, which is not a good idea at all.

      use Win32::FileOp qw(ShellExecute); ShellExecute("http://www.google.com?foo=1&bar=2");

      Jenda
      Enoch was right!
      Enjoy the last years of Rome.

        Hello Jenda,

        ShellExecute does the job nicely, and Win32::FileOp looks to be a useful module.

        Unfortunately, when I tried to install it on my system (Windows 8.1, 64-bit), I got a gmake error similar to the one reported in Bug #71759. XLAT’s fork on GitHub (version “0.16.03”) fixed the problem for me. I note that although the status for Bug #71759 is “open,” it is also marked as “Fixed in: 0.16.02,” which would seem to be incorrect.

        Just a heads-up,

        Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Thank you for your help, and expecially for pointing to Win32::ShellQuote that I was not aware of. I found that having Browser::Open this shortcoming, the easiest solution for my case is the following script I found here. It just works, and for the moment I do not see any drawback:

      sub openurl { my $url = shift; my $platform = $^O; my $cmd; if ($platform eq 'darwin') { $cmd = "open \"$url\""; } # +OS X elsif ($platform eq 'MSWin32' or $platform eq 'msys') { $cmd = "star +t \"\" \"$url\""; } # Windows native or MSYS / Git Bash elsif ($platform eq 'cygwin') { $cmd = "cmd.exe /c start \"\" \"$ur +l \""; } # Cygwin; !! Note the required trailing space. else { $cmd = "xdg-open \"$url\""; } # assume a Freedesktop-complia +nt OS, which includes many Linux distros, PC-BSD, OpenSolaris, ... if (system($cmd) != 0) { die "Cannot locate or failed to open default browser; please open +'$url' manually."; } }
        Make sure you trust the source of the URLs. Otherwise it's still a shell injection: try passing a $url = q["$(touch ~/hello.txt)"] if you're on Linux or maybe $url = q["&calc&"] on Windows (not sure about the CMD syntax, but it's definitely possible to construct a string that would cause a command to be run when wrapped in double quotes).