Translate a curl request in rest::client Perl - rest

This curl line works perfectly :
curl -v -H "Content-Type: application/json" -k -d "{\"UserName\":\"test\",\"Password\":\"test\"}" -X POST "https://xxx.xxx.xxx.xxx/redfish/v1/SessionService/Sessions"
but when trying to translate into Perl, I've a http 500 error code in response.
Here an excerpt of my code :
$CLIENT=REST::Client->new(
{
host => $HOSTURL,
timeout => 300,
}
);
# Formatage de la requete
$URL = "/redfish/v1/SessionService/Sessions";
$ACTION = "POST";
%CONTENT_JSON = (
'UserName' => 'test',
'Password' => 'test'
);
%SESS_HEADERS = (
'Content-Type' => 'application/json',
);
$CONTENT_JSON = encode_json(\%CONTENT_JSON);
# Lancement de la requete
print Dumper $ACTION,$URL,$CONTENT_JSON,\%SESS_HEADERS;
$CLIENT->request($ACTION,$URL,$CONTENT_JSON,\%SESS_HEADERS);
$REPCODE = $CLIENT->responseCode();
print Dumper $REPCODE;
print Dumper $CLIENT->responseContent();
exit;
and the results :
$VAR1 = 'POST';
$VAR2 = '/redfish/v1/SessionService/Sessions';
$VAR3 = '{"UserName":"test","Password":"test"}';
$VAR4 = {
'Content-Type' => 'application/json'
};
$VAR1 = 500;
$VAR1 = 'Can\'t connect to xxx.xxx.xxx.xxx:443
So, where am I wrong ?

This looks like a clue:
$VAR1 = 'Can\'t connect to xxx.xxx.xxx.xxx:443
Are you sure that you've got the correct domain name? And does the resource work over HTTPS?
Oh and I bet REST::Client uses LWP::UserAgent, so you'll need LWP::Protocol::https installed as well.

Related

Curl api parsing

Am trying to parse curl api
but am getting this error 401 Unauthorized
i don't know where is the problem comes from.
because the authentication details are ok
this is the curl
curl 'https://api.twilio.com/2010-04-01/Accounts/SID/Messages.json' \
-X POST \
--data-urlencode 'To=whatsapp:+123456789' \
--data-urlencode 'From=whatsapp:+1234567890' \
--data-urlencode 'Body=Your Yummy Cupcakes Company order of 1 dozen frosted cupcakes has shipped and should be delivered on July 10, 2019. Details: http://www.yummycupcakes.com/' \
-u SID:[AuthToken]
#!/usr/bin/perl
use strict;
use warnings;
use HTTP::Tiny;
use JSON;
use Data::Dumper;
my $url = "https://api.twilio.com/2010-04-01/Accounts/SID/Messages.json";
my $json = encode_json {
To => 'whatsapp:+256775562361',
From => 'whatsapp:+14155238886',
Body => 'new test msg',
};
my $http = HTTP::Tiny->new(
default_headers => {
Authorization => 'SID:TOKEN',
}
);
my $response = $http->post( $url => {
content => $json,
headers => { 'Content-Type' => 'application/json' },
});
if ( $response->{'is_success'} ) {
print Dumper( decode_json $response->{'content'} );
} else {
print "$response->{'status'} $response->{'reason'}\n";
}
The format of the "Authorization" header isn't <user>:<pass> -- it's <auth-scheme> <authorization-parameters>. curl is doing this for you, but for this it's basically:
Authorization: Basic <mime-encoded "<user>:<pass>">
I use the URI module for this:
my $uri = URI->new("https://api.twilio.com/...");
$uri->userinfo("$sid:$auth");
$http->post( $uri => ... );

Unable to pass custom header using perl module HTTP::Request::Generator

