Selling cookie info to third-parties is a classic example of you can make money without doing evil.
RSS

Kill those pesky forked children!

2009/08/06 filed under /perl

During some test writing, I had to spawn a shell command that would run while /bin/true was true. Unfortunately, my test script figured the run time should be limited, so I had to kill that little brat myself.

Let's have a look at a simplified setup first:

my $pid = fork();
if($pid == 0) {
    print "I'm the child: $$\n";
    system('while(/bin/true); do echo "Mwuahaha"; sleep 1; done');
} else {
    print "I'm the parent: $$\n";
}

sleep 3;
kill 1, $pid;

Although this might look valid perl, the "Mwhuahaha" will continue to fill up you terminal. The forked system command will not be killed when your program ends.

There had to be a way to kill the child (grandchild, if you want), and there is. Using setpgrp and getpgrp to the rescue!

Let's have a look at the documentation first (always a good thing):

   setpgrp PID,PGRP
       Sets the current process group for the specified PID, 0 for the
       current process. Will produce a fatal error if used on a
       machine that doesn't implement POSIX setpgid(2) or BSD
       setpgrp(2).  If the arguments are omitted, it defaults to
       "0,0".  Note that the BSD 4.2 version of "setpgrp" does not
       accept any arguments, so only "setpgrp(0,0)" is portable.  See
       also "POSIX::setsid()".

   getpgrp PID
       Returns the current process group for the specified PID.  Use a
       PID of 0 to get the current process group for the current
       process.  Will raise an exception if used on a machine that
       doesn' implement getpgrp(2).  If PID is omitted, returns
       process group of current process.  Note that the POSIX version
       of "getpgrp" does not accept a PID argument, so only "PID==0"
       is truly portable.

Almost there! Let's see the kill documentation as well, for it contains a fatal clue:

       Unlike in the shell, if SIGNAL is negative, it kills process
       groups instead of processes.  (On System V, a negative PROCESS
       number will also kill process groups, but that's not portable.)
       That means you usually want to use positive not negative
       signals.  You may also use a signal name in quotes.

Note that we need the negative signal!

So, if we change our test script to this, it'll all work, and those pesky (grand)children are killed when we want to:

my $pid = fork();
if($pid == 0) {
    setpgrp;
    print "I'm the child: $$\n";
    system('while(/bin/true); do echo "Mwuahaha"; sleep 1; done');
} else {
    print "I'm the parent: $$\n";
}

sleep 3;
kill -1, getpgrp($pid);

Posted by: B10m | permanent link | comments (0)

Catalyst, OpenID and Yahoo!

2008/10/13 filed under /perl

Net::OpenID::Consumer has just been released to CPAN (it was on BRADFITZ's svn repository for a while), which enables you to handle OpenID 2.0 logins (and since Brad is listed as author of the 2.0 protocol , I trust it's a solid module :)

Since Net::OpenID::Consumer now handles OpenID 2.0, Catalyst::Authentication::Credential::OpenID does too (thanks to ASHLEY (and yes, "ashley is a boy's name")).

This is good news, 'cause Yahoo! only accepts OpenID 2.0. So from now on, all Yahoo! users can login to your application and that without a lot of code (thanks to the awesome Catalyst Framework).

After implementing it, I ran into the horrors of the Yahoo! implementation. They are very strict and when you screw up at a certain point, they'll greet your users with a lovely message:

Warning: This website has not confirmed its identity with Yahoo! and might be fraudulent. Do not share any personal information with this website unless you are certain it is legitimate.

I tried to lookup what caused this and came across a good and quite detailed solution The only bad thing about it: it didn't work for me.

After messing with it for way too long, I noticed that my return_to URI was redirecting Yahoo! (so what?), so they ignored the Yadis header and thus raising the error.

To fix this in Catalyst, you must make sure you have the following things done:

  1. Create a yadis.xrdf (see the template)
  2. Have Catalyst return the right Content-Type header for the file (if you're using Catalyst::Plugin::Static, check the POD!)
  3. Inserted a X-XRDS-Location header for at least the return_to URL
  4. Have Catalyst return a 200-response code on the return_to URL

I was using code like this:

    my ( $self, $c ) = @_;

    if ( !$c->authenticate({}, "openid") ) {
        $c->flash(error => "OpenID login failed");
    }

    $c->res->redirect( $c->uri_for('/') );
    $c->detach();

FAIL! Don't redirect (or redirect with a meta-refresh, or javascript).

Since this took me hours to figure out, I hope this blog post makes your life a little easier.

Posted by: B10m | permanent link | comments (0)

No _parse_* routine defined on this driver

2008/10/09 filed under /perl

After I released Catalyst::Authentication::Credential::Flickr version 0.02, FAIL messages poured in from CPAN testers (well, to be more precise, from one tester with multiple test machines).

The error the tests failed on was:

No _parse_* routine defined on this driver (If it is a filter, remember to 
set the Parent property. If you call the parse() method, make sure to set a 
Source. You may want to call parse_uri, parse_string or parse_file instead.) 
[XML::LibXML::SAX::ChunkParser=HASH(0x83dab48)]

I was not able to reproduce the error and thus mailed the CPAN tester (ANDK). Not much later, Andreas informed me about the installed versions of several dependencies but even with those exact same versions, reproducing the error was impossible.

On closer look, it turned out the order of installing XML::SAX parsers really mattered, for that makes up the order of them in XML/SAX/ParserDetails.ini

As it turned out, ANDK had XML::LibXML::SAX::ChunkParser installed last and thus that module became the default parser module for XML::SAX. The author of that module is aware of this bug, and patched it in a newer release, but that didn't help me much.

I've spend way to much time debugging this, so I figured it'd be nice to at least write down the solution to this: erase the XML::LibXML::SAX::ChunkParser part out of ParserDetails.ini.

Since XML::Simple already has some checks for faulty modules, I've asked the author to add this module as well, so we can safely require a new version of XML::Simple in our Makefiles and bypass this bug.

Posted by: B10m | permanent link | comments (0)

WWW::Mechanize::Plugin::Web::Scraper

2008/06/11 filed under /perl

Joffie asked me if Web::Scraper could handle authentication while retrieving the website in question. A good question and after digging in Tatsuhiko's code, I noticed that you can simply dump HTML in the scrape function, instead of just the documented URI object.

I remembered Tatsuhiko mentioning integration with WWW::Mechanize somewhere but I couldn't find anything yet. So I decided to write the little Mechanize plugin. Shockingly, and completely surprising, it now carries the name WWW::Mechanize::Plugin::Web::Scraper.

Scrape the planet!

Posted by: B10m | permanent link | comments (1)

Perl code highlighters

2008/04/28 filed under /perl

Perl can be a real mess, yes. Everyone knows it, a few try to disagree, but in the end, you can make Perl code look very cryptic. So maybe this post isn't really fair. Never the less, I'd like to point out an annoyance I have noticed for some time now.

All over the web, websites exist that allows you to dump some code. The website will highlight it accordingly to the chosen language. While this usually works fine, it fails a lot of times on the Perl variable $#. This special variable specifies the last index of a list. As you might guess, most highlighters see the hash and think: comment!

Let's use this code:

#!/usr/bin/perl

my @test = qw(Just another Perl Hacker);
print "Last index of the test list is:", $#test, "\n";
print "Oh, of course ... ", join " ", @test, "\n";

This is fairly easy code to follow, even for a non-Perl programmer, I believe, so it's up to you to figure out what it does ;-)

Now, let's see how a 10 random sites handle this:

Wrong (see the hash as a commenting prefix):

Correct:

Sad but true ...

Posted by: B10m | permanent link | comments (0)
return-member