I am integrating Perl with Salesforce Reports. I am trying to connect Perl script through standard REST API (/00O93000009NpOy?export=1&enc=UTF-8&xf=csv) of Salesforce Report and getting response code 200. In high level I need to download the Salesforce report in Excel format using a Perl script.
Please look into my code:
#!/usr/bin/perl
use warnings;
use strict;
use WWW::Mechanize;
use WWW::Salesforce;
use REST::Client;
# Authenticate first via SOAP interface to get a session ID:
my $sforce = eval { WWW::Salesforce->login(
'username' => "USER_NAME",
'password' => "PASSWORD" ); };
die "Could not login to SFDC: $#" if $#;
# Get the session ID:
my $hdr = $sforce->get_session_header();
my $sid = ${$hdr->{_value}->[0]}->{_value}->[0];
my $host = 'https://ap1.salesforce.com';
my $client = REST::Client->new(host => $host);
# Get ALL incidents
$client->GET('/00O93000009NpOy?export=1&enc=UTF-8&xf=csv',
{'Authorization' => "OAuth $sid",
'Accept' => 'application/json'});
print 'Response: ' . $client->responseContent() . "\n";
print 'Response status: ' . $client->responseCode() . "\n";
foreach ( $client->responseHeaders() ) {
print 'Header: ' . $_ . '=' . $client->responseHeader($_) . "\n";
}
And when I ran this Perl code through command prompt then I got response like this:
C:\Users\Documents>perl TEST.pl`enter code here`
Response:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.or
g/TR/html4/loose.dtd">
<html>
<head>
<meta HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
<script>
if (this.SfdcApp && this.SfdcApp.projectOneNavigator) { SfdcApp.projectOneNaviga
tor.handleRedirect('https://login.salesforce.com/?ec=302&startURL=%2F00O90000009
NhOy%3Fenc%3DUTF-8%26export%3D1%26xf%3Dcsv'); } else
if (window.location.replace){
window.location.replace('https://login.salesforce.com/?ec=302&startURL=%2F00O900
00009NhOy%3Fenc%3DUTF-8%26export%3D1%26xf%3Dcsv');
} else {;
window.location.href ='https://login.salesforce.com/?ec=302&startURL=%2F00O90000
009NhOy%3Fenc%3DUTF-8%26export%3D1%26xf%3Dcsv';
}
</script>
</head>
</html>
<!-- Body events -->
<script type="text/javascript">function bodyOnLoad(){if(window.PreferenceBits){w
indow.PreferenceBits.prototype.csrfToken="null";};}function bodyOnBeforeUnload()
{}function bodyOnFocus(){}function bodyOnUnload(){}</script>
</body>
</html>
<!--
................................................................................
...................
................................................................................
...................
................................................................................
...................
................................................................................
...................
-->
Response status: 200
Header: Connection=close
Header: Date=Tue, 29 Nov 2016 10:05:43 GMT
Header: Pragma=NO-CACHE
Header: Content-Type=text/html;charset=UTF-8
Header: Client-Date=Tue, 29 Nov 2016 10:05:43 GMT
Header: Client-Peer=182.50.78.41:443
Header: Client-Response-Num=1
Header: Client-SSL-Cert-Issuer=/C=US/O=Symantec Corporation/OU=Symantec Trust Ne
twork/CN=Symantec Class 3 Secure Server CA - G4
Header: Client-SSL-Cert-Subject=/C=US/ST=California/L=San Francisco/O=Salesforce
.com, Inc/OU=Applications/CN=*.salesforce.com
Header: Client-SSL-Cipher=ECDHE-RSA-AES256-GCM-SHA384
Header: Client-SSL-Socket-Class=IO::Socket::SSL
Header: Set-Cookie=BrowserId=UGPsAKnYTgWN3JcU4kcKxg;Path=/;Domain=.salesforce.co
m;Expires=Sat, 28-Jan-2017 10:05:43 GMT
Although response should be in JSON format and not absurd. I tried with workbench and getting the response in JSON format that is good. The response is not proper.
In order to get the json of your report try the following:
$client->GET('https://<server name>.salesforce.com/services/data/v35.0/analytics/reports/<report id>',
{'Authorization' => "OAuth $sid",
'Accept' => 'application/json'});
This worked for me.
Related
I'm trying to call the KeyForge API with a simple Perl program but it doesn't work. I'm using what's in the LWP::UserAgent documentation:
use strict;
use warnings;
use LWP::UserAgent ();
my $ua = LWP::UserAgent->new;
my $response = $ua->get('https://www.keyforgegame.com/api/decks/');
if ($response->is_success) {
print $response->decoded_content;
}
else {
die $response->status_line;
}
The program prints:
500 write failed: at test.pl line 16.
If I use the URL https://www.google.com or http://www.example.com, it works. The HTML is correctly displayed.
If I use this simple PowerShell program, it works too:
$Url = "https://www.keyforgegame.com/api/decks/"
$decks = Invoke-RestMethod ($url)
$decks
It displays:
count data
743719 {#{name=Dr. "The Old" Jeffries; expansion=341; power_level=0; chains=0; wins=0; losses=0; id=ec86db52-e41e-4e...
What am I missing?
PS: I'm using Perl 5.16.3 on Windows 10.
EDIT:
Thank you all for your help. I finally found out what was happening. It turns out I had a very old version of Net::HTTP (from 2013). I upgraded it and now it works out of the box, without configuring agent, cookies or e-mail. The error message I had was actually from the client and not from the server.
$ perl -MLWP::UserAgent -e'
my $ua = LWP::UserAgent->new();
my $response = $ua->get("https://www.keyforgegame.com/api/decks/");
print $response->as_string;
'
HTTP/1.1 403 Forbidden
...
Content-Type: text/html; charset=UTF-8
...
<!DOCTYPE html>
...
<title>Access denied | www.keyforgegame.com used Cloudflare to restrict access</title>
...
<h2 data-translate="what_happened">What happened?</h2>
<p>The owner of this website (www.keyforgegame.com) has banned your access based on your browser's signature (4bfe0c0e2e86ab84-ua22).</p>
...
But,
$ perl -MLWP::UserAgent -e'
use version; our $VERSION = qv("v1.0.0");
my $ua = LWP::UserAgent->new(
agent => "NameOfTool/$VERSION",
from => q{me#example.com},
);
my $response = $ua->get("https://www.keyforgegame.com/api/decks/");
print $response->as_string;
'
HTTP/1.1 200 OK
...
Content-Type: application/json
...
{"count":...
If they want to block you, they can. So it's your best interest to provide a unique application name, a proper version and a valid email address (even if providing junk for the agent and leaving out from field works). This gives them more options to resolve any issues they have with your program.
I have a perl script that posts data to the web service that I wrote in php ...
This is the code:
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
my $server_endpoint = "http://example.com/";
my $req = HTTP::Request->new(POST => $server_endpoint);
$req->header('content-type' => 'application/json');
$req->header('x-auth-token' => 'kfksj48sdfj4jd9d');
# add POST data to HTTP request body
my $post_data = '{ "name": "Dan", "address": "NY" }';
$req->content($post_data);
my $resp = $ua->request($req);
if ($resp->is_success) {
my $message = $resp->decoded_content;
print "Received reply: $message\n";
}
else {
print "HTTP POST error code: ", $resp->code, "\n";
print "HTTP POST error message: ", $resp->message, "\n";
}
When I send the request, I get this response:
HTTP POST error code: 302
HTTP POST error message: Found
Questions:
How can I get rid of this error or is this even an error though it's says Found ?
How can I get the return value of the post?
What is the right way to post data ? (The code above is copied from this site.
My php site gets the post data and echo or just print it as return.)
Thanks in advance .
A 302 error from a server is a redirection instruction to the client. If you are using the default configuration of LWP::UserAgent, it will automatically follow redirects up to a maximum of seven times. If you are not getting a successful response, it suggests that either you've got redirects turned off (which looks unlikely from the code you've posted, unless you've omitted some configuration details for LWP::UserAgent), or that you're getting stuck in a redirect loop.
You can examine the redirection data by checking the HTTP::Response object:
my $resp = $ua->request($req);
# check for success, etc.
...
if ($resp->is_redirect) {
# check the number of redirects that the script has made:
say "n redirects: " . $resp->redirects;
}
With the default LWP::UA settings, seven is the maximum number of redirects you'll get before LWP::UA gives up.
More details on the redirects is available by calling $resp->redirects in array context:
# #redirects is an array of HTTP::Response objects
my #redirects = $resp->redirects;
# print out the 'location' header for each Response object to track the redirection:
say "Location: " . $_->header('location') for #redirects;
# or, for more comprehensive troubleshooting, print out the whole response:
say "Response: " . $_->as_string for #redirects;
Example output for a request to google.com, which redirects once:
# say "n redirects: " . $resp->redirects;
n redirects: 1
# say "Location: " . $_->header('location') for #redirects;
Location: http://www.google.co.uk/?gfe_rd=cr&ei=1bg3VJikJ_HH8gfOk4GwDw
# say "Response: " . $_->as_string for #redirects;
Response: HTTP/1.1 302 Found
Cache-Control: private
Connection: close
Date: Fri, 10 Oct 2014 10:45:41 GMT
Location: http://www.google.co.uk/?gfe_rd=cr&ei=1bg3VJikJ_HH8gfOk4GwDw
Server: GFE/2.0
Content-Length: 261
Content-Type: text/html; charset=UTF-8
Alternate-Protocol: 80:quic,p=0.01
Client-Date: Fri, 10 Oct 2014 10:45:39 GMT
Client-Peer: 74.125.230.102:80
Client-Response-Num: 1
Title: 302 Moved
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
here.
</BODY></HTML>
My guess is that you've got stuck in a redirect loop, and that is why you're not getting the expected response back from your PHP script.
NB: to enable say and other useful features from Perl 5.10 and later, put
use feature ':5.10';
at the top of your script after use strict; use warnings;.
Trying to learn Mojolicious here. For the following request, I get 404 when I try to get to
http://hostname:3000/xml
Here is the simple script:
use Mojolicious::Lite;
use Data::Dumper;
get '/xml' => sub {
my $self = shift;
$self->render(xml => "<employees>
<employee>
<id>1001</id>
<name>John Smith</name>
</employee>
<employee>
<id>1002</id>
<name>Jane Dole</name>
</employee>
</employees>"
);
};
app->start;
This script was adopted from an example for json, which works fine. Not sure why xml doesn't work.
Just need to specify a format
get '/xml' => sub {
my $self = shift;
my $xml = <<'XML';
<employees>
<employee><id>1001</id><name>John Smith</name></employee>
<employee><id>1002</id><name>Jane Dole</name></employee>
</employees>
XML
$self->render(data => $xml, format => 'xml');
};
Response header equals the following:
Connection: keep-alive
Server: Mojolicious (Perl)
Content-Length: 140
Content-Type: application/xml
Date: Wed, 09 Apr 2014 05:36:05 GMT
200 OK
Could also place the data in a template, of course:
get '/xml' => sub {
my $self = shift;
$self->render('employees', format => 'xml');
};
app->start;
__DATA__
## employees.xml.ep
<employees>
<employee><id>1001</id><name>John Smith</name></employee>
<employee><id>1002</id><name>Jane Dole</name></employee>
</employees>
i am trying to learn to work with cookies using Perl. following is my code. but i dont know why the cookie is not getting saved in chrome. everytime i run this script a new cookie is created.
#!"C:\wamp\perl\bin\perl.exe" -w
print "Content-type: text/html\n\n";
use CGI::Carp qw( fatalsToBrowser );
use CGI;
my $q=new CGI;
$value=$q->cookie('lol');
$cookie=$q->cookie
(
-name=>'lol',
-value=>'gh',
-expires=>'+7d'
);
print $q->header(-cookie=>$cookie);
$q->start_html
(
-title=>'CGI.pm Cookies'
);
unless($value) {print "cookie is goint to set";}
else {print "Hi $value";}
$q->end_html;
exit;
Here's the output of your script:
Content-type: text/html
Set-Cookie: lol=gh; path=/; expires=Sat, 04-May-2013 11:16:12 GMT
Date: Sat, 27 Apr 2013 11:16:12 GMT
Content-Type: text/html; charset=ISO-8859-1
cookie is goint to set
You send the Content-Type response header twice: first, on line 2, and again on line 16 when you print $q->header(-cookie => $cookie).
In fact, the double newline on line 2 ends your HTTP headers. So the output of $q->header(-cookie => $cookie) will be treated as document body content, not as HTTP headers.
Quickest solution? Comment out line 2.
Your forgot to send your cookie to the client:
print header(-cookie=>$cookie);
I have a CGI script in Perl that generates HTTP error pages by itself. I am running it under mod_perl via ModPerl::Registry, using the following Apache2 configuration:
Alias /perl "/var/www/perl"
<Directory "/var/www/perl">
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
Options Indexes FollowSymlinks +ExecCGI
AllowOverride None
Order allow,deny
Allow from all
</Directory>
Everything is fine, except a little problem: when HTTP status printed in headers is different than 200 (for instance 404), Apache appends a default HTML error document to my own generated response.
Take for example the following simple CGI script:
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw(:standard :escapeHTML -nosticky);
use CGI::Carp qw(fatalsToBrowser);
use Apache2::Const qw(:http :common);
our $cgi = CGI->new();
print $cgi->header(-type=>'text/html', -charset => 'utf-8',
-status=> '404 Not Found');
our $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
print <<"EOF";
<html>
<head>
<title>die_error_minimal$mod_perl_version
</head>
<body>
404 error
</body>
</html>
EOF
exit;
Running it with Apache configuration mentioned above results in
HTTP/1.1 404 Not Found
Date: Sun, 27 Nov 2011 13:17:59 GMT
Server: Apache/2.0.54 (Fedora)
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
<html>
<head>
<title>die_error_minimal mod_perl/2.0.1
</head>
<body>
404 error
</body>
</html>
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /perl/die_error_minimal.cgi was not found on this server.</p>
<hr>
<address>Apache/2.0.54 (Fedora) Server at localhost Port 80</address>
</body></html>
Note that replacing exit; in the example CGI script above with either return Apache2::Const::OK; or return Apache2::Const::DONE;, as recommended in "How do I suppress the default apache error document in mod_perl?" question on SO doesn't help -- the result stays the same.
What should I fix in my Apache configuration, or what should I add to my CGI script to suppress appending error page by mod_perl / Apache to generated response?
The FAQ works for me , after your CGI is done, after headers are sent, tell apache the status is ok, so it doesn't send ErrorDocument
http://search.cpan.org/~gozer/mod_perl-1.31/faq/mod_perl_faq.pod#So_how_do_I_use_mod_perl_in_conjunction_with_ErrorDocument%3F
#!/usr/bin/perl --
use strict; use warnings;
use CGI;
Main( #ARGV );
exit( 0 );
sub Main {
my404();
#~ my $r = CGI::Simple->new->_mod_perl_request;
my $r = CGI->new->r;
$r->status(200);
return;
}
sub my404 {
my $cgi = CGI->new;
print $cgi->header( -status => 404 );
print "<html><title>print404 says tough noogies</title>
<body><h1>tough noogies</h1></body></html>";
}
__END__
GET http://localhost/perl/print404
User-Agent: lwp-request/6.03 libwww-perl/6.03
404 Not Found
Connection: close
Date: Sun, 27 Nov 2011 20:55:39 GMT
Server: Apache/2.0.54 (Win32) mod_ssl/2.0.54 OpenSSL/0.9.7g PHP/4.3.11 mod_perl/2.0.1 Perl/v5.8.9
Content-Type: text/html; charset=ISO-8859-1
Client-Date: Sun, 27 Nov 2011 20:55:39 GMT
Client-Peer: 127.0.0.1:80
Client-Response-Num: 1
Client-Transfer-Encoding: chunked
Title: print404 says tough noogies
<html><title>print404 says tough noogies</title>
<body><h1>tough noogies</h1></body></html>
My version of the code, but working more stable:
#!/usr/bin/perl
use CGI qw/:standard/ ;
my $Content_of_webpage = 'Oops. 404 error ...' ;
my $status_code = 404 ;
if( $ENV{MOD_PERL} ) { # mod_perl ON
my $r = CGI->new->r ;
$r->status($status_code) ;
$r->content_type("text/html; charset=UTF-8") ;
$r->rflush ; # send the headers out << it is the trick :)
$r->status(200) ;
}
else { # mod_perl OFF
my $cgi = CGI->new ;
print $cgi->header(
-type => "text/html",
-status => $status_code,
-charset => 'UTF-8'
);
}
print $Content_of_webpage ;
I seem to be facing the same problem: I set header status to 400 in case of an error and return JSON array to describe the actual error.
When I do:
print $main::cgi->header(#ret), $html;
With variables:
#ret: {'-type' => 'application/json','-charset' => 'utf-8','-status' => '400 Bad Request'}
$html: '{"errors":{"short_name":["Missing!"]}}'
I will end up with this:
Status Code: 200 OK
Content-Type: application/json; charset=utf-8
Response: {"errors":{"short_name":["Missing!"]}<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.2.3 (CentOS) Server at localhost Port 80</address>
</body></html>
Using the method described by faquer will in deed suppress the error document, but still returns status 200 OK, like Jakub Narębski points out.
BUT! I have found a workaround, where $r is a Apache2::RequestRec, using this:
http://perl.apache.org/docs/2.0/user/coding/coding.html#Forcing_HTTP_Response_Headers_Out
(otherwise you would use $r->send_http_header(), I guess)
print $main::cgi->header(#ret), $html;
my $r = $main::cgi->r;
$r->rflush; # force sending headers (with headers set by CGI)
$r->status(200); # tell Apache that everything was ok, dont send error doc.
HTTP response:
Status Code: 400 Bad Request
Content-Type: application/json; charset=utf-8
Response: {"errors":{"short_name":["Missing!"]}}
Apache config:
PerlModule ModPerl::PerlRun
PerlModule CGI
PerlModule Apache::DBI
PerlRequire /var/www/html/startup.pl
PerlSendHeader On
.htaccess:
<Files *.cgi>
SetHandler perl-script
PerlHandler ModPerl::PerlRun
Options ExecCGI
</Files>