You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Stas Bekman <st...@stason.org> on 2003/06/12 06:30:01 UTC

[mp2] Apache::compat breaking 2.0 API solutions?

Last night I have done the mod_perl 1.0 to 2.0 porting presentation at the 
Melbourne mongers meeting, and I have raised the issue with Apache::compat, 
asking for input from my audience. Here is the problem that we have:

Apache::compat provides mod_perl 1.0 backward compatibility implementation. 
And everything works just fine as long as the API has a different name. 
However there is a problem if a certain method has the same name but a totally 
different functionality. Here is an example:

As explained here:
http://perl.apache.org/docs/2.0/user/porting/compat.html#C__connection_E_gt_remote_addr_

in mod_perl 1.0 you'd say:

   use Socket 'sockaddr_in';
   my ($port, $ip) = sockaddr_in($r->connection->remote_addr);

i.e. $r->connection->remote_addr was returned a packed socket information.

However in mod_perl 2.0 lingo (read: Apache 2.0 lingo), 
$r->connection->remote_addr returns an APR::SockAddr object (read: an opaque 
object, to which you need to use methods to access its values). So to 
accomplish the above you need to do:
   require APR::SockAddr;
   my $sock_addr = $c->remote_addr;
   my ($port, $ip) = ($sock_addr->port_get, $sock_addr->ip_get);

this is a 1:1 mapping to the Apache 2.0 C API.

So if we provide a back-compat implementation in Apache::compat and it gets 
loaded the real 2.0 API can no longer be used.

What I suggested is that we need some sort of scoped pragmata, so we can say:

{
   use mod_perl::compat;
   my ($port, $ip) = sockaddr_in($r->connection->remote_addr);
}
   my $sock_addr = $c->remote_addr;
   my ($port, $ip) = ($sock_addr->port_get, $sock_addr->ip_get);

so I can use both APIs and enable the back-compatibility functionality only in 
the needed scope. Of course this doesn't make the porting as simple as 
enabling Apache::compat, but it solves the API breaking problem. If it was 
only possible to make the scoping work.

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: [mp2] Apache::compat breaking 2.0 API solutions?

Posted by Stas Bekman <st...@stason.org>.
Scott Penrose wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
>> sounds good to me. Anybody has an experience of using Filter::Simple 
>> with mod_perl?
> 
> 
> A simple version looks like this...
> 
> package Apache::compat::uber;
> use strict;
> use Filter::Simple;
> 
> use constant ahh => 0;
> 
> FILTER {
>     print STDERR "PRE = $_\n" if ahh;
> 
>     s/localaddr/localaddr_compat/g;
> 
>     print STDERR "POST = $_\n" if ahh;
> };
> 
> 1;
> 
> And thats it... of course you have to write localaddr_compat in the 
> Apache::compat module.
> 
> (mind you, this is untested :-)
>     
> 
>> What perl versions Filter::Simple is working with? Assuming that 
>> someone will need to use this trickery to get the same code working 
>> with mod_perl 1.0 and mod_perl 2.0?
> 
> 
> Filter::Simple works with 5.6+

Thanks Scott, I'll give it a try.

>>> 2) Operator Overload
>>>     use Apache::compat;
>>>     # or what ever it actually is...
>>>     print STDERR sockdaddr_in($r->localaddr);
>>>     print STDERR $r->localaddr->ipnumber;
>>> $r->localaddr returns an operator overloaded object which can then
>>> check if we are returning a scalar (return the packed local address) or
>>> are we returning a blessed reference (return the normal blessed
>>> reference). I use this approach for code like this.
>>>     print $md->DC->Title . "\n";
>>>     print $md->DC->Title->Short . "\n";
>>
>>
>> How do you cope with a situation like this:
>>
>> my $title = $md->DC->Title;
>>
>> which can then be:
>>
>> print $title;
>>
>> or:
>>
>> print $title->Short;
> 
> 
> Both work, because in the first case it will be stringified to the 
> actual title.
> (although, sometimes you have to do print "" . $title;
> 
> In the second it will request from the overload method a blessed reference.
> 
>> of course you can overload the "" operator so it'll magically work 
>> because print calls "". Is that what you meants by your example?
> 
> 
> Yes :-) note to self, read bottom before replying above :-)

;)

