Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

mod_perl variable sharing problem

Status
Not open for further replies.

perl21

Programmer
Jul 13, 2005
22
US
I have mod_perl 2.1 installed with Apache 2.5.3.

In a library called, standard.pm, I have a sub routine

sub GetCookies{
undef(%Cookies);
undef(@ReturnCookies);
shift;
@ReturnCookies = @_;
$cookie_flag = 0;

if ($ENV{'HTTP_COOKIE'}) {
if ($ReturnCookies[0] ne '') {
foreach (split(/; /,$ENV{'HTTP_COOKIE'})) {
($cookie,$value) = split(/=/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
foreach $ReturnCookie (@ReturnCookies) {
if ($ReturnCookie eq $cookie) {
$value=~s~%20~ ~g;
$Cookies{$cookie} = $value;
$cookie_flag = "1";
}
}
}

}
else {
foreach (split(/; /,$ENV{'HTTP_COOKIE'})) {
($cookie,$value) = split(/=/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
$value=~s~%20~ ~g;
$Cookies{$cookie} = $value;
}
$cookie_flag = 1;
}
}

return %Cookies;
}


In my mod_perl file I call the subroutine and ask for the cookies.

#!/usr/bin/perl
use lib::standard;
$standardLibrary=lib::standard;

undef(%Cookies);
%Cookies=$standardLibrary->GetCookies("user");
$user=$Cookies{"user"};
print $user;

For whatever reason, this code will grab someone elses cookie and display the information to the wrong person. Not all the time, or even most of the time. Every once in a while.

Can anyone see anything that could possibly be wrong?

This problem has caused a lot of problems, and I thought I had fixed it until this morning when I got a call from an angry customer with someone elses info on their screen. Obviously they are concerned about their info on someone elses screen as well.

It's impossible to tell how many times this has happend because lots of users don't call.

Thank you,
Tony
 
On second thought, the problem may be with another sub.

I also have another subroutine in standard.pm which actually builds the information in html. The file which calls first the cookie sub then this sub is called.

application.sd

.sd I made up, I'm using .pl & .cgi for other types of perl & .sd is for mod_perl on my server.

After application.sd calls for the cookie, it allows the user to build an application using various forms. At the end. The information is displayed for a preview to correct any problems the user may see at the last minute.

This is where 1 person has reported other persons information was shown. I validated the information they reported seeing with information of another user in the database.

In the past, the problem was happening with any one of the 10 sections in the application.sd file. Which was because this line

undef(%Cookies);

was, then, absent from the sub routine. Since added, the problem was apparently fixed and no one reported anything for another week, today being 1 week.

I automatically assumed the same bug had re-surfaced which is why I posted the cookie routine. Now, I believe the sub which is presenting the information is problematic. Here is the sub. I have take out all the parts where the the html is built to cut down on size. It's just a lot of substitutions of tags so I figure the problem can not be there.

sub buildApplication{
shift;
$template=shift;
$id=shift;
$user=shift;

$sth = $dbh->prepare(<<End_SQL) or print "Couldn't open database: $DBI::errstr; stopped";
SELECT * FROM `fileinfo` WHERE `user` = '$user'
End_SQL
$sth->execute() or print "Couldn't open database: $DBI::errstr; stopped";
$row = $sth->fetchrow_hashref();
$sth->finish();

open(data,"<$template");
while(<data>){
$html.=$_;
}
close(data);

$sth = $dbh->prepare(<<End_SQL) or print "Couldn't open database: $DBI::errstr; stopped";
SELECT * FROM `clients` WHERE login = '$user'
End_SQL
$sth->execute() or print "Couldn't open database: $DBI::errstr; stopped";
$clientInfo=$sth->fetchrow_hashref();
$sth->finish();

# edited out $html substitutions #

return $html;
}

The application.sd file calls this sub in this way.

$application=$standardLibrary->buildApplication("$config->{templatepath}/view.html","$in{id}","$user");

It calls for the user cookie in the same way as my first post explains.

I highly appreciate anyone's ideas about what could be wrong. This problem has got the tech dept on everyone's "you know what" list.

I've made some changes including the addition of this line

$html='';

At the beginning of the sub. I posted it as it was during the occurance of the bug. Not sure if the change has fixed the problem. I'll be testing all day though.

Thanks everyone,
Tony
 
If it's only a 'once in a while' thing, then I'd say start by checking your cookie generation. That's the most obvious part of the code that had any randomness to it. Sounds like user A is getting assigned user B's cookie.


jaa
 
Hey Jaa,

Thanks a lot for looking over my post. It's a lot of info to review and I greatly appreciate it.

I enjoy a good challenge but this one is quite difficult because I can't make it fail. I have to review the sections called into question and make my best guess or guesses.

I thought it was the cookie thing as well, but since last week with hundreds of users going through the steps in this program no one reported an issue with another persons data appearing in the forms.

The only section reported was not a form, but a page that displays the html page with all the form data collected from the previous 8 steps.

So my conclusion is the cookies are being properly read. But for some reason the part that shows the application to the user before final submission has a caching problem.

I added and undef($html); to it, and the addition of undef(%Cookies); solved my problem with the cookies caching so I am hopeful I won't hear about this one again.

I just wanted some suggestions. This is the main problem when converting a system writting for basic perl to a mod_perl environment.

It doesn't make much sense to me, that's why I'm reading this chapter in practicle mod_perl on debugging all over again.


If you have any thoughts on that buildApplication sub I posted let me know :)

Thanks again Jaa,
Tony
 
AAARRRGGG - all your variables are global - one copy of each - so if the script is run multiple times concurrently you'll get pretty random results.

Forget
Code:
undef %something;
and use
Code:
my %something;
Use 'strict' and take each one of it's "requires fully qualified package" errors as an instruction to convert a global $something into a lexical.

Perl lets you ignore scope and declaration for quick-and-dirty scripts but you'll never get away with it under mod-perl.

Yours,

fish

&quot;As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.&quot;
--Maurice Wilkes
 
Thanks Fish

I am getting randon results, lol. Can't wait to get strict employed on my scripts.

I'm really confused on the global variable issue. I thought I had to use vars to create a global variable.

So my %something will automatically make it null.

I had been using strict on this library but I removed strict and all the my calls thinking they were the problem.

It wasn't working with the my calls the way I did it. I must have not used them properly.

Thanks again for the tip fish.

Tony
 
use vars" declares a package global whereas "my" sets up lexical scope, so if its outside any sub it can be accessed from the whole file. Package globals can be accessed from other packages and lexicals cannot, which is the main reason why you might want to use package globals.

In this case, you want to use lexicals within your sub so that you get a new variable each time the sub is entered and they cannot interfere with each other. Lexicals were introduced to perl to help with the many problems of package variables and, except in the case of a module wishing to expose variables to a caller (and one or two other exceptions), you are better of with lexicals throughout.

The other exceptions are things like the automatic instantiation of an eponymous filehandle with open - this only works if the filename variable is a package global - and, in every case, these are clearly documented and easy to avoid if you wish.

BTW - the cookie handling in CGI.pm is beautifully simple.

f

&quot;As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.&quot;
--Maurice Wilkes
 
Hey Fish,

I used to compile my perl because my boss was worried someone would break into our server and steal all our code. Long story but I wound up not using many modules because of the compiling problems.

Now that I'm a mod_perl guy, I'm more than happy to use CGI.pm, thanks for reminding me. I can't remember where I even got the sub for the cookies. I didn't write it, pretty sure I pulled it out of a cpan module.

CGI.pm can solve my cookie issue for good, but I've still got these variables being shared every once in a while. So I'm doing a lot of testing to fully understand the mod_perl process of variable sharing.

I looked up LWP::parallel and made a script to test my code with 5 simultaneous connections. I test with 1000 requests per session and run 4 sessions from 4 console windows on my linux machine.

Should help me figure out why things go wrong with my variables.

This is the code I'm running tests on so far.

Code:
#!/usr/bin/perl

use lib::standard;
$standardLibrary=lib::standard;

$html='Html Var Parent';

print "Content-type: text/html\n\n";

$html2=$standardLibrary->test();

print $html;

test.sd calls sub test() from standard.pm

Code:
sub test {
$html='Bad Var';
return $html;
}

When I run test.sd, it still prints "Html Var Parent".

I'm not sure what to expect. Is this solid code? If I declare either the $html var from test.sd with my or the $html var in the sub, or both, the result is the same.

Why is this happening?
 
Still not sure why my example is not failing, Maybe because the sub is in it's own pm file.

Perhaps my problem is not with variables getting mixed up between the pm file use()d by the parent file. But variables getting mixed up within the pm file, or within the parent program.

I think this code shows how bad coding can be fixed with my in a very basic way

Code:
my $i = 1;
my $variable;

if($i > 0)
{
  $variable = "Hello World!";
  print_it();
}

sub print_it()
{
  print "$variable<br>";
  $variable=1;
}


{
  my $variable = "True";
  print "$variable<br>";
}

print "$variable<br>";

When I run it for the first time I get

Hello World!
True
1

Every time after that I get

1
True
Hello World!

Until the process dies and it runs in a new thread.

This script will seem to give random results when run thousands of times.

I think this example is pretty lame but it shows the basics of localizing vars to me. The line causing the randomness is really obvious in this example "$variable=1;".

Of course my programs aren't written with problems just as obvious but I'm sure after using strict I'll find them.

Hope this helps other mod_perl new comers.

Lesson learned: use strict;

Thanks Fish,
Tony
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top