Cookies in perl lwp - perl

I once wrote a simple 'crawler' to download http pages for me in JAVA.
Now I'm trying to rewrite to same thing to Perl, using LWP module.
This is my Java code (which works fine):
String referer = "http://example.com";
String url = "http://example.com/something/cgi-bin/something.cgi";
String params= "a=0&b=1";
HttpState initialState = new HttpState();
HttpClient httpclient = new HttpClient();
httpclient.setState(initialState);
httpclient.getParams().setCookiePolicy(CookiePolicy.NETSCAPE);
PostMethod postMethod = new PostMethod(url);
postMethod.addRequestHeader("Referer", referer);
postMethod.addRequestHeader("User-Agent", " Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13");
postMethod.addRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8");
postMethod.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
String length = String.valueOf(params.length());
postMethod.addRequestHeader("Content-Length", length);
postMethod.setRequestBody(params);
httpclient.executeMethod(postMethod);
And this is the Perl version:
my $referer = "http://example.com/something/cgi-bin/something.cgi?module=A";
my $url = "http://example.com/something/cgi-bin/something.cgi";
my #headers = (
'User-Agent' => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Referer' => $referer,
'Content-Type' => 'application/x-www-form-urlencoded',
);
my #params = (
'a' => '0',
'b' => '1',
);
my $browser = LWP::UserAgent->new( );
$browser->cookie_jar({});
$response = $browser->post($url, #params, #headers);
print $response->content;
The post request executes correctly, but I get another (main) webpage. As if cookies were not working properly...
Any guesses what is wrong?
Why I'm getting different result from JAVA and perl programs?

You can also use WWW::Mechanize, which is a wrapper around LWP::UserAgent. It gives you the cookie jar automatically.

You want to be creating hashes, not arrays - e.g. instead of:
my #params = (
'a' => '0',
'b' => '1',
);
You should use:
my %params = (
a => 0,
b => 1,
);
When passing the params to the LWP::UserAgent post method, you need to pass a reference to the hash, e.g.:
$response = $browser->post($url, \%params, %headers);
You could also look at the request you're sending to the server with:
print $response->request->as_string;
You can also use a handler to automatically dump requests and responses for debugging purposes:
$ua->add_handler("request_send", sub { shift->dump; return });
$ua->add_handler("response_done", sub { shift->dump; return });