> It aint perfect. The Filter::Simple would probably be more reliable.

It also won't work in the case of APR::URI::unparse which has a different 
problem. It'd be nice to have a generic solution.

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: [mp2] Apache::compat breaking 2.0 API solutions?

Posted by Scott Penrose <sc...@dd.com.au>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

> sounds good to me. Anybody has an experience of using Filter::Simple 
> with mod_perl?

A simple version looks like this...

package Apache::compat::uber;
use strict;
use Filter::Simple;

use constant ahh => 0;

FILTER {
	print STDERR "PRE = $_\n" if ahh;

	s/localaddr/localaddr_compat/g;

	print STDERR "POST = $_\n" if ahh;
};

1;

And thats it... of course you have to write localaddr_compat in the 
Apache::compat module.

(mind you, this is untested :-)
	
> What perl versions Filter::Simple is working with? Assuming that 
> someone will need to use this trickery to get the same code working 
> with mod_perl 1.0 and mod_perl 2.0?

Filter::Simple works with 5.6+

>> 2) Operator Overload
>>     use Apache::compat;
>>     # or what ever it actually is...
>>     print STDERR sockdaddr_in($r->localaddr);
>>     print STDERR $r->localaddr->ipnumber;
>> $r->localaddr returns an operator overloaded object which can then
>> check if we are returning a scalar (return the packed local address) 
>> or
>> are we returning a blessed reference (return the normal blessed
>> reference). I use this approach for code like this.
>>     print $md->DC->Title . "\n";
>>     print $md->DC->Title->Short . "\n";
>
> How do you cope with a situation like this:
>
> my $title = $md->DC->Title;
>
> which can then be:
>
> print $title;
>
> or:
>
> print $title->Short;

Both work, because in the first case it will be stringified to the 
actual title.
(although, sometimes you have to do print "" . $title;

In the second it will request from the overload method a blessed 
reference.

> of course you can overload the "" operator so it'll magically work 
> because print calls "". Is that what you meants by your example?

Yes :-) note to self, read bottom before replying above :-)

It aint perfect. The Filter::Simple would probably be more reliable.

Scooter
- -- 
Scott Penrose
Open source developer
http://linux.dd.com.au/
scottp@dd.com.au

Dismaimer: Open sauce usually ends up never coming out (of the bottle).
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (Darwin)
Comment: For info see http://www.gnupg.org

iD8DBQE+6BCuDCFCcmAm26YRAhuhAKCItBmR+OSFq/yW6DCk9BeNDX8jJQCfR4m0
zmmgtPgUFEL+Uc7wxxwpAjo=
=AJUR
-----END PGP SIGNATURE-----


Re: [mp2] Apache::compat breaking 2.0 API solutions?

Posted by Stas Bekman <st...@stason.org>.
[...]
> From: Scott Penrose <sc...@dd.com.au>
> To: Stas Bekman <st...@stason.org>
> 
> I have two solutions for your problem you presented yesterday.
> Both have side effects but I can work them at least in part (I don't
> know all the gotchas with ModPerl though).
> 
> 1) Filter::Simple
> 
>     use Apache::compat::uber;
> 
>     # or what ever it actually is...
>     print STDERR sockdaddr_in($r->localaddr);
> 
>     no Apache::compat::uber;
> 
>     print STDERR $r->localaddr->ipnumber;
> 
> will get converted to this
> 
>     print STDERR sockaddr_in($r->localaddr_compat);
> 
>     print STDERR $r->localaddr->ipnumber;
> 
> This has the side effect of having to do a Filter stage which is slower
> start up (but not much) and you have to get the regular expression
> right, but that won't be hard.

Sounds good to me. Anybody has an experience of using Filter::Simple with 
mod_perl?

What perl versions Filter::Simple is working with? Assuming that someone will 
need to use this trickery to get the same code working with mod_perl 1.0 and 
mod_perl 2.0?

> 2) Operator Overload
> 
>     use Apache::compat;
> 
>     # or what ever it actually is...
>     print STDERR sockdaddr_in($r->localaddr);
> 
>     print STDERR $r->localaddr->ipnumber;
> 
> $r->localaddr returns an operator overloaded object which can then
> check if we are returning a scalar (return the packed local address) or
> are we returning a blessed reference (return the normal blessed
> reference). I use this approach for code like this.
> 
>     print $md->DC->Title . "\n";
>     print $md->DC->Title->Short . "\n";

