mod_perl headers_in not working - perl

I'm using mod_perl 2 with Apache 2.2.3 on Red Hat 5.2, and I'm trying to access the request headers, but the Apache2::RequestRec headers_in method (or rather, its return value) is not behaving the way I would expect.
Code fragment:
$logger->warn('version ' . $mod_perl::VERSION);
$logger->warn('r ' . $r);
my $headers = $r->headers_in;
$logger->warn('headers ' . $headers);
my $accept = $headers->get('Accept');
$logger->warn('got $accept');
$logger->warn($accept);
gives the following log output:
WARN version 2.000004
WARN r Apache2::RequestRec=SCALAR(0x2ae0598e9ef0)
WARN headers APR::Table=HASH(0x2ae06cad15a0)
with execution appearing to halt as soon as any access to the APR::Table is attempted.
The tied interface for APR::Table had the same effect - i.e. changing the get('Accept') line to:
my $accept = $headers->{Accept};
gives exactly the same log output.
According to the above linked documentation:
This table is available starting from the PerlHeaderParserHandler phase
So I would expect my code, running in the PerlResponseHandler phase, to be able to access the headers.
Does anyone have any ideas what I'm doing wrong?
Edit: Using Data::Dumper hasn't really clarified matters at all.
Code:
use Data::Dumper;
$logger->warn(Dumper($r));
my $headers = $r->headers_in;
$logger->warn($headers);
$logger->warn(Dumper($headers));
$logger->warn('have dumped $headers');
Output:
WARN $VAR1 = bless( do{\(my $o = '47143456365192')}, 'Apache2::RequestRec' );
WARN APR::Table=HASH(0x2ae071b06fd0)
So it seems that trying to get into $headers even through Data::Dumper results in the execution halting.
Edit: Attempting to set one of the headers fails as well.
$logger->warn('reset accept');
$r->headers_in->{'Accept'}= 'everything';
$logger->warn('post set accept');
stops log output at the
WARN reset accept
point. I tried the set(Accept => 'everything') alternative as well, with the same result.

Is there anything in the apache logs? It seems if your code stops executing there should be an error somewhere saying why.

Problem found:
I needed to add
use APR::Table;
somewhere. Kind of weird that it was happily able to create an APR::Table object though.

Have you tried getting the Accept header without assigning the header object to $header:
my $accept = $r->headers_in->get('Accept');
This works in my code running in the PerlResponseHandler phase.

Related

Can't figure out why Sereal encoder/decoder round-trip is not returning proper object