I believe it has to do with $response = $browser->post($url, #params, #headers);
From the doc of LWP::UserAgent
$ua->post( $url, \%form )
$ua->post( $url, \#form )
$ua->post( $url, \%form, $field_name => $value, ... )
$ua->post( $url, $field_name => $value,... Content => \%form )
$ua->post( $url, $field_name => $value,... Content => \#form )
$ua->post( $url, $field_name => $value,... Content => $content )
Since your params and headers are as hashes, I would try this:
my $referer = "http://example.com/something/cgi-bin/something.cgi?module=A";
my $url = "http://example.com/something/cgi-bin/something.cgi";
my %headers = (
'User-Agent' => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; pl; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Referer' => $referer,
'Content-Type' => 'application/x-www-form-urlencoded',
);
my %params = (
'a' => '0',
'b' => '1',
);
my $browser = LWP::UserAgent->new( );
$browser->cookie_jar({});
$response = $browser->post($url, \%params, %headers);

Related

Set header fields for HTTP::Request::Common

I've problems to set header fields for sending requests by Perl modul 'HTTP::Request::Common'.
In subject to the corresponding server I have to set different header fields for my request.
So I want to use a sub 'MakeRequest()'
sub MakeRequest {
my $url = shift;
my $header = shift;
my $content = shift;
my $request = HTTP::Request::Common::POST($url, Header => $header, Content => $content);
# I tried also my $request = HTTP::Request::Common::POST($url, $header, Content => $content);
my $ua = LWP::UserAgent->new;
my $response = $ua->request($request);
return $response;
}
and pass some informations into it my $response = MakeRequest($url, GetRequestHeader(), $content);
sub GetRequestHeader {
my $header = HTTP::Headers->new;
$header->header('Content-Type' => 'application/json; charset=utf-8');
$header->header('accept' => 'application/json');
$header->authorization_basic($username, $password);
return $header;
# I tried this first, but got the same result as shown below
#
# my %header = (
# 'content_type' => 'application/json; charset=utf-8',
# 'authorization_basic' => ($username, $password),
# 'accept' => 'application/json'
# );
# return %header;
}
But all I got from the remote server is this
"Content type 'application/x-www-form-urlencoded' is not supported.
Please use 'application/json; charset=utf-8'."
When I made a print Data::Dumper($request); I get
'_headers' => bless( {
'content-length' => 544,
'user-agent' => 'libwww-perl/6.15',
'header' => bless( {
'content-type' => 'application/json; charset=utf-8',
'authorization' => 'Basic Qxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==',
'accept' => 'application/json'
}, 'HTTP::Headers' ),
'::std_case' => {
'header' => 'Header',
'if-ssl-cert-subject' => 'If-SSL-Cert-Subject'
},
'content-type' => 'application/x-www-form-urlencoded'
}, 'HTTP::Headers' ),
What's my mistake that the 'content-type' isn't overwritten by my header field settings?
According to the documentation:
HTTP::Request::Common::GET $url, Header => Value,...
is the same as
HTTP::Request->new(
GET => $url,
HTTP::Headers->new(Header => Value,...),
)
I think your original approach (the commented) is good, but you assign it the wrong way:
my $header = shift;
my $content = shift;
my $request = HTTP::Request::Common::POST($url, Header => $header, Content => $content);
Here, you create only one header, named Header. You can use the following if you have a HTTP::Headers object:
my $request = HTTP::Request::Common::POST($url, $header->flatten, Content => $content);
If you change GetRequestHeader to return a hash reference (as you have commented, but with return \%header instead of return %header), you can use the following:
my $request = HTTP::Request::Common::POST($url, %$hashref, Content => $content);

Getting "500 Internal Server Error" retrieving page with LWP::UserAgent

I'm trying to retrieve a page using LWP::UserAgent but I keep getting a "500 Internal Server Error" as a response. Retrieving the exact same page in Firefox (using a fresh "Private Window" - so without any cookies set yet) succeeds without a problem.
I've duplicated the headers exactly as sent by Firefox, but that still does not make a difference. Here's my full code:
use strict;
use LWP::UserAgent;
my $browserObj = LWP::UserAgent->new();
$browserObj->cookie_jar( {} );
$browserObj->timeout(600);
my #header = (
'Host' => 'www.somedomain.com',
'User-Agent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0',
'Accept-Language' => 'en-US,en;q=0.5',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding' => 'gzip, deflate, br',
'DNT' => '1',
'Connection' => 'keep-alive',
'Upgrade-Insecure-Requests' => '1'
);
my $URL = "https://www.somedomain.com";
my $response = $browserObj->get( $URL, #header );
if( $response->is_success ) {
print "Success!\n";
} else {
print "Error: " . $response->status_line . ".\n" );
}
The real web address is something other than "www.somedomain.com". In fact, it's a URL to an online casino, but I don't want my question be regarded as spam.
But anyone any idea what could be wrong?
On our corporate network which has a proxy (and an out of date perl version - there may be better options in newer versions) we tend to add the following for one-offs:
BEGIN {
$ENV{HTTPS_DEBUG} = 1; # optional but can help if you get a response
$ENV{HTTPS_PROXY} = 'https://proxy.server.here.net:8080';
}
If we don't do this the script simply fails to connect with no other information.
You may also want to add something like this if you want to inspect the messages:
$browserObj->add_handler("request_send", sub { shift->dump; return });
$browserObj->add_handler("response_done", sub { shift->dump; return });

need to set headers on guzzle request

I need to add the type of headers to the guzzle request below, but cannot figure out how to put it in without getting an error
This is what I want to add :
$command->set('command.headers', array('content-type' => 'application/x-www-form-urlencoded
to this code below:
<?php
$url = "https://jsonplaceholder.typicode.com/posts";
$client = \Drupal::httpClient();
$post_data = array('color' => 'red');
$response = $client->request('POST', $url, [
'form_params' => $post_data,
'verify' => false
]);
$body = $response->getBody();
dsm($body);
?>
When I needed use the Guzzle at D8 to make a POST I passed the Content-Type like this:
$url = "https://jsonplaceholder.typicode.com/posts";
$client = \Drupal::httpClient();
$post_data = array('color' => 'red');
$response = $client->request('POST', $url, [
'headers' => ['Content-Type' => 'application/json'],
'body' => rawData($post_data),
]);
$body = $response->getBody()->getContents();
$status = $response->getStatusCode();
A good idea is use the D8 Dependency Injection to pass the HTTP_CLIENT.

POSTing to form using LWP::UserAgent gets no response (mostly)

Here is my dilemma: I am trying to fill out a web form and get a result back from that form using LWP::UserAgent. Here is an example of my code:
#!/usr/bin/perl -w
use strict;
use LWP;
use HTTP::Request::Common;
use LWP::Debug qw(+);
my $ua = LWP::UserAgent->new(protocols_allowed=>["https"]);
my $req = POST 'https://their.securesite.com/index.php',
[ 'firstName' => 'Me',
'lastName' => 'Testing',
'addressLine1' => '123 Main Street',
'addressLine2' => '',
'city' => 'Anyplace',
'state' => 'MN',
'zipCode' => '55555',
'card' => 'visa',
'cardNumber' => '41111111111111111',
'ccv2' => '123',
'exp_month' => '07',
'exp_year' => '2015',
'shared_key' => 'hellos',
];
my $response = $ua->request($req);
print $response->is_success() . "\n";
print $response->status_line . "\n";
print $response->content . "\n";
When I run this, I get back a 200 OK and a "1" for success, but not the response page from the form. Just the closing tags:
</body>
</html>
Could this possibly be due to the fact that the form page and response page both have the same URL? I am new to LWP, so I am grasping at straws here. It may still be on the clients end, but I want to rule out any issues on my end as well.
Thanks in advance for any help you guys can give - I am Googled out.
If you can use Mojo::UserAgent (part of the Mojolicious suite of tools) the code would look like this. Note that you might need IO::Socket::SSL in order to use HTTPS.
#!/usr/bin/env perl
use strict;
use warnings;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $tx = $ua->post('https://their.securesite.com/index.php', form =>
{ 'firstName' => 'Me',
'lastName' => 'Testing',
'addressLine1' => '123 Main Street',
'addressLine2' => '',
'city' => 'Anyplace',
'state' => 'MN',
'zipCode' => '55555',
'card' => 'visa',
'cardNumber' => '41111111111111111',
'ccv2' => '123',
'exp_month' => '07',
'exp_year' => '2015',
'shared_key' => 'hellos',
});
if ( $tx->success ) {
print $tx->res->body;
# or work with the resulting DOM
# my $dom = $tx->res->dom;
} else {
my ($err, $code) = $tx->error;
print $code ? "$code response: $err\n" : "Connection error: $err\n";
}
The interface is a little different, but it has lots of nice features, including Mojo::DOM integration for parsing the response HTML.
Use $response->decoded_content to get the content without the headers. See HTTP::Message for more information.
#!/usr/bin/perl -w
use strict;
use URI;
use LWP::UserAgent;
use HTTP::Request;
my $url = URI->new('https://their.securesite.com/index.php');
my $ua = LWP::UserAgent->new();
my $request = HTTP::Request->new(
'POST',
$url,
HTTP::Headers->new(
'User-Agent' => "perl ua/ v0.001",
'Accept' => "text/xml, multipart/*, application/soap"
),
[ 'firstName' => 'Me',
'lastName' => 'Testing',
'addressLine1' => '123 Main Street',
'addressLine2' => '',
'city' => 'Anyplace',
'state' => 'MN',
'zipCode' => '55555',
'card' => 'visa',
'cardNumber' => '41111111111111111',
'ccv2' => '123',
'exp_month' => '07',
'exp_year' => '2015',
'shared_key' => 'hellos',
]
) or die "Error initiating Request: $#\n";
my $response = $ua->request( $request );
if ($response->is_success) {
print $response->decoded_content, "\n";
} else {
die $response->status_line;
}
Check the value of $response->as_string
It'll show you full http response with headers

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.