Catalyst::Plugin::RunAfterRequest behaves differently under server script and FastCGI - perl

I'm trying to set up the Perl Catalyst plugin Catalyst:: Plugin:: RunAfterRequest and am seeing different behaviour when it is being run with the server script "APPNAME/script/APPNAME_server.pl" and the FastCGI process under Lighttpd.
That is, it works as expected with the server script, but when used in the FastCGI web server environment the request being returned seems to be blocked by the code allegedly running after the request is returned. This is easily reproducible with the code in Controller/Root.pm:
sub index : Private {
my ($self, $c) = #_;
$c->run_after_request(
sub {sleep 10;}
);
$c->response->body("foobar");
}
Running the test script returns a result instantaneously as expected, but will wait 10 seconds before a response in the web server environment.
Is there any configuration that needs to be made with Lighttpd or FastCGI to get this to work properly?
UPDATE:
As requested, sample lighttpd config:
include "common/mime.conf"
include "common/modules-core.conf"
server.bind = "127.0.0.1"
server.port = 6080
server.pid-file = "/path/to/lighttpd-6080.pid"
server.username = "user"
server.groupname = "group"
server.document-root = "/path/to/root"
server.errorlog = "/path/to/.errors-6080"
accesslog.filename = "/path/to/.access-6080"
include "common/index.conf"
server.modules += ( "mod_fastcgi")
server.stream-response-body = 2
$HTTP["url"] !~ "^/(?:img/|static/|css/|favicon.ico$)" {
fastcgi.server = (
"" => (
"appname" => (
"socket" => "/path/to/appname-fcgi.sock",
"check-local" => "disable",
"bin-path" => "/path/to/appname_fastcgi.pl",
"min-procs" => 2,
"max-procs" => 5,
"idle-timeout" => 20
)
)
)
}

Related

How to solve lighttpd "No input file specified."

Last time I was using Apache2+PHP5 as my web server and it run normally unless too slow when server is process my script and I had change it to lighttpd + fastcgi. It faster than and low memory usage.
My problem is when lighttpd running some time it "No input file specified." but some time is ok. But when I restart lighttpd every come to normally.
I don't know why and how to solve it.
This is my config.
$SERVER["socket"] == ":80" {
$HTTP["host"] == "xxx.xxx.xxx.xxx" {
server.document-root = "/var/www/public_html"
server.errorlog = "/var/www/public_html/logs/error.log"
accesslog.filename = "/var/www/public_html/logs/access.log"
compress.cache-dir = "/var/www/public_html/cache"
}
$HTTP["host"] == "sub.domain.com" {
server.document-root = "/var/www/public_html"
server.errorlog = "/var/www/public_html/logs/error.log"
accesslog.filename = "/var/www/public_html/logs/access.log",
compress.cache-dir = "/var/www/public_html/cache"
}
index-file.names = ( "index.php", "index.html", "index.htm", "default.htm" )
url.rewrite-if-not-file = (
"^/image(.*)" => "/image-api.php$1",
"^/go/([a-zA-Z0-9_-]+)" => "/index.php?go=$1",
"^/oembed(.*)" => "/oembed_provider/index.php$1",
"^/player$" => "/library/plugin/video-player/player.swf",
"^/v(.*)" => "/cvd.php$1",
"^/me" => "/user.php",
"^/#(.*)\?(.*)" => "/profile.php?indentity=$1&$2",
"^/#(.*)" => "/profile.php?indentity=$1",
"^/url?g=(.*)" => "/url.php?g=$1",
"^/social_auth/(.*)" => "/partner_api/$1.php",
"^/c/(.*)" => "/view.php?view=$1",
"^/u/(.*)" => "/profile.php?indentity=$1",
"^/project/(.*)" => "/section.php?page=$1",
"^/min/(.*)" => "/mini/index.php$1",
"^/src/(.*)" => "/src/$1",
"^/library/(.*)" => "/library/$1",
"^/\?(.*)" => "/index.php?$1",
"^/(.*)\?(.*)" => "/page.php?p=$1&$2",
"^/(.*)" => "/page.php?p=$1"
)
$HTTP["host"] == "domain.org" {
url.redirect = ("/(.*)$" => "https://domain.com/$1")
}
$HTTP["host"] == "domain.info" {
url.redirect = ("/(.*)$" => "https://domain.com/$1")
}
$HTTP["host"] == "domain.net" {
url.redirect = ("/(.*)$" => "https://domain.com/$1")
}
}
From the FAQ, it looks like there are several possibilities:
I get the error "No input file specified" when trying to use PHP
Sadly, this error message can mean a lot of things.
A common explanation attempt: PHP is unable to locate or open the file which it
is supposed to parse.
This can have a lot of reasons:
You forgot to
add ''cgi.fix_pathinfo=1 to your php.ini'' file. See the comments in
the PHP docs. The issue here is that the environment variable
SCRIPT_FILENAME is not being passed to PHP.
Make sure you did not set
doc_root or userdir in php.ini, or if you have set it, make sure it
has the correct value (doc_root should match lighttpd's
server.document-root option in this case)
If open_basedir is set, make
sure the requested file is below one of the directories which is
specified there. In the past PHP parsed files which were not inside
open_basedir as well, but this security problem was fixed (in
php-5.2.3 or so).
If you are running PHP with different permissions
than lighttpd (spawn-fcgi with -u/-g, execwrap, suexec, ...), check
that PHP can really read the file
If you are unable to find / fix the
problem, you can use strace to see if it is a (OS-related) permission
problem (look out for stat*(...YOURFILE...) = RETURNCODE). It might
help to set max-procs to 1 and PHP_FCGI_CHILDREN as well (see fastcgi
docs) in that case, so that you can easily attach strace to the
correct php-cgi process.

