0

The following script should demonstrate a problem I'm facing using Mojolicious on OpenBSD5.2 using mod_perl.

The script works fine 4 times being called as CGI under mod_perl. Additional runs of the script result in Mojolicious not returning the asynchronous posts. The subs that are usually called when data is arriving just don't seem to be called anymore. Running the script from command line works fine since perl is then completely started from scratch and everything is reinitialized, which is not the case under mod_perl. Stopping and starting Apache reinitializes mod_perl so that the script can be run another 4 times.

I only tested this on OpenBSD5.2 using Mojolicious in the version that's provided in OpenBSDs ports tree (2.76). This is kinda old I think but that's what OpenBSD comes with.

Am I doing something completely wrong here? Or is it possible that Mojolicious has some circular reference or something which causes this issue?

I have no influence on the platform (OpenBSD) being used. So please don't suggest to "use Linux and install latest Mojolicious version". However if you are sure that running a later version of Mojolicous will solve the problem, I might get the permission to install that (though I don't yet know how to do that).

Thanks in advance!

T.

Here's the script:

#!/usr/bin/perl

use diagnostics;
use warnings;
use strict;
use feature qw(switch);
use CGI qw/:param/;
use CGI qw/:url/;
use CGI::Carp qw(fatalsToBrowser warningsToBrowser);
use Mojo::IOLoop;
use Mojo::JSON;
use Mojo::UserAgent;

my ($activeconnections, $md5, $cgi);

my $ua = Mojo::UserAgent->new;
$ua->max_redirects(0)->connect_timeout(3)->request_timeout(6); # Timeout 6 seconds of which 3 may be connecting
my $delay = Mojo::IOLoop->delay();

sub online{
 my $url = "http://www.backgroundtask.eu/Systeemtaken/Search.php";
 $delay->begin;
 $activeconnections++;
 my $response_bt = $ua->post_form($url, { 'ex' => $md5 }, sub {
    my ($ua, $tx) = @_;
    my $content=$tx->res->body;
    $content =~ m/(http:\/\/www\.backgroundtask\.eu\/Systeemtaken\/taakinfo\/.*$md5\/)/;
        if ($1){
                print "getting $1\n";
                my $response_bt2 = $ua->get($1, sub {
                        $delay->end();
                        $activeconnections--;
                        print "got result, ActiveConnections: $activeconnections\n";
                        ($ua, $tx) = @_;
                        my $filename = $tx->res->dom->find('table.view')->[0]->find('tr.even')->[2]->td->[1]->all_text;
                        print "fn = " . $filename . "\n";
                }
            )
        } else {
                print "query did not return a result\n";
                $activeconnections--;
                $delay->end;
        }
 });
}

$cgi = new CGI;
print $cgi->header(-cache_control=>"no-cache, no-store, must-revalidate") . "\n";

$md5 = lc($cgi->param("md5") || ""); # read param
$md5 =~ s/[^a-f0-9]*//g if (length($md5) == 32); # custom input filter for md5 values only

if (length $md5 != 32) {
        $md5=lc($ARGV[0]);
        $md5=~ s/[^a-f0-9]*//g;
        die "invalid MD5 $md5\n" if (length $md5 ne 32);
}

online;

if ($activeconnections) {
        print "waiting..., activeconnections: $activeconnections\n" for $delay->wait;
}

print "all pending requests completed, activeconnections is " . $activeconnections . "\n";
print "script done.\n md5 was $md5\n";
exit 0;
Joel Berger
  • 20,180
  • 5
  • 49
  • 104
user1458620
  • 205
  • 1
  • 4
  • 12

1 Answers1

0

Well I hate to say it, but there's a lot wrong here. The most glaring is your use of ... for $delay->wait which doesn't make much sense. Also you are comparing numbers with ne rather than !=. Not my-ing the arguments in the deeper callback seems problematic for async style code.

Then there are some code smells, like regexing for urls and closing over the $md5 variable unnecessarily.

Lastly, why use CGI.pm when Mojolicious can operate under CGI just fine? When you do that, the IOLoop is already running, so some things get easier. And yes I understand that you are using the system provided Mojolicious, however I feel I should mention that the current version is 3.93 :-)