With all the hating on Storable -- I decided to check out Sereal for serialization needs. Plus I was having some issues with 32bit/64bit cross platform issues with Storable, so I figured this would be a good time.
After having some issues, I boiled the problem down to the following code. (i'm persisting an HTTP::Request object, hence the example code).
This is my encode test, i'm storing to a file:
use Sereal::Encoder;
use HTTP::Request;
use HTTP::Headers;
use URI;
my $encoder = Sereal::Encoder->new();
open(my $fh, ">", 'myfile.data') or die $!;
binmode($fh);
my $uri = URI->new('http://www.example.com');
my $headers = HTTP::Headers->new(
Content_Type => 'application/json',
);
my $http_request = HTTP::Request->new(POST => $uri, $headers, 'bleh');
print $fh $encoder->encode( $http_request );
close($fh);
And on the same machine(same perl etc. on 5.18), I run the following:
use Sereal::Decoder;
use File::Slurp qw(read_file);
use URI;
my $data = read_file('myfile.data') or die $!;
my $dec = Sereal::Decoder->new();
my $decoded = $dec->decode($data);
print $decoded->{_uri}->scheme,"\n";
And the output of running the encoding program, and then the decoding program is:
Can't locate object method "scheme" via package "URI::http" at testd.pl line 8.
Anyhow, was really nagging me as to what the problem was. I ended up reverting back to Storable and using nfreeze to solve my arch issues with Storable but was wondering why my attempt to transition to Sereal crashed and burned.
Thanks!
Sereal, unlike Storable, won't automatically load a module when it encounters a serialized object. This is a security issue with Storable, so Sereal is working as intended.[1]
At the point where scheme is called in the second test program, URI::http hasn't been loaded yet, so the method call results in an error. It seems that URI will load its subclasses when its constructor is used on a string that "looks like" one of them, e.g.
URI->new('http://www.stackoverflow.com');
loads the URI::http module. So one solution would be to add a dummy invocation of that constructor to ensure URI::http is loaded, or manually use URI::http instead. Either option causes the print $decoded->{_uri}->scheme line of the second script to work as expected, but I think the second is the lesser of two evils (importing an undocumented submodule from URI versus an arbitrary method call done specifically for its not-immediately-obvious side effect).

Soap Issue - SoapFault exception: [Client] looks like we got no XML document

Ive looked at similar errors and i think its most likely due to a BOM character but to be honest most of the other coding is in a different context and i just dont understand it, im not that familiar with soap and just use it to pull the data then format it in php.
My code is simple:
$activityClient = xpmClient::getModuleInstance('activity', $remoteSessionId, 'xxx.5pmweb.com');
$filter = new stdClass();
$count = 300;
$offset = 0;
$activityList = $activityClient->getList($filter, $offset, $count);
Now the server error shows:
> PHP Fatal error: Uncaught SoapFault exception: [Client] looks like we got no XML document in xxx/caching.php:59\nStack trace:\n
\#0 xxx/caching.php(59): SoapClient->__call('getList', Array)\n
\#1 xxx/caching.php(59): xpmClient->getList(Object(stdClass), 0, '371')\n
\#2 /xxx/reports.php(296): include('/xxx/...')\n
\#3 {main}\n thrown in /xxx/caching.php on line 59
Line 296 on report.php is an include for the caching.php file, line 59 of that file is
$activityList = $activityClient->getList($filter, $offset, $count);
This worked for months without issue so im not sure what changed today. Any ideas how to strip the BOM and still get my data into $activityList as an object so i can access the information?
edit//
The preg replace doesnt work, i guess thats because once i call $activityList the server gives a fatal error and doesnt process anything after that so im trying to fix it AFTER its broke rather than before.
How would i go about doing __getLastResponse()
Ive read the manual but dont understand how to structure it, im pretty sure i need a try catch for the reasons i said preg replace didnt work but i tried a few variations and its doing nothing, im pretty sure the structure is wrong, any pointers or ideas?
I don't know why would BOM cause this but if you want to strip bom here you go
function strip_bom( $str ) {
return preg_replace( '/^(\x00\x00\xFE\xFF|\xFF\xFE\x00\x00|\xFE\xFF|\xFF\xFE|\xEF\xBB\xBF)/', "", $str );
}
The Soap server you are using is broken. Have you checked manually trying to call it?

Exceptions from parsing unquoted cookies in Apache2

I'm using Apache2::Cookie (i.e. Apache2 with mod_perl) to parse cookies.
my %cookies = Apache2::Cookie->fetch;
do_something($cookies{"cookie1"});
This code has been running in production for years without any problems. I just learned that a cookie with particular formatting causes this to throw an exception Expected token not present. The cookie in question is generated by client-side JavaScript:
document.cookie = "val=a,b"
Apache2::Cookie appears to not like the comma.
I can catch this error with eval, but the cookie retrieval is done in lots of places in the code (yes, it could have been factored out, but frankly the code is so simple there was no need). In any case, it's there now and I have to track down and catch the exception for this cookie that I didn't set and I don't need.
Is there an easier way to get rid of this exception than refactoring dozens of calls to Apache2::Cookie->fetch? Either by redefining Apache2::Cookie::fetch, or by setting a global flag for libapreq to not puke on this (there isn't any I could find), or some other bright idea I'm missing.
(yes, it could have been factored out, but frankly the code is so simple there was no need).
I would take this opportunity to fix this oversight, instead of making another
If you insist, you could learn something from CGI::Cookie
sub fetch {
my $class = shift;
my $raw_cookie = get_raw_cookie(#_) or return;
return $class->parse($raw_cookie);
}
sub get_raw_cookie {
my $r = shift;
$r ||= eval { $MOD_PERL == 2 ?
Apache2::RequestUtil->request() :
Apache->request } if $MOD_PERL;
return $r->headers_in->{'Cookie'} if $r;
die "Run $r->subprocess_env; before calling fetch()"
if $MOD_PERL and !exists $ENV{REQUEST_METHOD};
return $ENV{HTTP_COOKIE} || $ENV{COOKIE};
}
I faced the same issue and you can find the solution here :
“Expected token not present” error in my Apache log

Curl Perl module not working, formadd method missing

I want to use following script:
use FileHandle;
use WWW::Curl::Easy;
use WWW::Curl::Form;
my $file, my $curl, my $curlf, my $return, my $minified;
$file = new FileHandle();
$curl = new WWW::Curl::Easy();
$curl->setopt(CURLOPT_URL, "http://closure-compiler.appspot.com/compile");
$curlf = new WWW::Curl::Form();
$curlf->formadd('output_format', 'text');
$curlf->formadd('output_info', 'compiled_code');
$curlf->formadd('compilation_level', 'ADVANCED_OPTIMIZATIONS');
$curlf->formaddfile($name, 'js_code', 'multipart/form-data');
$curl->setopt(CURLOPT_HTTPPOST, $curlf);
$file->open(\$minified, ">");
$curl->setopt(CURLOPT_WRITEDATA, $file);
$return = $curl->perform();
Following error is thrown:
Can't locate object method "formadd" via package "WWW::Curl::Form" at ./minifyjs.pl ....
WHY??? The WWW::Curl module is installed properly, I used package libwww-curl-perl under Debian/Ubuntu.
Can anyone help me please?
Whoops.
Looks like this commit broke formadd. The XS sub doesn't match the PREFIX = curl_form_ declaration (as it's named curl_formadd), so perl doesn't know how to map the Perl version of the method back to XS.
4.12 was the first release that tried to support WWW::Curl::Form, looks like it didn't work after all. Not sure how I've missed this one. I should probably note it here that WWW::Curl::Form support wasn't exactly a high priority TODO item on my list, due to the existence of various high quality form handling modules on CPAN. I've only accepted the patch for the sake of feature completeness. You're encouraged to use those modules for managing form content. The standard WWW::Curl use case statement applies.
I released 4.13 to fix this issue. Good catch!
Check out WWW::Mechanize. It has a lot of nice form methods.

How can I fix the "Couldn't create file parser context for file ..." bug with Perl libxml on Debian?

When I try to read an XML file with XML::Simple, sometimes I get this error message:
Couldn't create file parser context for file ...
After some googling, it seems to be a problem with libxml-libxml-perl and is supposed to be fixed in the version I use (1.59-2).
Any ideas?
Edit: (code)
sub Read
{
my ($file, $no_option) = #_;
my %XML_INPUT_OPTIONS = ( KeyAttr => [], ForceArray => 1 );
if ((defined $file) && (-f $file))
{
my #stats = stat($file);
if ((defined $XML_CACHE{$file})
&& ($stats[9] == $XML_CACHE{$file}{modif_time}))
{
return ($XML_CACHE{$file}{xml});
}
else
{
my $xml = eval { XMLin($file,
(defined $no_option ? () : %XML_INPUT_OPTIONS)) };
AAT::Syslog("AAT::XML", "XML_READ_ERROR", $#) if ($#);
$XML_CACHE{$file}{modif_time} = $stats[9];
$XML_CACHE{$file}{xml} = $xml;
return ($xml);
}
}
return (undef);
}
And yes, I should & will use XML::Simple cache feature...
Does the error continue "No such file or directory at..."? If so, then I think that the problem is that (for whatever reason) when you get to that point in the script, whatever you are passing to XML::Simple has no xml file in it. Long story short, the script you are using may be passing a bad variable (blank? empty?) to XML::Simple at which point the module chokes. To debug, add a check on whatever you hand to XML::Simple before you pass it along. (See the next paragraph for a concrete example explaining why I think this may be your problem.)
A few months ago, I had a similar problem with Weather::Google. In a nutshell, the weather module was trying to get data from Google via LWP::Simple without a user agent. Google began (apparently) to reject requests without a user agent. I had to backtrack through the modules because the error appeared to come from XML::Simple. In fact, it was caused by what was done in LWP::Simple and Weather::Google. Or rather, the error was a result of Weather::Google not checking the data that was in an object created via LWP::Simple. In a case like this, it can be hard at first to see what's going wrong and where.