How to suspend https warning message in perl - perl

I use https connection without any certificate using LWP.
How to suspend this annoying warning message so I can get only the number at the last line:
*******************************************************************
Using the default of SSL_verify_mode of SSL_VERIFY_NONE for client
is deprecated! Please set SSL_verify_mode to SSL_VERIFY_PEER
together with SSL_ca_file|SSL_ca_path for verification.
If you really don't want to verify the certificate and keep the
connection open to Man-In-The-Middle attacks please set
SSL_verify_mode explicitly to SSL_VERIFY_NONE in your application.
*******************************************************************
at C:/perl/lib/LWP/Protocol/http.pm line 31.
0
?
That message appears then I use https connection winthout certificate!
Here is the source code:
#!/usr/bin/perl
use LWP::UserAgent;
use JSON;
$ENV{PERL_LWP_SSL_VERIFY_HOSTNAME} = 0;
# my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
my $ua = LWP::UserAgent->new();
$ua->timeout(15);
my $response = $ua->get("https://useful_link");
if ($response->is_success) {
my $json_text = decode_json $response->content;
my $max_val = -1;
for(my $i = 0; $json_text->{'monitors'}[$i]; $i++) {
# Поиск по значениям хэша с ключом 'monitors'
for(my $j = 0; ; $j++) {
# Поиск по значениям хэша 'properties'
my $json_var = $json_text->{'monitors'}[$i]{'properties'}[$j]{'key'};
if($json_var eq "MemoryPercentUsage") {
my $json_val = $json_text->{'monitors'}[$i]{'properties'}[$j]{'value'};
if($json_val > $max_val) { $max_val = $json_val; }
last;
}
elsif($json_var) { next; }
else { last; }
}
}
print $max_val >= 0 ? $max_val : "Error! Cannot evaluate parameters value!";
}
else { die sprintf "Error! HTTP code: %d - Message:'%s'", $response->code, $response->message; }

It's OK.
I've got my own clumsy solution:
open my $saveout, ">&STDERR";
open STDERR, '>', File::Spec->devnull(); # Связывание STDERR с devnull
# Необходимые операции
my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
$ua->timeout(15);
my $response = $ua->get("https://useful_link");
# Конец
open STDERR, ">&", $saveout; # Восстановление STDERR
Just simply binded STDERR with devnull :)

Related

WebSocket server from scratch showing opcode -1