Anyway, here is an example, which strips out a lot of things but still should do pretty much the same thing as the example. Of course I can't test it without a valid md5 for the site (and I also can't get rid of the url regex without sample data).

#!/usr/bin/perl

use Mojolicious::Lite;
use Mojo::UserAgent;

my $ua = Mojo::UserAgent->new;
$ua->max_redirects(0)->connect_timeout(3)->request_timeout(6); # Timeout 6 seconds of which 3 may be connecting

any '/' => sub {
  my $self = shift;
  $self->res->headers->cache_control("no-cache, no-store, must-revalidate");

  my $md5 = lc($self->param("md5") || ""); # read param
  $md5 =~ s/[^a-f0-9]*//g if (length($md5) == 32); # custom input filter for md5 values only

  if (length $md5 != 32) {
    $md5=lc($ARGV[0]);
    $md5=~ s/[^a-f0-9]*//g;
    die "invalid MD5 $md5\n" if (length $md5 != 32);
  }

  $self->render_later; # wait for ua

  my $url = "http://www.backgroundtask.eu/Systeemtaken/Search.php";
  $ua->post_form($url, { 'ex' => $md5 }, sub {
    my ($ua, $tx) = @_;
    my $content=$tx->res->body;
    $content =~ m{(http://www\.backgroundtask\.eu/Systeemtaken/taakinfo/.*$md5/)};
    return $self->render( text => 'Failed' ) unless $1;
    $ua->get($1, sub {
      my ($ua, $tx) = @_;
      my $filename = $tx->res->dom->find('table.view')->[0]->find('tr.even')->[2]->td->[1]->all_text;
      $self->render( text => "md5 was $md5, filename was $filename" );
    });
  });

};

app->start;
Joel Berger
  • 20,180
  • 5
  • 49
  • 104
  • I'm thankful for every comment about what's wrong in my code! _delay->wait_ -> no idea, I copied that from an example and I thought it would be some kind of loop that waits for the asynchronous subs to complete. I admit I haven't understood it. The goal of the script is to fire 4 or 5 http-requests (posts and gets) to various sources and start parsing the results after all sources have responded, then return the final result. My example code is just an excerpt of my script showing the problems I'm having with that script under mod_perl. – user1458620 Apr 10 '13 at 15:00
  • About the resouces: Any MD5 of any MS Windows system file will do. For example 10e4a1d2132ccb5c6759f038cdb6f3c9 (calc.exe). – user1458620 Apr 10 '13 at 15:01
  • I only had a few minutes to try your suggested code. Yet I cannot get it working, I might need to dig deeper why, it returns "Status: 404 Not Found" though I cannot see at first look what could be wrong there. – user1458620 Apr 10 '13 at 15:08
  • I may not have much time to work on this for several days, I'm only just a few days from having to submit my doctoral thesis. If you have a specific question I would be happy to help, but I probably already spent more time on this example than I should have :-) – Joel Berger Apr 10 '13 at 15:29
  • I wasn't able to run the code under mod_perl and Apache, but it ran fine using morbo. So I assume that the problem is not within my script but there's some general issue with this (old) version of Mojolicious and mod_perl. Seems like I will have to try to get the latest version of mojolicious running on OpenBSD. – user1458620 Apr 11 '13 at 07:17
  • if you do move to the latest mojolicious, note that the method call for posting forms has changed slightly. It has been rolled into the more generic `post` method. `$ua->post( $url, form => { ... }, sub { ... } )` – Joel Berger Apr 11 '13 at 18:22
  • One more thing, the async calls might have problems under mod_perl, you might be right about having to use Mojo::IOLoop directly as you did before (should you want that). Otherwise, you might just want to remove the async calls entirely, and do the processing synchronously. – Joel Berger Apr 11 '13 at 18:24
  • Joel, thanks again for your help. However, I believe I could reproduce the issue with the latest version of Mojolicious using mod_perl (not using Mojolicious::Lite or morbo). So I think that this might be something that cannot be solved here and I'll try to post this issue on the Mojolicious mailing list. – user1458620 Apr 12 '13 at 14:19
  • yeah, as sri replied on the mailing list, the problem is that the IOLoop is not running under mod_perl deployment. Sorry I sent you down a dead-end. My brain has been in another world this week. – Joel Berger Apr 13 '13 at 02:28