How do you cope with a situation like this:

my $title = $md->DC->Title;

which can then be:

print $title;

or:

print $title->Short;

of course you can overload the "" operator so it'll magically work because 
print calls "". Is that what you meants by your example?

__________________________________________________________________
Stas Bekman            JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/     mod_perl Guide ---> http://perl.apache.org
mailto:stas@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org   http://ticketmaster.com


Re: [mp2] Apache::compat breaking 2.0 API solutions?

Posted by Stas Bekman <st...@stason.org>.
Stas Bekman wrote:
> Last night I have done the mod_perl 1.0 to 2.0 porting presentation at 
> the Melbourne mongers meeting, and I have raised the issue with 
> Apache::compat, asking for input from my audience. Here is the problem 
> that we have:
> 
> Apache::compat provides mod_perl 1.0 backward compatibility 
> implementation. And everything works just fine as long as the API has a 
> different name. However there is a problem if a certain method has the 
> same name but a totally different functionality. Here is an example:
> 
> As explained here:
> http://perl.apache.org/docs/2.0/user/porting/compat.html#C__connection_E_gt_remote_addr_ 
> 
> 
> in mod_perl 1.0 you'd say:
> 
>   use Socket 'sockaddr_in';
>   my ($port, $ip) = sockaddr_in($r->connection->remote_addr);
> 
> i.e. $r->connection->remote_addr was returned a packed socket information.
> 
> However in mod_perl 2.0 lingo (read: Apache 2.0 lingo), 
> $r->connection->remote_addr returns an APR::SockAddr object (read: an 
> opaque object, to which you need to use methods to access its values). 
> So to accomplish the above you need to do:
>   require APR::SockAddr;
>   my $sock_addr = $c->remote_addr;
>   my ($port, $ip) = ($sock_addr->port_get, $sock_addr->ip_get);
> 
> this is a 1:1 mapping to the Apache 2.0 C API.
> 
> So if we provide a back-compat implementation in Apache::compat and it 
> gets loaded the real 2.0 API can no longer be used.
> 
> What I suggested is that we need some sort of scoped pragmata, so we can 
> say:
> 
> {
>   use mod_perl::compat;
>   my ($port, $ip) = sockaddr_in($r->connection->remote_addr);
> }
>   my $sock_addr = $c->remote_addr;
>   my ($port, $ip) = ($sock_addr->port_get, $sock_addr->ip_get);
> 
> so I can use both APIs and enable the back-compatibility functionality 
> only in the needed scope. Of course this doesn't make the porting as 
> simple as enabling Apache::compat, but it solves the API breaking 
> problem. If it was only possible to make the scoping work.

And Scott Penrose, of the melbourne pm's fame sent me these suggestions 
(posted here with Scott's permission):

-------- Original Message --------
Subject: Two solutions to Apache::compat
Date: Thu, 12 Jun 2003 12:47:28 +1000
From: Scott Penrose <sc...@dd.com.au>
To: Stas Bekman <st...@stason.org>

I have two solutions for your problem you presented yesterday.
Both have side effects but I can work them at least in part (I don't
know all the gotchas with ModPerl though).

1) Filter::Simple

	use Apache::compat::uber;

	# or what ever it actually is...
	print STDERR sockdaddr_in($r->localaddr);

	no Apache::compat::uber;

	print STDERR $r->localaddr->ipnumber;

will get converted to this

	print STDERR sockaddr_in($r->localaddr_compat);

	print STDERR $r->localaddr->ipnumber;

This has the side effect of having to do a Filter stage which is slower
start up (but not much) and you have to get the regular expression
right, but that won't be hard.

2) Operator Overload

	use Apache::compat;

	# or what ever it actually is...
	print STDERR sockdaddr_in($r->localaddr);

	print STDERR $r->localaddr->ipnumber;

$r->localaddr returns an operator overloaded object which can then
check if we are returning a scalar (return the packed local address) or
are we returning a blessed reference (return the normal blessed
reference). I use this approach for code like this.

	print $md->DC->Title . "\n";
	print $md->DC->Title->Short . "\n";


Scooter
- --
Scott Penrose
Open source developer
http://linux.dd.com.au/
scottp@dd.com.au