Passing Parameter to Test::Class Setup method

I need to invoke a browser in selenium dynamically.
To achieve this I need to send the browser name as parameter to the set-up or start-up methods in Test::Class. How do I achieve this?
I take it you want to get a browser, then reuse it for some tests, then destroy it later? So just use a global to hold the browser you create. For example:
my $browser = '';
sub b_connect : Test(startup) {
$browser = WWW::Selenium->new( host => "localhost",
port => 4444,
browser => "*iexplore",
browser_url => "http://www.google.com",
);
};
sub b_disconnect : Test(shutdown) {
$browser->close()
};
Just use the $browser var in you tests.
sub startup : Test( startup ) {
my ($self) = #_;
my $arg = shift;
$self->{browser_type} = $arg->{browser};
-------------------------------#some other code for myself
$self->{browser} =
Test::WWW::Selenium->new(
host => $self->{host},
port => $self->{port},
browser => $self->{browser_type},
browser_url => $self->{test_url},
);
In my test script I need it to call using the following
my $t1 = Test::Class::Selenium::TestCases->new(browser=>$browser,);
Test::Class->runtests($t1);

How can I run mojolicious under Win32::Daemon?

I'm trying to run mojolicious as a Windows Service using Win32::Daemon, but I don't know how to return from the start callback after starting the mojo app. The mojo app begins to listen but the Windows Service Controller assumes the start failed because you never reach the return statement.
sub Callback_Start
{
my( $Event, $Context ) = #_;
app->start; # <-- code hangs here
$Context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State( SERVICE_RUNNING );
return();
}
Is it possible to start the Mojo server in a non-blocking way?
This is what I have finally done:
my $daemon = Mojo::Server::Daemon->new( app => app, listen => ['http://*:3000' ] );
$daemon->prepare_ioloop;
Win32::Daemon::StartService( \%context, 100 );
Win32::Daemon::RegisterCallbacks({
start => \&_start,
running => \&_running,
stop => \&_stop,
pause => \&_pause,
continue => \&_continue,
});
# ...
sub _running {
my( $Event, $context ) = #_;
if( SERVICE_RUNNING == Win32::Daemon::State() ) {
$daemon->ioloop->one_tick;
}
}
sub _start {
my ($event, $context ) = #_;
$context->{last_state} = SERVICE_RUNNING;
$context->{last_event} = $event;
Win32::Daemon::State( SERVICE_RUNNING );
return();
}
# ...
Calling the one_tick method repeteadly allows you to embed the Mojo server (see the doc). With the code above Windows will call the _running sub every 100 milliseconds (second StartService parameter).
What if you'd for a process, run the web app in the child and in the parent let the service controller know everything's running fine. I'm curios about how you'd stop the service in this case :)

Perl SSH connection to execute telnet

