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

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

Related

Translate a curl request in rest::client Perl

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.

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.

perl 500 proxy connect failed: PROXY ERROR HEADER, could be non-SSL URL

have a problem when i try to connect with web service that have certification , username and password as credentials
500 proxy connect failed: PROXY ERROR HEADER, could be non-SSL URL
My code is below:
use LWP::Debug qw(+);
use HTTP::Request::Common;
use Crypt::SSLeay;
use HTTP::Headers;
use HTTP::Request;
use LWP;
$url = "https://ip:port/service";
my $ua = new LWP::UserAgent;
$ENV{HTTPS_DEBUG} = 1;
$ENV{HTTPS_PROXY} = 'https://ip:port';
$ENV{HTTPS_PROXY_USERNAME} = "username";
$ENV{HTTPS_PROXY_PASSWORD} = "password";
$ENV{HTTPS_CA_FILE} = 'cert.crt';
$ENV{HTTPS_CA_DIR} = '/passof/cert/';
$ENV{HTTPS_VERSION} = '3';
my $message = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/e
nvelope/" xmlns:aud="https://ip:port/">
<soapenv:Body>
any /////
</soapenv:Body>
</soapenv:Envelope>';
my $userAgent = LWP::UserAgent->new();
my $request = HTTP::Request->new( GET => 'https://ip:port/service' );
$request->header( SOAPAction => '"https://ip:port/action"' );
$request->content($message);
$request->content_type("text/xml; charset=utf-8");
my $response = $userAgent->request($request);
if ( $response->code == 200 ) {
print $response->as_string;
}

Reading Firefox cookie using LWP

I was trying to eliminate the logging in process to a website by reading the browser cookies (which I created by logging in using Firefox earlier). I exported it from Firefox using this Firefox addon. It gives a 200 OK response but returns the generic homepage instead of my custom 'logged in' home page. How do I make sure that cookie is passed to the server properly ?
#!/usr/bin/perl
use strict ;
use warnings;
use LWP::UserAgent;
use HTTP::Cookies::Netscape;
my #GHeader = (
'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.19) Gecko/2010040200 Ubuntu/8.04 (hardy) Firefox/3.0.19',
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language' => 'en-us,en;q=0.5',
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
'Accept-Encoding' => 'gzip,deflate',
'Keep-Alive' => '300',
'Connection' => 'keep-alive'
);
my $cookie_jar = HTTP::Cookies::Netscape->new(
file => "cookies.txt",
);
my $Browser = LWP::UserAgent->new;
$Browser->cookie_jar( $cookie_jar );
my ($OutLine,$response)=();
my $URL = 'http://www.hanggliding.org/';
printf("Get [%s]\n",$URL);
$response = $Browser->get($URL,#GHeader);
if($response->is_success)
{
if($response->status_line ne "200 OK")
{
printf("%s\n", $response->status_line);
}
else
{
printf("%s\n", $response->status_line);
$OutLine =$response->decoded_content;
open(HTML,">out.html");printf HTML ("%s",$OutLine);close(HTML);
}
}
else
{
printf("Failed to get url [%s]\n", $response->status_line);
}
You can inject a handler to access or modify request/response data during processing.
Quoting LWP::UserAgent's docs:
Handlers are code that injected at various phases during the processing of requests. The following methods are provided to manage the active handlers:
$ua->add_handler( $phase => \&cb, %matchspec )
Add handler to be invoked in the given processing phase. For how to specify %matchspec see "Matching" in HTTP::Config.
...
request_send => sub { my($request, $ua, $h) = #_; ... }
This handler gets a chance of handling requests before they're sent to the protocol handlers. It should return an HTTP::Response object if it wishes to terminate the processing; otherwise it should return nothing.
From there, you can inject a handler which will analyze the request object, but otherwise do nothing:
use LWP::UserAgent;
use Data::Dumper;
sub dump_request {
my ($request, $ua, $h) = #_;
print Dumper($request);
return undef;
}
my $browser = LWP::UserAgent->new;
$browser->add_handler(
request_send => \&dump_request,
m_method => 'GET'
);
$browser->get('http://www.google.com');

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);?