I'm using atom and testing out HTTP::Request::Generator PERL module. Code , below works on most part but I'm unable to send cookies or headers, it only displays default headers even when I have set in my code.
use strict;
use warnings;
use HTTP::Request::Generator 'generate_requests';
use LWP::UserAgent;
my $ua = 'LWP::UserAgent'->new;
my $gen = generate_requests(
method => 'GET',
host => [ 'https://abc.ai/' ],
pattern => 'https://abc.ai',
headers => {
"User-Agent" => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64',
"Cookie" => '_abc',
},
wrap => sub {
my ( $req ) = #_;
# Fix up some values
$req->{'headers'}{'Content-Length'} = 666;
},
wrap => \&HTTP::Request::Generator::as_http_request,
);
while ( my $req = $gen->() ) {
my $response = $ua->request( $req );
# print $response->protocol, ' ', $response->status_line, "\n";
print $req->headers->as_string, "\n";
print $req->as_string();
# Do something with $response here?
if ($response->is_success) {
# print $response->decoded_content;
print $response ->header('title');
}
else {
die $response->status_line;
}
}
Output
User-Agent: libwww-perl/6.31
Login
The title page indicate me I'm not logged in this cookie is fine and i have tested it using curl i can manually login and retrieve required resource. Why its failing for perl, how can access my header options in code above. Thanks.
Solution
body_params => {
comment => ['Some comment', 'Another comment, A++'],
},
Got it solved adding above code.
You can't provide the same option (wrap) twice:
wrap => sub {
my ( $req ) = #_;
# Fix up some values
$req->{'headers'}{'Content-Length'} = 666;
},
wrap => \&HTTP::Request::Generator::as_http_request,
This may work though:
wrap => sub {
my ( $req ) = #_;
# Fix up some values
$req->{'headers'}{'Content-Length'} = 666;
return HTTP::Request::Generator::as_http_request( $req );
},
Also the headers option appears to take an arrayref of hashrefs, like this:
headers => [
{
"User-Agent" => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
"Cookie" => '_abc',
},
],
I guess the reason for that is so you can provide alternative sets of headers:
headers => [
{
"User-Agent" => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
"Cookie" => '_abc',
},
{
"User-Agent" => 'Mozilla/1.0 (Hoover Vacuum Cleaner)',
"Cookie" => '_def',
},
],
That way your request generator can generate two requests for each page, using different User-Agent strings, or different cookies (so logged in as different users), or different Accept headers, or whatever.

Unable to post messages using Mailbox API and Mojo::UserAgent