I tried the following to access a router via a central admin server as "ssh hop" server
#!/usr/bin/perl -X
use strict;
use Net::OpenSSH;
use Net::Telnet;
my $lhost = "linuxserver";
my $luser = "linuxuser";
my $lpass = "linuxpassword";
my $chost = "routername";
my $cpass = "Routerpassword";
my $prompt = '/(?:Password: |[>])/m';
my #commands = ("show users\r");
my $ssh = Net::OpenSSH->new($lhost,
'user' => $luser,
'password' => $lpass,
'master_opts' => [ '-t' ],
#'async' => 1 # if enabled then password cannot be set here
);
my ($pty, $err, $pid) = $ssh->open2pty("telnet $chost");
my $t = new Net::Telnet(
-telnetmode => 0,
-fhopen => $pty,
-prompt => $prompt,
-cmd_remove_mode => 1,
-output_record_separator => "\r",
#-dump_log => "debug.log",
);
my $end = 0;
while (!$end) {
my ($pre, $post) = $t->waitfor($prompt);
if ($post =~ /Password: /m) {
# send password
$t->print("$cpass");
}
elsif ($post =~ /[>#]/ && #commands) {
my $cmd = shift(#commands);
if ($cmd !~ /[\r\n]/) {
$t->print($cmd);
}
else {
print $t->cmd($cmd);
}
}
else {
$end = 1;
$t->cmd("exit");
}
}
#close $pty;
$t->close();
Unfortunately I always get the following error:
read error: Input/output error at test.pl line 71
Can somebody help me please or is there a better solution only to test if a telnet connection via the "hop" server is possible or not?
The connection looks like:
workstation --ssh-> server --telnet-> router
Thanks in advance.
I think best option is to make an SSH-tunnel to your admin server and use it for telnetting to the router.
Getting Net::Telnet to work over Net::OpenSSH sometimes is not as easy as it should be and it requires some experimentation to get to the right combination of flags and calls that make it work.
For instance, instead of telneting to the target host, use netcat to open a raw connection (or Net::OpenSSH support for TCP forwarding if tunnels are allowed on the proxy).
Expect + Net::OpenSSH may be a better option.

Why does Perl's Net::Msmgr hang when I try to authenticate?

There's Net::Msmgr module on CPAN. It's written clean and the code looks trustworthy at the first glance. However this module seems to be beta and there is little documentation and no tests :-/
Has anyone used this module in production? I haven't managed to make it run by now, because it requires all event loop processing to be done in the application and as I've already said there is little documentation and no working examples to study.
That's where I've gone so far:
#!/usr/bin/perl
use strict;
use warnings;
use Event;
use Net::Msmgr::Object;
use Net::Msmgr::Session;
use Net::Msmgr::User;
use constant DEBUG => 511;
use constant EVENT_TIMEOUT => 5; # seconds
my ($username, $password) = qw/my.username#live.com my.password/;
my $buddy = 'your.username#live.com';
my $user = Net::Msmgr::User->new(user => $username, password => $password);
my $session = Net::Msmgr::Session->new;
$session->debug(DEBUG);
$session->login_handler(\&login_handler);
$session->user($user);
my $conv;
sub login_handler {
my $self = shift;
print "LOGIN\n";
$self->ui_state_nln;
$conv = $session->ui_new_conversation;
$conv->invite($buddy);
}
our %watcher;
sub ConnectHandler {
my ($connection) = #_;
warn "CONNECT\n";
my $socket = $connection->socket;
$watcher{$connection} = Event->io(fd => $socket,
cb => [ $connection, '_recv_message' ],
poll => 're',
desc => 'recv_watcher',
repeat => 1);
}
sub DisconnectHandler {
my $connection = shift;
print "DISCONNECT\n";
$watcher{$connection}->cancel;
}
$session->connect_handler(\&ConnectHandler);
$session->disconnect_handler(\&DisconnectHandler);
$session->Login;
Event::loop();
That's what it outputs:
Dispatch Server connecting to: messenger.hotmail.com:1863
Dispatch Server connected
CONNECT
Dispatch Server >>>VER 1 MSNP2 CVR0
--> VER 1 MSNP2 CVR0
Dispatch Server >>>USR 2 MD5 I my.username#live.com
--> USR 2 MD5 I my.username#live.com
Dispatch Server <<<VER 1 CVR0
<-- VER 1 CVR0
And that's all, here it hangs. The handler on login is not being triggered. What am I doing wrong?
Hope these documents will help you out
1) Net::Msmgr documentation
2) Net::Msmgr::Session