Parsing this kind of data - perl

I have written a wrapper for an API. Previously I'd worked on simple string-based GET requests to PHP scripts using Perl.
As part of analysing the response, I have to analyse the following data which appears to be an object. Unfortunately, I'm not sure how to extract usable data from this.
print Dumper on the data returns this:
$VAR1 = bless( {
'_rc' => '200',
'_request' => bless( {
'_uri_canonical' => bless( do{\(my $o = 'http://example.com/?list=1&token=h_DQ-3lru6uy_Zy0w-KXGbPm_b9llY3LAAAAALSF1roAAAAANxAtg49JqlUAAAAA')}, 'URI::http' ),
'_content' => '',
'_uri' => $VAR1->{'_request'}{'_uri_canonical'},
'_method' => 'GET',
'_headers' => bless( {
'accept-charset' => 'iso-8859-1,*,utf-8',
'accept' => 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*',
'cookie' => 'GUID=cHoW3DLOljP4K9LzposM',
'user-agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7) Gecko/20041107 Firefox/1.0',
'authorization' => 'Basic YWRtaW46bmljb2xl',
'cookie2' => '$Version="1"',
'::std_case' => {
'cookie' => 'Cookie',
'cookie2' => 'Cookie2'
},
'accept-language' => 'en-US'
}, 'HTTP::Headers' )
}, 'HTTP::Request' ),
'_headers' => bless( {
'client-peer' => 'myip:8085',
'content-type' => 'text/plain',
'cache-control' => 'no-cache',
'connection' => 'keep-alive',
'client-date' => 'Sat, 18 Jul 2015 12:41:00 GMT',
'::std_case' => {
'client-response-num' => 'Client-Response-Num',
'set-cookie2' => 'Set-Cookie2',
'client-date' => 'Client-Date',
'client-peer' => 'Client-Peer',
'set-cookie' => 'Set-Cookie'
},
'client-response-num' => 1,
'content-length' => '8684'
}, 'HTTP::Headers' ),
'_msg' => 'OK',
'_protocol' => 'HTTP/1.1',
'_content' => '{"build":30470,"torrents": [
["043CC5FA0C741CDAD9D2E5CC20DF64A4A400FA34",136,"Epi.S01E03.720p.HDTV.x264-IMMERSE[rarbg]",690765843,39,26951680,671744,24,0,0,0,"",0,1454,0,114,2436,1,663814163,"","","Stopped","512840d7",1437022635,0,"","/mydir/Epi.S01E03.720p.HDTV.x264-IMMERSE[rarbg]",0,"0368737A",false],
["097AA60280AE3E4BA8741192CB015EE06BD9F992",200,"Epi.S01E04.HDTV.x264-KILLERS[ettv]",221928759,1000,221928759,8890308649,40059,0,0,0,"",0,1461,0,4395,65536,-1,0,"","","Queued Seed","512840d8",1437022635,1437023190,"","/mydir/Epi.S01E04.HDTV.x264-KILLERS[ettv]",0,"8F52310A",false]],
"label": [],"torrentc": "350372445"
,"rssfeeds": []
,"rssfilters": []
}
',
'_msg' => 'OK',
'_protocol' => 'HTTP/1.1'
}, 'HTTP::Response' );
I would like to extract each of the following strings from the returned object
097AA60280AE3E4BA8741192CB015EE06BD9F992
200
Epi.S01E04.HDTV.x264-KILLERS[ettv]
Unfortunately, my understanding of objects in Perl is very elementary.
The original code which returns this data looks like this:
my $ua = LWP::UserAgent->new();
my $response = $ua->get( $url, #ns_headers );
print Dumper($response);
How can I work on the strings that of interest?

If you read the documentation for HTTP::Response, you will see that there is a content method, which will return the content of your HTTP message, and a decoded_content method that does the same but also decompresses the data if it happens to be compressed (in your case the data is uncompressed.)
In this case it looks like the content is encoded as JSON data, so you will also need to load the JSON module to decode it into a Perl data structure
For example
use JSON 'from_json';
my $content = from_json $response->decoded_content;
my $torrents = $content->{torrents};
for my $torrent ( #$torrents ) {
say for #$torrent[0,1,2];
say '';
}
output
043CC5FA0C741CDAD9D2E5CC20DF64A4A400FA34
136
Epi.S01E03.720p.HDTV.x264-IMMERSE[rarbg]
097AA60280AE3E4BA8741192CB015EE06BD9F992
200
Epi.S01E04.HDTV.x264-KILLERS[ettv]

Related

How do I unittest CGI.pm's file upload?

I have a CGI which gets a File uploaded and does something with it.
I would like a Unittest for the fileupload functionality
After reading http://www.perlmonks.org/?node_id=249917
I tried to adapt the code in CGI.pm's t/upload.t
{
%ENV = (
%ENV,
'SCRIPT_NAME' => '/data.cgi',
'SERVER_NAME' => 'localhost',
'HTTP_CONNECTION' => 'TE, close',
'REQUEST_METHOD' => 'POST',
'SCRIPT_URI' => 'http://localhost/data.cgi',
'CONTENT_LENGTH' => '160',
'SCRIPT_FILENAME' => '/var/www/cgi-bin/data.cgi',
'SERVER_SOFTWARE' => 'Apache/1.3.27 (Unix) ',
'HTTP_TE' => 'deflate,gzip;q=0.3',
'QUERY_STRING' => '',
'REMOTE_PORT' => '1855',
'HTTP_USER_AGENT' => 'libwww-perl/5.69',
'SERVER_PORT' => '80',
'REMOTE_ADDR' => '127.0.0.1',
'CONTENT_TYPE' => 'multipart/form-data; boundary=xYzZY',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'PATH' => '/usr/local/bin:/usr/bin:/bin',
'REQUEST_URI' => '/data.cgi',
'GATEWAY_INTERFACE' => 'CGI/1.1',
'SCRIPT_URL' => '/data.cgi',
'SERVER_ADDR' => '127.0.0.1',
'DOCUMENT_ROOT' => '/var/www/html',
'HTTP_HOST' => 'localhost'
);
local *STDIN;
open STDIN, '<test.txt' or die 'argh';
binmode STDIN;
$cgi = new CGI;
run()
}
test.txt:
--xYzZY
Content-Disposition: form-data; name="hello_world"; filename="goodbye_world.txt"
Content-Length: 13
Content-Type: text/plain
Goodbye World!
--xYzZY--
Now i get "400 Bad request (malformed multipart POST)" in cgi_error when i try to access the filehandle with
our $cgi;
sub run() {
$cgi = new CGI unless $cgi;
my $upload_fh = $cgi->upload('upload');
}

Facebook status update using WWW::Mechanize

I am trying to update status on facebook using Mechanize.I am able to login using the script but unable to update.I verified the id of form for status update is "u_0_w".
But selecting the form_id method says "There is no form with ID "u_0_w"".
My script is this:
use WWW::Mechanize;
use strict;
use warnings;
use Data::Dumper;
use HTTP::Cookies::Netscape;
my $cookiesfilename='/home/xxx/xxx/cookies.txt';
my $out;
my $mech = WWW::Mechanize->new( cookie_jar => HTTP::Cookies::Netscape->new( file => $cookiesfilename ) );
$mech->get("https://www.facebook.com/login.php");
my $response=$mech->submit_form(
fields => {
email => 'xxxx#xxxx.com',
pass => 'xxxxx',
}
);
#my $array=$mech->forms();
#$mech->get('/home.php');
print Dumper($mech->forms());
#$mech->form_id("u_0_w");
$mech->submit_form(
fields => {
xhpc_message_text=>'Why so serious'
}
);
print $response->status_line;
open($out, ">", "output_page.html") or die "Can't open output_page.html: $!";
print $out $response->decoded_content;
Then I tried to print all the forms on the page using Dumper the output is:
$VAR1 = bless( {
'default_charset' => 'UTF-8',
'enctype' => 'application/x-www-form-urlencoded',
'accept_charset' => 'UNKNOWN',
'action' => bless( do{\(my $o = 'https://www.facebook.com/search/web/direct_search.php')}, 'URI::https' ),
'method' => 'GET',
'attr' => {
'method' => 'get'
},
'inputs' => [
bless( {
'tabindex' => '-1',
'value' => '1',
'class' => '_42ft _42fu _4w98',
'type' => 'submit'
}, 'HTML::Form::SubmitInput' ),
bless( {
'/' => '/',
'autocomplete' => 'off',
'tabindex' => '1',
'name' => 'q',
'aria-label' => 'Search Facebook',
'value_name' => '',
'class' => 'inputtext _586f',
'type' => 'text',
'id' => 'u_0_b',
'role' => 'combobox',
'placeholder' => 'Search Facebook'
}, 'HTML::Form::TextInput' )
]
}, 'HTML::Form' );
It means it is not detecting the status update form it is detecting only Facebook search form.
What may be the problem for mechanize not detecting all the form elements?
The form contains <button type="submit">. Do Mechanize support it?
Why do you have to use Mechanize for this? There's already a module available for this on CPAN.
Take a look at WWW::Facebook::API.
Also see a related question: How do I use Perl's WWW::Facebook::API to publish to a user's newsfeed?
Synopsis:
use WWW::Facebook::API;
my $facebook = WWW::Facebook::API->new(
desktop => 0,
api_key => $fb_api_key,
secret => $fb_secret,
session_key => $query->cookie($fb_api_key.'_session_key'),
session_expires => $query->cookie($fb_api_key.'_expires'),
session_uid => $query->cookie($fb_api_key.'_user')
);
my $response = $facebook->stream->publish(
message => qq|Test status message|,
);

HTTP::Proxy in Perl

I need show the "content" that is in the hash , i test with : $c->header("content") , but but shows nothing , but in the content hash value if this.
as I can show _content?
The hash
<pre>
$VAR1 = bless(
{
'_protocol' => 'HTTP/1.1',
'_content' => '-----------------------------8283483225031
Content-Disposition: form-data; name="archivo"; filename="GFWLIVESetupLog.txt"
Content-Type: text/plain
l i v e R e d i s t : 0
G F W L C l i e n t : 0
-----------------------------8283483225031
Content-Disposition: form-data; name="destino"
C:/perl/test.txt
-----------------------------8283483225031--
',
'_uri' => bless(
do {
\(
my $o =
'http://localhost/shell.php?uploa
d='
);
},
'URI::http'
),
'_headers' => bless(
{
'user-agent' => 'Mozilla/5.0 (Windows NT
5.1; rv:19.0) Gecko/20100101 Firefox/19.0',
'accept' => 'text/html,application/xhtml
+xml,application/xml;q=0.9,*/*;q=0.8',
'accept-language' => 'es-ar,es;q=0.8,en-
us;q=0.5,en;q=0.3',
'cookie' => 'PHPSESSID=a8bkktvsripf6agpi
fnma61qq4',
'content-length' => '378',
'host' => 'localhost',
'via' => '1.1 doddy-701c8cb49 (HTTP::Pro
xy/0.20)',
'content-type' => 'multipart/form-data;
boundary=---------------------------8283483225031',
'x-forwarded-for' => '127.0.0.1',
'referer' => 'http://localhost/shell.php
?upload='
},
'HTTP::Headers'
),
'_method' => 'POST'
},
'HTTP::Request'
);
</pre>
The source :
use HTTP::Proxy;
use HTTP::Proxy::BodyFilter::simple;
use HTTP::Proxy::BodyFilter::complete;
use Data::Dumper;
my $server = HTTP::Proxy->new(port=>8080);
$server->host();
$server->push_filter(mime=>undef,response => HTTP::Proxy::BodyFilter::complete->new());
$server->push_filter(
mime=>undef,
request=>HTTP::Proxy::BodyFilter::simple->new(\&enable),
response => HTTP::Proxy::BodyFilter::simple->new(\&enable2));
$server->start();
sub enable {
my($a,$b,$c,$d,$e) = #_;
print $c->header("content");
#print Dumper $c;
}
sub enable2 {
my ($j,$k,$l,$m,$n) = #_;
print $$k;
}
pd : excuse my bad English
The content is not in the headers. In your dumper output, the headers is the HTTP::Headers object denoted by the _headers key. You want to call the content method.
$c->content;
See the HTTP::Request documentation for a full list of available methods.

trying to parse text and html from email over IMAP using MAIL::IMAPClient but text is hidden in parts and multi-parts

I can connect to the IMAP mail server easy enough:
use Mail::IMAPClient;
use MIME::Base64;
use MIME::Parser;
my $imap = Mail::IMAPClient->new(
Server => '192.168.2.2',
User => 'xxxxxx',
Password => 'yyyyyy',
Ssl => 1,
Uid => 1,
);
my $folders = $imap->folders
or die "List folders error: ", $imap->LastError, "\n";
print "Folders: #$folders\n";
$sfolder="INBOX.2012";
$imap->select( $sfolder )
or die "Select '$Opt{sfolder}' error: ", $imap->LastError, "\n";
my #msgs = $imap->messages or die "Could not messages: $#\n";
However, the text and html I want is not easily parsed due to codes like this:
Content-Transfer-Encoding:base64
Content-Type:text/html; charset=utf-8
Content-Transfer-Encoding:base64
Content-Type:text/html; charset=utf-8
Content-Transfer-Encoding:
Content-Type:multipart/mixed; boundary="----------=_4F0F4830.7079357A"
Multipart
Content-Transfer-Encoding:
Content-Type:multipart/mixed; boundary="----=_Part_4487195_1184536749.1326753403034"
Multipart
Content-Transfer-Encoding:
Content-Type:multipart/alternative; boundary=--boundary_164442_d184e417-739f-
46d6-824a-6ea1846e79de
Multipart
Content-Transfer-Encoding:
Content-Type:multipart/mixed; boundary="----=_Part_3882878_23916831.1326509484032"
Multipart
Content-Transfer-Encoding:
I tried this but it only works on a tiny number of different encodings.
if ($imap->get_header($msg,"Content-Transfer-Encoding")=~ /base64/i) {
print "\nMatch base64";
if ($imap->get_header($msg,"Content-Type")=~m/text/i ) {
push(#mail,decode_base64($imap->body_string($msg)));
}
elsif ($imap->get_header($msg,"Content-Type")=~m/image/i )
{ print "\nImage detected"; }
elsif ($imap->get_header($msg,"Content-Type")=~m/application/i )
{ print "\nApplication detected"; }
There are 7bit and 8bit variants and other encoding methods that contain the html or text I want for later use. I successfully use decode_base64() to decode base64. The worse ones to decode are the ones that contain multi-part codes. I feel like I am re-inventing the wheel and there must be a library or module that can do all the heavy lifting for me.
Other content types such as .jpg,.gif, and .pdf should simply be ignored. The multi-part emails contain at least 1 part that I an interested but many that are useless to me.
After further research this structure has some of the information I need but don't know how to get it out efficiently is another matter.
Dumping:$VAR1 = bless( {
'bodyparms' => {
'boundary' => '----=_NextPart_002_BC64_7D688C1F.A2FF9BE0'
},
'bodyextra' => undef,
'_top' => 1,
'bodydisp' => 'NIL',
'_id' => 'HEAD',
'bodysubtype' => 'mixed',
'PartsIndex' => {
'1.3' => bless( {
'bodyparms' => 'NIL',
'bodyid' => '<d9e26cc0-019c-4ac0-9b1e-9c9ac8424f52>',
'bodyextra' => 'NIL',
'bodydisp' => 'NIL',
'_id' => '1.3',
'bodysubtype' => 'jpeg',
'_prefix' => '1.3',
'bodysize' => '4808',
'bodytype' => 'image',
'bodyMD5' => 'NIL',
'bodylang' => 'NIL',
'bodydesc' => 'NIL',
'bodyenc' => 'base64'
}, 'Mail::IMAPClient::BodyStructure' ),
'1.1' => bless( {
'bodyparms' => {
'boundary' => '----=_NextPart_000_36AE_880DDD08.0A776E35'
},
'bodyextra' => undef,
'bodydisp' => 'NIL',
'_id' => '1.1',
'bodysubtype' => 'alternative',
'_prefix' => '1.1',
'bodytype' => 'MULTIPART',
'bodystructure' => [
bless( {
'bodyparms' => {
'charset' => 'utf-8'
},
'bodyextra' => 'NIL',
'bodyid' => 'NIL',
'bodydisp' => 'NIL',
'_id' => '1.1.1',
'bodysubtype' => 'PLAIN',
'_prefix' => '1.1.1',
'bodysize' => '1971',
'bodytype' => 'TEXT',
'bodyMD5' => 'NIL',
'textlines' => '74',
'bodylang' => 'NIL',
'bodydesc' => 'NIL',
'bodyenc' => 'quoted-printable'
}, 'Mail::IMAPClient::BodyStructure' ),
bless( {
'bodyparms' => {
'charset' => 'utf-8'
},
'bodyextra' => 'NIL',
'bodyid' => 'NIL',
'bodydisp' => 'NIL',
'_id' => '1.1.2',
'bodysubtype' => 'HTML',
'_prefix' => '1.1.2',
'bodysize' => '23364',
'bodytype' => 'TEXT',
'bodyMD5' => 'NIL',
'textlines' => '331',
'bodylang' => 'NIL',
'bodydesc' => 'NIL',
'bodyenc' => 'quoted-printable'
}, 'Mail::IMAPClient::BodyStructure' )
],
'bodyloc' => 'NIL',
'bodylang' => 'NIL'
}, 'Mail::IMAPClient::BodyStructure' ),
'1' => bless( {
'bodyparms' => {
'boundary' => '----=_NextPart_001_EA96_2BF8DEDE.32622D51'
},
'bodyextra' => undef,
'bodydisp' => 'NIL',
'_id' => 1,
'bodysubtype' => 'related',
'_prefix' => 1,
'bodytype' => 'MULTIPART',
'bodystructure' => [
$VAR1->{'PartsIndex'}{'1.1'},
bless( {
'bodyparms' => 'NIL',
'bodyid' => '<5dff39db-e81c-4410-be75-8662564fd328>',
'bodyextra' => 'NIL',
'bodydisp' => 'NIL',
'_id' => '1.2',
'bodysubtype' => 'jpeg',
'_prefix' => '1.2',
'bodysize' => '14406',
'bodytype' => 'image',
'bodyMD5' => 'NIL',
'bodylang' => 'NIL',
'bodydesc' => 'NIL',
'bodyenc' => 'base64'
}, 'Mail::IMAPClient::BodyStructure' ),
$VAR1->{'PartsIndex'}{'1.3'},
bless( {
'bodyparms' => 'NIL',
'bodyid' => '<717f2ef4-f795-4d1c-87cc-283c9b0a59b0>',
'bodyextra' => 'NIL',
'bodydisp' => 'NIL',
'_id' => '1.4',
'bodysubtype' => 'gif',
'_prefix' => '1.4',
'bodysize' => '2912',
'bodytype' => 'image',
'bodyMD5' => 'NIL',
'bodylang' => 'NIL',
'bodydesc' => 'NIL',
'bodyenc' => 'base64'
}, 'Mail::IMAPClient::BodyStructure' )
],
'bodyloc' => 'NIL',
'bodylang' => 'NIL'
}, 'Mail::IMAPClient::BodyStructure' ),
'1.2' => $VAR1->{'PartsIndex'}{'1'}{'bodystructure'}[1],
'1.1.2' => $VAR1->{'PartsIndex'}{'1.1'}{'bodystructure'}[1],
'2' => bless( {
'bodyparms' => {
'name' => 'BKD-7361945220.pdf'
},
'bodyid' => 'NIL',
'bodyextra' => 'NIL',
'bodydisp' => {
'attachment' => {
'filename' => 'BKD-7361945220.pdf'
}
},
'_id' => 2,
'bodysubtype' => 'octetstream',
'_prefix' => 2,
'bodysize' => '47540',
'bodytype' => 'application',
'bodyMD5' => 'NIL',
'bodystructure' => [],
'bodylang' => 'NIL',
'bodydesc' => 'NIL',
'bodyenc' => 'base64'
}, 'Mail::IMAPClient::BodyStructure' ),
'1.4' => $VAR1->{'PartsIndex'}{'1'}{'bodystructure'}[3],
'1.1.1' => $VAR1->{'PartsIndex'}{'1.1'}{'bodystructure'}[0]
},
'_prefix' => 'HEAD',
'PartsList' => [
1,
'1.1',
'1.1.1',
'1.1.2',
'1.2',
'1.3',
'1.4',
2
],
'bodytype' => 'MULTIPART',
'bodystructure' => [
$VAR1->{'PartsIndex'}{'1'},
$VAR1->{'PartsIndex'}{'2'}
],
'bodyloc' => 'NIL',
'bodylang' => 'NIL'
}, 'Mail::IMAPClient::BodyStructure' );
As you can see none of the values are guaranteed to be part of every part on the PartsIndex and some them are nested.
variable of interest for each PartsIndex item:
bodytype
bodysubtype
bodyenc
Parse mail messages with Courriel:
use strictures;
use Mail::IMAPClient qw();
use Courriel qw();
sub walk_parts {
my ($obj, $callback) = #_;
if ($obj->is_multipart) {
for my $part ($obj->parts) {
walk_parts($part, $callback);
}
} else {
$callback->($obj);
}
}
my $imap = Mail::IMAPClient->new(
…
) or die $#;
my $folders = $imap->folders
or die $imap->LastError;
$imap->select('INBOX')
or die $imap->LastError;
my #messages = $imap->messages
or die $imap->LastError;
for my $id (#messages) {
my $raw = $imap->message_string($id)
or die $imap->LastError;
my $email = Courriel->parse(text => $raw);
walk_parts $email, sub {
my ($part) = #_;
my $content = $part->content;
my $type = $part->mime_type;
}
}
I tried using a couple of prebuilt modules but they had too many dependencies and was hard to work with. This solution adds no dependencies beyond the original. I also had issues with the dependencies for libMagic, see above, and I did not want anyone who uses my program to have to deal with that issue either.
You have to call decode twice once for the main parent, and again for each child. Since this $imap->get_bodystructure($msg); contains all the information you need why add dependencies where none are needed. It took many many hours to figure out how to decode it manually, but it was worth it.
You can add whatever decoders you want to the decode() subroutine. I only need to decode the text/html and base64 encoded versions there of. The IMAPClient functions give you a list of all parents and children so you don't have to go making a list by yourself. The tricky part is you can have any number of parent each with any number of children, but only the children contain useful data. The parents can be ignored, since many of their values are blank,undef, or 'NIL' (literally). In fact a vast number of variables have the value of 'NIL'. Even ones that the email client could have answered for the user like bodyMD5 and bodylang are USUALLY equal 'NIL'. Due to the overwhelming use of 'NIL' parsing and using other fields may prove futile. Depend on your imap server and the people you recieve email from you mileage may vary.
If you have further questions leave a comment.
use Mail::IMAPClient;
use MIME::Base64;
use MIME::Parser;
sub decode {
($process, $imap) =#_;
if ($process->bodytype eq "TEXT") {
print "\n Text SubType:".$process->bodysubtype;
if ($process->bodyenc eq "base64") {
return decode_base64($imap->bodypart_string($msg,$process->id));
}
elsif (index(" -7bit- -8bit- -quoted-printable- ",lc($process->bodyenc)) !=-1 ) {
return $imap->bodypart_string($msg,$process->id);
}
print "\n==========Insert new decoder here============";
print "\n".$imap->bodypart_string($msg,$process->id);
print "\n=================================================";
}
return "";
}
#insert your login code with credentials here
$imap->select( $sfolder )
or die "Select '$Opt{sfolder}' error: ", $imap->LastError, "\n";
my #msgs = $imap->messages or die "Could not messages: $#\n";
foreach $msg (#msgs) {
my $raw = $imap->message_string($msg)
or die $imap->LastError;
$struct = $imap->get_bodystructure($msg);
#MULTIPART is a container designation and does not contain anything useful by itself.
#However it will still process all of the children that have content
if ($struct->bodytype ne "MULTIPART") { print "\n BodyEnc:".$struct->bodyenc();}
$rDecode=decode($struct,$imap);
#do not insert blanks.
if ($rDecode ne "" && (length($rDecode)>2)) {push(#mail,$rDecode); }
foreach $dumpme ($struct->bodystructure()) {
if ($dumpme->bodytype() eq "MULTIPART") {next;}
$rDecode="";
$rDecode=decode($dumpme,$imap);
#do not insert blanks.
if (($rDecode ne "") && (length($rDecode)>2) ) {
push(#mail,$rDecode); }
}
}
You need a MIME parser. Unfortunately, even then, you will need some normalization of your own, because there are multiple ways to represent the same data in MIME.

How do I access a value of a nested Perl hash?

I am new to Perl and I have a problem that's very simple but I cannot find the answer when consulting my Perl book.
When printing the result of
Dumper($request);
I get the following result:
$VAR1 = bless( {
'_protocol' => 'HTTP/1.1',
'_content' => '',
'_uri' => bless( do{\(my $o = 'http://myawesomeserver.org:8081/counter/')}, 'URI::http' ),
'_headers' => bless( {
'user-agent' => 'Mozilla/5.0 (X11; U; Linux i686; en; rv:1.9.0.4) Gecko/20080528 Epiphany/2.22 Firefox/3.0',
'connection' => 'keep-alive',
'cache-control' => 'max-age=0',
'keep-alive' => '300',
'accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'accept-language' => 'en-us,en;q=0.5',
'accept-encoding' => 'gzip,deflate',
'host' => 'localhost:8081',
'accept-charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'
}, 'HTTP::Headers' ),
'_method' => 'GET',
'_handle' => bless( \*Symbol::GEN0, 'FileHandle' )
}, 'HTTP::Server::Simple::Dispatched::Request' );
How can I access the values of '_method' ('GET') or of 'host' ('localhost:8081').
I know that's an easy question, but Perl is somewhat cryptic at the beginning.
Narthring has it right as far as the brute force method. Nested hashes are addressed by chaining the keys like so:
$hash{top_key}{next_key}{another_key}; # for %hash
# OR
$hash_ref->{top_key}{next_key}{another_key}; # for refs.
However since both of these "hashes" are blessed objects. It might help reading up on HTTP::Server::Simple::Dispatched::Request, which can tell you that it's a HTTP::Request object and looking at HTTP::Request section on the header and method methods, tells you that the following do the trick:
my $method = $request->method();
my $host = $request->header( 'host' );
Really, I recommend you get the firefox search plugin called Perldoc Module::Name and when you encounter Dumper output that says "bless ... 'Some::Module::Name'" you can just copy and paste it into the search plugin and read the documentation on CPAN.