According to the API docs (https://documentation.mailgun.com/api-sending.html) all the relevant parameters are supplied, but it gives me
400 response: BAD REQUEST
Here's my piece of code:
#!/usr/bin/perl
use Mojo::UserAgent;
use MIME::Base64;
use JSON qw(to_json);
use strict;
use warnings;
use v5.10;
my $ua = Mojo::UserAgent->new;
my $endpoint = 'https://api.mailgun.net/v3/sandbox2ad5b70fd744416ea7ff3d5422YYYYYY.mailgun.org/messages';
my $key = 'key-d3d8d350d4ef9c92349df62208XXXXXX';
my $headers = { 'Authorization' => 'Basic ' . encode_base64('api:' . $key) };
my $params = {
'to' => 'abc#domain.ru',
'subject' => 'testing',
'text' => 'some text',
'from' => 'postmaster#sandbox2ad5b70fd744416ea7ff3d5422YYYYYY.mailgun.org'
};
my $tx = $ua->post($endpoint, $headers, json => $params);
my $res = $tx->success;
if ($res) {
say $res->body;
} else {
my $err = $tx->error;
die "$err->{code} response: $err->{message}" if $err->{code};
die "Connection error: $err->{message}";
}
I have Mojo version as follows:
CORE
Perl (v5.22.1, linux)
Mojolicious (7.26, Doughnut)
OPTIONAL
EV 4.0+ (4.22)
IO::Socket::Socks 0.64+ (0.67)
IO::Socket::SSL 1.94+ (2.024)
Net::DNS::Native 0.15+ (n/a)
I wrote another version of this script using LWP::UserAgent and it works fine.
Are there some Mojo::UserAgent experts who might have an idea of what is wrong with the script?
UPDATED
Here's my LWP::UserAgent version which works without problems:
my ($key, $domain, $from, $from_name, $to, $subject, $comments) = #_;
my $url = 'https://api.mailgun.net/v3';
$url = $url . '/' . $domain . '/messages';
my $ua = LWP::UserAgent->new;
$ua->default_header('Authorization' => 'Basic ' . encode_base64('api:' . $key));
my $data = {
to => $to,
subject => $subject,
text => $comments,
from => $from_name . '<' . $from . '>'
};
my $r = $ua->post($url, Content => $data);
my $rc = $r->code;
if ($rc == 200) {
my $hash = from_json($r->decoded_content);
say $hash->{id};
say $hash->{message};
} else {
return { error => $rc };
}
UPDATED ON 25.02.2017
I used fake requests to my localhost:9000. Here's what I've traced using nc -l 9000:
POST / HTTP/1.1
TE: deflate,gzip;q=0.3
Connection: TE, close
Authorization: Basic YXBpOmtleS1kM2Q4ZDM1MGQ0ZWY5YzkyMzQ5ZGY2MjIwOGRXXXXXX==
Host: localhost:9000
User-Agent: libwww-perl/6.15
Content-Length: 144
Content-Type: application/x-www-form-urlencoded
text=%3Chtml%3E%3Cbody%3E%3Cp%3Etest%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E&from=John%3Clala%40ya.ru%3E&to=zozoba29a%40yandex.ru&subject=My+Subject
And:
POST / HTTP/1.1
Host: localhost:9000
Accept-Encoding: gzip
Content-Type: application/x-www-form-urlencoded
Authorization: Basic YXBpOmtleS1kM2Q4ZDM1MGQ0ZWY5YzkyMzQ5ZGY2MjIwOGRjXXXXXX==
Content-Length: 144
User-Agent: Mojolicious (Perl)
from=John%3Clala%40ya.ru%3E&subject=My+Subject&text=%3Chtml%3E%3Cbody%3E%3Cp%3Etest%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E&to=zozoba29a%40yandex.ru

Send a HTTP POST Request(xml data ) using WWW::Curl in perl

I want to use WWW::Curl instead of LWP::UserAgent to send a post request.
Below is the Code using LWP::UserAgent which works fine.
my $agent = LWP::UserAgent->new(agent => 'perl post');
push #{ $agent->requests_redirectable }, 'POST';
my $header = HTTP::Headers->new;
$header->header('Content-Type' => "text/xml; charset=UTF-8");
$header->content_encoding('gzip');
utf8::encode( my $utf8_content = $args{content} );
sinfo $utf8_content;
$error->description($utf8_content);
$error->log;
my $request = HTTP::Request->new(POST => $args{url}, $header, $utf8_content);
my $response = $agent->request($request);
I need to rewrite this code using WWW::Curl as Curl is faster than LWP.
I have tried the below code but it returns me code '35' as response, which
means the request is invalid.
my $curl = WWW::Curl::Easy->new();
$curl->setopt(WWW::Curl::Easy::CURLOPT_HEADER,1);
$curl->setopt(WWW::Curl::Easy::CURLOPT_URL,$self->uri());
$curl->setopt(WWW::Curl::Easy::CURLOPT_POST, 1);
$curl->setopt(WWW::Curl::Easy::CURLOPT_POSTFIELDS, $utf8_content);
my $response;
$curl->setopt(WWW::Curl::Easy::CURLOPT_WRITEDATA,\$response);
my $retcode = $curl->perform();
The data i pass in the post request ($utf8_content) is a xml string ,sample xml :
<Request>
<Source>
<RequestorID Password="PASS" Client="Client" EMailAddress="email#address.com"/>
<RequestorPreferences Language="en">
<RequestMode>SYNCHRONOUS</RequestMode>
</RequestorPreferences>
</Source>
<RequestDetails>
<SearchRequest>
<ItemDestination DestinationType="area" DestinationCode="XYZ"/>
</ItemDestination>
</SearchRequest>
</RequestDetails>
</Request>
Moreover the response too will be a xml string which can be retrieved from $response;
In theory, this should work, but doesn't. The problem is that $utf8_content_gzip contains a \0 in the middle and the C API truncates the request body. If this is a bug and not just a misunderstanding of mine how to talk to WWW::Curl, then either have the bug fixed or work around by simply not encoding the request.
use utf8;
use strictures;
use Devel::Peek qw(Dump);
use Encode qw(encode);
use HTTP::Response qw();
use IO::Compress::Gzip qw(gzip $GzipError);
use WWW::Curl::Easy qw();
my $utf8_content_gzip;
{
my $utf8_content = encode('UTF-8', '<root>Třistatřicettři stříbrných stříkaček stříkalo přes třistatřicettři stříbrných střech.</root>', Encode::LEAVE_SRC | Encode::FB_CROAK);
gzip(\$utf8_content, \$utf8_content_gzip)
or die sprintf 'gzip error: %s', $GzipError;
}
Dump $utf8_content_gzip;
my $xml;
{
my $curl = WWW::Curl::Easy->new;
$curl->setopt(WWW::Curl::Easy::CURLOPT_HEADER(), 1);
$curl->setopt(WWW::Curl::Easy::CURLOPT_URL(), 'http://localhost:5000');
$curl->setopt(WWW::Curl::Easy::CURLOPT_HTTPHEADER(), ['Content-Type: text/xml; charset=UTF-8', 'Content-Encoding: gzip']);
$curl->setopt(WWW::Curl::Easy::CURLOPT_POST(), 1);
$curl->setopt(WWW::Curl::Easy::CURLOPT_POSTFIELDS(), $utf8_content_gzip);
my $response;
$curl->setopt(WWW::Curl::Easy::CURLOPT_WRITEDATA(), \$response);
my $retcode = $curl->perform;
if (0 == $retcode) {
$response = HTTP::Response->parse($response);
$xml = $response->decoded_content;
} else {
die sprintf 'libcurl error %d (%s): %s', $retcode, $curl->strerror($retcode), $curl->errbuf;
}
}
Have you tried $curl->setopt(CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3);?

Connecting keeps closing?

so i'm having a problem trying to automatically login to a internal website. I'm able to send a post request but in the response I always get the Header Connection: close. I've tried to pass is through the post request but it still seems to respond with Connection: close. I want to be able to navigate through the website so I need the Connection: keep-alive so that i can send more request. Could anyone tell me what I'm doing wrong? here's the code:
#usr/bin/perl
#NetTelnet.pl
use strict; use warnings;
#Sign into cfxint Unix something...
use Net::Telnet;
# Create a new instance of Net::Telnet,
my $telnetCon = new Net::Telnet (Timeout => 10,
Prompt => '/bash\$ $/') or die "Could not make connection.";
my $hostname = 'cfxint';
# Connect to the host of the users choice
$telnetCon->open(Host => $hostname,
Port => 23) or die "Could not connect to $hostname.";
use WWW::Mechanize;
my $mech = WWW::Mechanize->new(cookie_jar => {});
&login_alfresco;
sub login_cxfint {
#get username and password from user
my $CXusername = '';
my $CXpassword = '';
# Recreate the login
# Wait for the login: message and then enter the username
$telnetCon->waitfor(match => '/login:/i');
# this method adds a \n to the end of the username, it mimics hitting the enter key after entering your username
$telnetCon->print($CXusername);
# does the same as the previous command but for the password
$telnetCon->print($CXpassword);
#Wait for the login successful message
$telnetCon->waitfor();
}
sub login_alfresco{
my $ALusername = '';
my $ALpassword = '';
$mech->get('http://documents.ifds.group:8080/alfresco/faces/jsp/login.jsp');
my $res = $mech->res;
my $idfaces = '';
if($res->is_success){
my $ff = $res->content;
if($ff =~ /id="javax.faces.ViewState" value="(.*?)"/){
$idfaces = $1;
}
else {
print "javax.faces /Regex error?\n";
die;
}
}
print $idfaces, "\n";
#Send the get request for Alfresco
$mech->post('http://documents.ifds.group:8080/alfresco/faces/jsp/login.jsp',[
'loginForm:rediretURL' =>,
'loginForm:user-name' => $ALusername,
'loginForm:user-password' => $ALpassword,
'loginForm:submit' => 'Login',
'loginForm_SUBMIT' => '1',
'loginForm:_idcl' => ,
'loginForm:_link_hidden_' => ,
'javax.faces.ViewState' => $idfaces], **'Connection' =>'keep-alive'**);
$res = $mech->res;
open ALF, ">Alfresco.html";
print ALF $mech->response->as_string;
if($res->is_success){
my $ff = $res->content;
if($ff =~ /id="javax.faces.ViewState" value="(.*?)"/){
$idfaces = $1;
}
else {
print "javax.faces /Regex error?\n";
die;
}
}
print $idfaces, "\n";
#Logout
$mech->post('http://documents.ifds.group:8080/alfresco/faces/jsp/extension/browse/browse.jsp', [
'browse:serach:_option' => '0',
'browse:search' => ,
'browse:spaces-pages' => '20',
'browse:content-pages' => '50',
'browse_SUBMIT' => '1',
'id' => ,
'browse:modelist' => '',
'ref'=>'',
'browse:spacesList:sort' => ,
'browse:_idJsp7' => ,
'browse:sidebar-body:navigator' => ,
'browse:contentRichList:sort' => ,
'browse:act' => 'browse:logout',
'outcome' => 'logout',
'browse:panel' => ,
'javax.faces.ViewState' => $idfaces,])
}
You can enable keep-alive by using a connection cache:
use LWP::ConnCache;
...
$mech->conn_cache(LWP::ConnCache->new);
All that header means is that the connection will be closed upon completion of the request, instead of being kept open for possible further requests. This is perfectly normal and should not interfere with sending the request.
EDIT: If you're sending a Connection:Keep-Alive and the server is still responding with Connection:Close, then the server configuration needs to be changed. The default for HTTP/1.1 is persistent connections, so the server must explicitly be configured to send Connection:Close. See Section 8 of RFC2616.