I am trying to create a simple WebSocket server in perl from scratch, when I tried it in Google Chrome it gave me opcode -1, How can I fix it?
websocket.pl
#!/usr/bin/perl -w
use strict;
use IO::Socket::INET;
use Digest::SHA1 "sha1_base64";
$| = 1;
my $magic_string = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
# Create a server
my $socket = IO::Socket::INET->new( LocalHost => 'localhost',
LocalPort => 7777,
Proto => 'tcp',
Listen => 5,
Reuse => 1
) || die "$!";
print "Server is running on port 7777\n";
while (1) {
my $client = $socket->accept();
my $key = "";
# Get the Request
my $data = "";
while (my $line = <$client>) {
$data .= $line;
}
# Get the Sec-WebSocket-Key value
foreach my $line ( split /\n/ => $data ) {
if ( $line =~ /^Sec-WebSocket-Key: (\S+)/ ) {
$key = $1;
}
}
print "Sec-WebSocket-Key: $key\n";
# Create the Sec-WebSocket-Accept header value
my $accept = sha1_base64($key);
$accept .= "="x(4-(length($accept)%4));
print "Sec-WebSocket-Accept: $accept\n";
# Response
print $client "HTTP/1.1 101 Switching Protocols\r\n";
print $client "Upgrade: websocket\r\n";
print $client "Connection: Upgrade\r\n";
print $client "Sec-WebSocket-Accept: $accept\r\n\r\n";
shutdown($client, 1);
}
$socket->close();
I am pretty sure that the key returned to website is correct, so where is the problem? What went wrong?
ws.js
var ws = new WebSocket("ws://localhost:7777/");
ws.onopen = function() {
alert("connected!");
ws.send( 'Hello server' );
};
ws.onclose = function() {
alert( 'Connection is closed... ');
};
Web Browser network traffic
Edit
Stefan Becker: Yea, I know, but in this case I was sure that the request is under 1024 bytes, I've fixed it, thanks.
(Opcode -1) is a generic error. In your case it is a bad Sec-WebSocket-Accept header. You forgot to use $magic_string:
my $accept = sha1_base64($key.$magic_string);
Also while (my $line = <$client>) { will probably run forever. You need to check for an empty line.

Azure REST API "Put Block" error 596?

I can't see any information in the Azure Blob Service Error Code list https://msdn.microsoft.com/en-us/library/dd179439.aspx that relates to error 596.
I am trying to upload some blocks to the Azure service and am getting a response back from the API with code 596 and description 'Broken pipe'.
Has anyone encountered this before ?
(N.B. Yes, I know the code below is not complete yet in that the code as-is does not upload the final chunk)
#!/usr/bin/perl
use 5.014;
use strict;
use warnings;
use autodie;
use Data::Dumper;
use Digest::MD5 qw(md5_base64);
use Crypt::PRNG::Fortuna qw(random_bytes_b64u random_bytes);
use Digest::SHA qw(hmac_sha256_base64);
use Getopt::Long;
use Sys::Syslog qw( :DEFAULT setlogsock);
use File::stat;
use AnyEvent;
use AnyEvent::HTTP;
use Time::Piece;
use Encode qw(decode encode);
use MIME::Base64 qw(encode_base64 decode_base64 encode_base64url);
use FileHandle;
use Fcntl ':flock', 'SEEK_SET';
delete #ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
use sigtrap 'handler' => \&term_handler, 'normal-signals';
####### PARAMS
my $script="upload.pl";
my $maxSingleUpload=1048576; # Maximum size of a single attempt upload (in bytes);
my $multiChunkSize=4194304; # Maximum size of a single block (in bytes)
my $multiLimit=6; # Maximum number of parallel HTTP requests
####### AZURE
my $azureKey="<REMOVED>";
my $azureKeyBin=decode_base64($azureKey);
####### ARGS
my ($vault,$container,$localfile,$remotefile);
my $debug=0;
GetOptions(
"vault|v=s" => \$vault,
"container|c=s" => \$container,
"localfile|l=s" => \$localfile,
"remotefile|r=s" => \$remotefile,
"debug|d+" => \$debug
);
if (!defined $vault || !defined $container || !defined $localfile || !defined $remotefile) {
say "USAGE: -v <vault> -c <container> -l <localfile> -r <remotefile> [-d (debug)]";
exit 1;
}
if (!-e $localfile) {
say "Local file does not exist !";
exit 1;
}
####### Vars
my ($wholeChunks,$chunkRemainder,$runID,$condvar,#offsets,#blocklist);
my $activeCount=0;
my $putBlockURL="https://${vault}.blob.core.windows.net/${container}/${remotefile}?comp=block&blockid=";
####### FUNCTIONS
# Quotient remainder calculator
sub qrem {
use integer;
my( $dividend, $divisor ) = #_;
my $quotient = $dividend / $divisor;
my $remainder = $dividend % $divisor;
my #result = ( $quotient, $remainder );
return #result;
}
# Do pad
sub doPad {
my ($raw) = #_;
while (length($raw) % 4) {
$raw .= '=';
}
return $raw;
}
# Random
sub getRandom {
my ($len) = #_;
#return doPad(random_bytes_b64u($len));
return doPad(encode_base64(random_bytes($len)));
}
# Term handler
sub term_handler {
doLog("err","term_handler: Program terminated early due to user input");
exit 2;
}
# Log sub
sub doLog {
my ($priority,$msg) = #_;
return 0 unless ($priority =~ /info|err|debug/);
setlogsock('unix');
openlog($script, 'pid,cons', 'user');
syslog($priority, $msg);
closelog();
return 1;
}
# Get file size
sub fileSz {
my($file) = #_;
my $stat = stat($file);
return $stat->size;
}
# Get data
sub readData {
my ($file,$length,$offset)=#_;
my $fh = FileHandle->new;
my ($data);
if ($debug) { say "Reading ${file} offset ${offset} for length ${length}";}
#open ($fh,"<",$file);
$fh->open("< $file");
binmode($fh);
seek($fh,$offset,SEEK_SET);
read($fh,$data,$length);
if ($debug) { say "readData read ".byteSize($data);}
#close($fh);
$fh->close;
return $data;
}
# Calc MD5
sub calcMD5 {
my ($data)=#_;
my $hash = md5_base64($data);
return doPad($hash);
}
# Populate offsets
sub populateOffsets {
my ($count,$offsetSize)=#_;
if (!defined $count || !defined $offsetSize) {exit 1;}
my $offset=0;
my #offsets;
for my $i (1..$count) {
push #offsets,$offset;
$offset = $offset + $offsetSize;
}
return #offsets;
}
# Calc auth string
sub azureAuth {
my($t,$signstring)=#_;
if (!defined $signstring) { exit 1;}
if ($debug) {say "String to sign:${signstring}";}
my $auth;
$auth=doPad(hmac_sha256_base64($signstring,$azureKeyBin));
if ($debug) { say "Sig:${auth}";}
return $auth;
}
# Byte size
sub byteSize {
use bytes;
my ($inval)=#_;
return length($inval);
}
# Process
sub doProcess {
return if $activeCount >= $multiLimit;
my $offset = shift #offsets;
return if !defined $offset;
$activeCount++;
if ($debug) { say "Active:${activeCount}, Offset:${offset}";}
$condvar->begin;
my $t = localtime;
my $tNow = $t->strftime();
my $blockid = getRandom(8);
my $subRunID=getRandom(5);
my $contentLength=$multiChunkSize-1;
my $content = readData($localfile,$contentLength,$offset);
my $hash = calcMD5($content);
if ($debug) { say "Block ID:${blockid}, Hash: ${hash}";}
my $url = $putBlockURL.$blockid;
my $canocResource="/${vault}/${container}/${remotefile}\nblockid:${blockid}\ncomp:block";
my $hdrs="x-ms-client-request-id:${runID}\nx-ms-date:${tNow}\nx-ms-version:2009-09-19";
my $byteLength=byteSize(${content});
my $canocHeaders=encode('UTF-8',"PUT\n\n\n${byteLength}\n${hash}\n\n\n\n\n\n\n\n${hdrs}\n${canocResource}",Encode::FB_CROAK);
my $authData=azureAuth($t,$canocHeaders);
if ($debug) {say "Length:${byteLength}";say "Sig: ${authData}"; say "URL:${url}";}
my $azureArr = {
"Authorization"=>"SharedKey ${vault}:${authData}",
"Content-Length"=>${byteLength},
"Content-MD5"=>${hash},
"x-ms-version"=>"2009-09-19",
"x-ms-date"=>${tNow},
"x-ms-client-request-id"=>"${runID}"
};
####### ERROR OCCURS HERE ....
http_request "PUT" => $url,
persistent=>0,
headers=>$azureArr,
body=>$content,
sub {
my ($body, $hdr) = #_;
say Dumper($hdr);
#say "received, Size: ", length $body;
#say $body;
$activeCount--;
$condvar->end;
doProcess();
};
return 1;
}
####### MAIN
$runID=getRandom(5);
doLog("info","${runID} Starting upload for ${localfile} (${remotefile})");
if (fileSz($localfile)<$maxSingleUpload) {
if ($debug) {say "Using single upload method";}
} else {
if ($debug) {say "Using multi-upload method";}
# Calculate chunk quantity
my #chunks = qrem(fileSz($localfile),$multiChunkSize);
$wholeChunks=$chunks[0];
$chunkRemainder=$chunks[1];
if ($debug) {say "Whole chunks (${multiChunkSize}):${wholeChunks}, Remainder:${chunkRemainder}";}
# Init
#offsets=populateOffsets(${wholeChunks},${multiChunkSize});
say Dumper(#offsets);
$condvar = AnyEvent->condvar;
# DO IT
for (1..$multiLimit) {
doProcess();
}
$condvar->recv;
}
doLog("info","${runID} Upload complete");
exit 0;
Error 596 is a client-side error returned by AnyEvent::HTTP. You need to investigate locally to see why you are hitting this error.
See this page for more info:
https://metacpan.org/pod/AnyEvent::HTTP
596 - errors during TLS negotiation, request sending and header processing.

Perl HTTP server

I'm new at Perl, and I have a question regarding HTTP servers and client APIs.
I want to write an HTTP server which accepts requests from HTTP clients. The problem is that I do not know how to do it because I'm a Java developer, and it's a little bit difficult for me. Please can you give me some tutorials and example for HTTP::Daemon module for Perl?
I spent a lot of time trying to make a "simple" usable web server by many users simultaneously. The documentation for HTTP::Daemon and other online resources isn't helping me.
Here is a working (Ubuntu 12.10 with default Perl package v5.14.2) example preforked web server with different content type pages and error pages:
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw/ :standard /;
use Data::Dumper;
use HTTP::Daemon;
use HTTP::Response;
use HTTP::Status;
use POSIX qw/ WNOHANG /;
use constant HOSTNAME => qx{hostname};
my %O = (
'listen-host' => '127.0.0.1',
'listen-port' => 8080,
'listen-clients' => 30,
'listen-max-req-per-child' => 100,
);
my $d = HTTP::Daemon->new(
LocalAddr => $O{'listen-host'},
LocalPort => $O{'listen-port'},
Reuse => 1,
) or die "Can't start http listener at $O{'listen-host'}:$O{'listen-port'}";
print "Started HTTP listener at " . $d->url . "\n";
my %chld;
if ($O{'listen-clients'}) {
$SIG{CHLD} = sub {
# checkout finished children
while ((my $kid = waitpid(-1, WNOHANG)) > 0) {
delete $chld{$kid};
}
};
}
while (1) {
if ($O{'listen-clients'}) {
# prefork all at once
for (scalar(keys %chld) .. $O{'listen-clients'} - 1 ) {
my $pid = fork;
if (!defined $pid) { # error
die "Can't fork for http child $_: $!";
}
if ($pid) { # parent
$chld{$pid} = 1;
}
else { # child
$_ = 'DEFAULT' for #SIG{qw/ INT TERM CHLD /};
http_child($d);
exit;
}
}
sleep 1;
}
else {
http_child($d);
}
}
sub http_child {
my $d = shift;
my $i;
my $css = <<CSS;
form { display: inline; }
CSS
while (++$i < $O{'listen-max-req-per-child'}) {
my $c = $d->accept or last;
my $r = $c->get_request(1) or last;
$c->autoflush(1);
print sprintf("[%s] %s %s\n", $c->peerhost, $r->method, $r->uri->as_string);
my %FORM = $r->uri->query_form();
if ($r->uri->path eq '/') {
_http_response($c, { content_type => 'text/html' },
start_html(
-title => HOSTNAME,
-encoding => 'utf-8',
-style => { -code => $css },
),
p('Here are all input parameters:'),
pre(Data::Dumper->Dump([\%FORM],['FORM'])),
(map { p(a({ href => $_->[0] }, $_->[1])) }
['/', 'Home'],
['/ping', 'Ping the simple text/plain content'],
['/error', 'Sample error page'],
['/other', 'Sample not found page'],
),
end_html(),
)
}
elsif ($r->uri->path eq '/ping') {
_http_response($c, { content_type => 'text/plain' }, 1);
}
elsif ($r->uri->path eq '/error') {
my $error = 'AAAAAAAAA! My server error!';
_http_error($c, RC_INTERNAL_SERVER_ERROR, $error);
die $error;
}
else {
_http_error($c, RC_NOT_FOUND);
}
$c->close();
undef $c;
}
}
sub _http_error {
my ($c, $code, $msg) = #_;
$c->send_error($code, $msg);
}
sub _http_response {
my $c = shift;
my $options = shift;
$c->send_response(
HTTP::Response->new(
RC_OK,
undef,
[
'Content-Type' => $options->{content_type},
'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
'Pragma' => 'no-cache',
'Expires' => 'Thu, 01 Dec 1994 16:00:00 GMT',
],
join("\n", #_),
)
);
}
There is a very fine example in the documentation for HTTP::Daemon.
A client example compliant with the synopsys from HTTP::Daemon :
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;
my $response = $ua->get('http://localhost:52798/xyzzy');
if ($response->is_success) {
print $response->decoded_content; # or whatever
}
else {
die $response->status_line;
}
You just need to adapt the port and maybe the host.

HTTP::Daemon crashing when I stop the loop

I'm working on an adhoc GUI so that I can easily view a bunch of data from the VMWare Perl SDK without having to setup a bunch of scripts under IIS. The basic idea is to start up the script, and have it fork two processes. One is the HTTP::Daemon web server, and then two seconds later its the Win32::IEAutomation run browser. It's not pretty, I admit, but I'm slightly comfortable with the VMPerlSDK than the VMCOMSDK. Plus I'm kind of curious to see if I can get this to work.
As far as I can tell, the program starts okay. The fork works. The little URI parser works. The only problem is whenever I try to call /quit to shutdown the server, the script explodes.
Any suggestions (aside from how this should be done with IIS and AutoIT, I know, I know) would be appreciated. Thanks!
#!/usr/bin/perl -w
use Data::Dumper;
use HTTP::Daemon;
use HTTP::Status;
use HTTP::Response;
use strict;
use warnings;
use Win32::IEAutomation;
sub MainPage {
return<<eol
<html>
<head><title>Test</title></head>
<body>
<h3>Home</h3>
<p>Quit</p>
</body>
</html>
eol
}
# Parses out web variables
sub WebParse {
my ($wstring) = #_;
my %webs = ();
# gets key/value data
my #pairs = split(/&/, $wstring);
# puts the key name into an array
foreach my $pair (#pairs) {
my ($kname, $kval) = split (/=/, $pair);
$kval =~ tr/+/ /;
$kval =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$webs{$kname} = $kval;
}
return(%webs);
}
sub StartServer {
my $PORT = shift;
my $ALLOWED = shift;
my $d = HTTP::Daemon->new(ReuseAddr => 1, LocalAddr => $ALLOWED, LocalPort => $PORT) || die;
# Prints a startup message
print "Please contact me at: <URL:", $d->url, ">\n";
my $xt = 0;
BLOOP: while (my $c = $d->accept) {
while (my $r = $c->get_request) {
# Handles requests with the GET or POST methods
if ($r->method =~ m/GET/i || $r->method =~ m/POST/i) {
my $uri = $r->uri; my %ENV = ();
$ENV{REQUEST_METHOD} = $r->method;
$ENV{CONTENT_TYPE} = join('; ', $r->content_type);
$ENV{CONTENT_LENGTH} = $r->content_length || '';
$ENV{SCRIPT_NAME} = $uri->path || 1;
$ENV{REMOTE_ADDR} = $c->peerhost();
if ($r->method =~ m/GET/i) {
$ENV{QUERY_STRING} = $uri->query || '';
}
elsif ($r->method =~ m/POST/i) {
$ENV{QUERY_STRING} = $r->{"_content"} || '';
}
my %q = &WebParse($ENV{QUERY_STRING});
my $res = HTTP::Response->new("200");
if ($uri =~ m/quit/i) {
$res->content("Goodbye");
$xt=1;
}
else {
$res->content(MainPage());
}
$c->send_response($res);
}
# Otherwise
else {
$c->send_error("This server only accepts GET or POST methods");
}
if ($xt == 1) {
sleep(2);
$c->force_last_request();
last BLOOP;
}
$c->close;
}
undef($c);
}
$d->close;
undef($d);
exit;
}
sub StartInterface {
my $PORT = shift;
my $ALLOWED = shift;
my $ie = Win32::IEAutomation->new(visible => 1, maximize => 1);
$ie->gotoURL("http://".$ALLOWED.":".$PORT."/");
exit;
}
# Return Status
my $STATUS = 1;
# Server port number
my $PORT = 9005;
# The server that's allowed to talk to this one
my $ALLOWED = "127.0.0.1";
my $pid = fork();
if ($pid == 0) {
StartServer($PORT, $ALLOWED);
} else {
sleep(2);
StartInterface($PORT, $ALLOWED);
}
exit;
before you close your daemon $d, shutdown the socket and tell the parent pid to quit:
$d->shutdown(2);
$d->close;
undef $d;
kill(2,getppid());
exit;

TCP Server multiple receive and respond

Im trying to emulate a TCP Server on the same PC where the app is running.
I dont know if it can be done in Perl because im not very experienced.
With the code bellow the first reply is working but i dont know how to implement the second.
#!/usr/bin/perl -w
use IO::Socket::INET;
use strict;
my $socket = IO::Socket::INET->new('LocalPort' => '3000',
'Proto' => 'tcp',
'Listen' => SOMAXCONN)
or die "Can't create socket ($!)\n";
print "Server listening\n";
while (my $client = $socket->accept) {
my $name = gethostbyaddr($client->peeraddr, AF_INET);
my $port = $client->peerport;
while (<$client>) {
print "$_";
print $client "RESPONSE1";
}
close $client
or die "Can't close ($!)\n";
}
die "Can't accept socket ($!)\n";
EDIT: Thank you guys for the imput, i ended up with php done it and its working, yay!
Use Net::Server for the connection, and a variable in the sub to keep the current state ($state in this code); something like this:
package MyServer;
use base qw/Net::Server/;
use strict;
use warnings;
sub process_request {
my $self = shift;
my $state = 0;
while (<STDIN>) {
s/\r?\n$//; # like chomp but for crlf too
if ($state == 0 and $_ eq 'data1') {
print "> okay1\n";
$state++;
} elsif ($state == 1 and $_ eq 'data2') {
print "> okay2\n";
$state++;
} else {
last if $state == 2;
$state = 0;
}
}
}
my $port = shift || 3000;
MyServer->run( port => $port );
The example in the Net::Server POD suggests using an alarm to timeout connections, which might be appropriate here. The code above does the following:
$ nc localhost 3000
data1
> okay1
data2
> okay2
data3
$
And if you need to move to a forking / preforking / non-blocking / co-routine driven system, there's a Net::Server personality for that.
"ready to go" code:
package MyServer;
use base qw/Net::Server/;
use strict;
use warnings;
sub process_request {
my $self = shift;
my $state = 0;
$| = 1;
binmode *STDIN;
while (read(*STDIN, local $_, 3 )) {
if ($state == 0 and $_ eq "\x{de}\x{c0}\x{ad}") {
print "\x{c4}\x{1a}\x{20}\x{de}";
$state++;
} elsif ($state == 1 and $_ eq "\x{18}\x{c0}\x{0a}") {
print "\x{11}\x{01}\x{73}\x{93}";
$state++;
last;
}
}
}
my $port = shift || 3000;
MyServer->run( port => $port );
It seems to me process_request sub doesn't work correctly when a low port is set (in my situation, port 23). In particular only with low port, while parsing data input, the first request contains additional chars (but it's all ok with subsequent requests).
Have you a tips? Thank you