Plack does not come back from Catalyst - perl

I have an app that may choose to serve a file from disk - or go to Catalyst and generate a dynamic one.
Something like this (inside call()):
if (-f $path){
my $app = Plack::App::File->new(file => $path)->to_app; #serve published page
$res = $app->($env);
}else{
log_debug "Fall through to app ";
$res = $self->app->($env);.
}
I'd like to set some cookies when it gets back. So I use Plack::Util
Plack::Util::response_cb($res, sub {
my $res = shift;
log_debug "Handling app response";
...
});
The results? In the first case (Plack::App::File), everything works as expected. In the second (continue to the app the normal way) it never comes back in.
I wonder why this is happenning? Here is my psgi initialization:
my $app = MainApp->psgi_app(#_);
$app = Plack::MyAppAbove->wrap($app);
$app = MainApp->apply_default_middlewares($app);

Related

Perl catalyst controller redirect not working

I have looked over this code and I can not understand the weirdness it exhibits. For a lack of understanding all I know
$c->res->redirect('qbo/home');
is being ignored, in favor of the redirect in the following if else condition. In other words, I always end up at the OAuthentication website.
If I block comment out the else condition I end up where I want to go qbo/home
sub index :Path :Args(0) {
my ($self, $c) = #_;
# Check to see if we have QBO::OAuth object in our user's session
# Create new object in session if we don't already have one
if(!($c->session->{qbo})) {
$c->log->info('Creating QBO::OAuth, save in user session');
$c->session->{qbo} = QBO::OAuth->new(
consumer_key => 'qyprddKpLkOclitN3cJCJno1fV5NzcT',
consumer_secret => 'ahwpSghVOzA142qOepNHoujyuHQFDbEzeGbZjEs3sPIc',
);
}
# Now we set our object variable to the session old or new
my $qbo = $c->session->{qbo};
######### GOTO 'qbo/home' ##########
$c->res->redirect('qbo/home');
####################################
if($c->req->params->{oauth_token}) {
$c->log->info('Now Redirect to access_endpoint');
# Get realmId and save it to our QBO::OAuth object in user session
$qbo->realmId($c->req->params->{realmId});
# Call QBO::OAuth->request_access_token
my $r = $qbo->request_access_token($c->req->params->{oauth_verifier});
$c->res->redirect('qbo/home');
} else {
my $callback = 'http://www.example.com/qbo';
# Request a token
my $r = $qbo->request_token($callback);
if($qbo->has_token) {
#Continue on down, Redirect to auth_user_endpoint
$c->res->redirect($qbo->auth_user_endpoint . '?oauth_token=' . $qbo->token);
}
}
}
Seems I am missing some basic fundamental about how this works. Any clues appreciated
From the fine manual...
This is a convenience method that sets the Location header to the redirect destination, and then sets the response status. You will want to return or $c->detach() to interrupt the normal processing flow if you want the redirect to occur straight away.
Note also the warning on that manual page about redirecting to a relative URL - you shouldn't do it. For your use-case, I'd recommend getting into the habit of using:
return $c->res->redirect($c->uri_for('qbo/home'));
or
$c->res->redirect($c->uri_for('qbo/home')) && $c->detach();
depending on your preference.

Mojolicious, redirects, session and trying to create an authentication system

I'm trying to get away from Basic Auth in my Mojolicious application. I am able to detect the absence of a session key and redirect to a login page. The login page then posts to my application and I authenticate to a back end process. That back end process is returning success and then my mojo app sets the session like thus:
$self->session( user => $name, groups => $groups );
in debugging this, $name and $group are both defined and valid. I then wish to redirect into the "protected" space of my app. The redirect lands in the right place but then fails to detect the $self->session('user') (is undef when debugging) I end up redirecting back to login repeatedly.
I'll include snippets of the setup below. What am I missing?
MyApp.pm
my $r = $self->routes;
$r->route('/verify')->via('post')->to('util-auth#verify')->name('verify');
$r->route('/login')->via('get')->to('util-auth#login')->name('login');
my $app = $r->under('/myapp')->to('util-auth#check');
$app->route('/foo')->via('get')->to('controller-api#foo')->name('foo');
MyApp::Util::Auth
sub verify {
my $self = shift;
my $name = $self->param('username');
my $pass = $self->param('password');
my $dest = "/myapp/foo"; # in the protected area
if ( $self->authenticate($name, $pass) ) {
my $groups = $self->get_groups($name);
$self->session(
user => $name,
groups => $groups,
);
}
else {
$self->flash( message => "invalid login..." );
}
$self->redirect_to($dest);
}
sub login {
my $self = shift;
$self->render(); # renders the login form
}
sub check {
my $self = shift;
my $user = $self->session('user');
return 1 if defined $user;
$self->redirect_to('/login');
return 0;
}
I was having a similar problem and I ended up putting these in stash. I think session is string based, mainly because a cookie is set with session info.
Why your verify function accept name, pass via #_ variable?
May be need to use $self->param('name') and $self->param('pass')?
See working example here:
https://gist.github.com/Logioniz/bdf6f22c00fc51798c43

Win32::IEAutomation will not click on links when IE >= 9

On a modern setup (Windows 7 64-bit, IE 11, ActiveState Perl 5.16 64-bit), the Click method in Win32::IEAutomation (v0.5) does not seem to work. Here is an example, lightly adapted from the documentation:
use Win32::IEAutomation;
my $ie = Win32::IEAutomation->new( visible => 1);
$ie->gotoURL('http://www.google.com');
$ie->getLink('linktext:', "About")->Click;
At this point, I should see the "About" page in IE. But I still see Google's home page in IE, and I cannot use the Content method in Win32::IEAutomation to get the source of the "About" page.
I have the same problem on an older setup (Vista SP2 64-bit, IE 9, ActiveState Perl 5.10.1). But the problem does not arise when I use a similar setup with IE8 instead of IE9. The problem thus seems to lie with a difference between IE8 and subsequent IE versions.
Is there anything that I can do to get the example script working with more recent versions of IE?
Win32::IEAutomation is a thin wrapper around the various interfaces exposed by InternetExplorer.Application and MSHTML.
Therefore, I tried to replicate the problem by writing a script to do the navigation without using Win32::IEAutomation. Using the click method on a link did not initiate navigation whereas passing its href to Navigate2 did.
The click method "Simulates a click by causing the HTMLFrameSiteEvents::onclick event to fire," meaning any onClick handlers defined on the page will be involved. I am not sure why specifically navigation is not being initiated.
However, the problem is not specific to Google's home page: I tried it with example.com, and invoking the click method on a link on that page did not initiate navigation either.
Here is the script I used as a testbed:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Win32::OLE qw(EVENTS in valof);
$Win32::OLE::Warn = 3;
my $url = 'https://www.google.com/';
my %event_handler = (
DocumentComplete => \&onDocumentComplete,
);
my %page_handler = (
'https://www.google.com/'
=> \&onPageGoogleHome,
'https://www.google.com/intl/en/about/'
=> \&onPageGoogleAbout,
);
my $ie = Win32::OLE->new(
"InternetExplorer.Application", sub { $_[0]->Quit }
);
Win32::OLE->WithEvents($ie, \&Event, 'DWebBrowserEvents2');
$ie->{Visible} = 1;
$ie->Navigate2($url);
Win32::OLE->MessageLoop;
Win32::OLE->SpinMessageLoop;
$ie->Quit;
sub Event {
my ($ie, $event, #argv) = #_;
if (exists $event_handler{$event}) {
$event_handler{$event}->($ie, \#argv);
}
else {
# unhandled event
}
return;
}
sub onDocumentComplete {
my ($ie, $argv) = #_;
my $url = valof($argv->[-1]);
if (exists $page_handler{$url}) {
$page_handler{$url}->($ie, $argv);
}
else {
# unhandled page
}
return;
}
sub onPageGoogleHome {
my ($ie, $argv) = #_;
say "We are on Google's home page";
my $links = $ie->Document->links;
my $about_link;
for my $link (in $links) {
if ($link->innerText eq 'About') {
say "Found 'About' link";
$about_link = $link;
last;
}
}
if ($about_link) {
# Doesn't work:
# $about_link->click;
$ie->Navigate2($about_link->href);
}
return;
}
sub onPageGoogleAbout {
my ($ie, $argv) = #_;
say "Yay, we are on the about page!";
Win32::OLE->QuitMessageLoop;
return;
}
Version information:
This is perl 5, version 19, subversion 12 (v5.19.12) built for MSWin32-x64-multi-thread
Internet Explorer 11
Windows 8.1 Pro 64-bit
I observe the same faulty behavior with the ->Click() in Strawberry Perl v5.18.2 and Win32::IEAutomation v0.5 and IE v11.0.9600.17105.
My work around is to use the gotoURL() method directly. This obviously would not work with javascript actions, but does for this particular example.
use strict;
use warnings;
use Win32::IEAutomation;
my $ie = Win32::IEAutomation->new( visible => 1);
$ie->gotoURL('http://www.google.com');
my $about = $ie->getLink('linktext:' => 'About')
or die "Unable to find About";
# $about->Click(); # <--- does not work, using alternative method
$ie->gotoURL($about->linkUrl());

How do I direct a Perl script to check for website response?

I’m pinging a website and checking the availability and sending an email only when it’s down. (That part is working just fine according to the code below.)
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(20);
my $response = $ua->get('https://www.Mysite.net/websuite/');
if (! $response->is_success) {
#print 'CMM Is up and Running';
$path = "C:\\prac\\send_email_failure.ps1";
$pwspath = "c:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe";
system("$pwspath -command $path"); #using powershell to invoke email utility
}
Now, I’m working on trying to expand the script to see whether
It can check once it’s down and send email (which it’s doing now) and don’t send email until it’s bought up. By the way, I’m using Windows task scheduler to run the script every twenty minutes.
After it sees the website is up it should goto its normal process of checking whether the site is down again and send email (for example the website went down then bought back up and again went down). I’m running the script every 20 mins using task scheduler.
Any help appreciated.
If your script is executed from some kind of scheduler you'll need to persist the status of your last request somehow. You could for example create a file which flags the last status as "down".
Or you could simply run your script as a daemon and schedule a check every 20 minutes (for example with AnyEvent). This way you wouldn't have to cope with filesystem related issues.
use LWP::UserAgent;
use AnyEvent;
my $previous = 1;
my $watch = AnyEvent->timer(interval => 1200, cb => sub {
if(check_status() == 0) {
if($previous == 1) {
# send e-mail
}
$previous = 0;
}
else {
$previous = 1;
}
});
AnyEvent->condvar->recv;
sub check_status {
my $ua = LWP::UserAgent->new(timeout => 20);
my $response = $ua->get('...');
return $response->is_success ? 1 : 0;
}

How Upload file using Mojolicious?

I have been trying out Mojolicious web framework based on perl. And I have try to develop a full application instead of the Lite. The problem I am facing is that I am trying to upload files to server, but the below code is not working.
Please guide me what is wrong with it. Also, if the file gets uploaded then is it in public folder of the application or some place else.
Thanks in advance.
sub posted {
my $self = shift;
my $logger = $self->app->log;
my $filetype = $self->req->param('filetype');
my $fileuploaded = $self->req->upload('upload');
$logger->debug("filetype: $filetype");
$logger->debug("upload: $fileuploaded");
return $self->render(message => 'File is not available.')
unless ($fileuploaded);
return $self->render(message => 'File is too big.', status => 200)
if $self->req->is_limit_exceeded;
# Render template "example/posted.html.ep" with message
$self->render(message => 'Stuff Uploaded in this website.');
}
(First, you need some HTML form with method="post" and enctype="multipart/form-data", and a input type="file" with name="upload". Just to be sure.)
If there were no errors, $fileuploaded would be a Mojo::Upload. Then you could check its size, its headers, you could slurp it or move it, with $fileuploaded->move_to('path/file.ext').
Taken from a strange example.
To process uploading files you should use $c->req->uploads
post '/' => sub {
my $c = shift;
my #files;
for my $file (#{$c->req->uploads('files')}) {
my $size = $file->size;
my $name = $file->filename;
push #files, "$name ($size)";
$file->move_to("C:\\Program Files\\Apache Software Foundation\\Apache24\\htdocs\\ProcessingFolder\\".$name);
}
$c->render(text => "#files");
} => 'save';
See full code here: https://stackoverflow.com/a/28605563/4632019
You can use Mojolicious::Plugin::RenderFile
Mojolicious::Plugin::RenderFile