mirror of
https://github.com/centreon/centreon-plugins.git
synced 2025-07-31 01:24:35 +02:00
273 lines
10 KiB
Perl
273 lines
10 KiB
Perl
#!/usr/bin/perl
|
|
use strict;
|
|
use warnings;
|
|
use Test2::V0;
|
|
use Test2::Plugin::NoWarnings echo => 1;
|
|
|
|
use Net::Curl::Easy qw(:constants);
|
|
use Data::Dumper;
|
|
use File::Copy;
|
|
use IO::Socket::INET;
|
|
|
|
# Here, we test that in various cases, requests made using the centreon
|
|
# curl backend and the curl utility send the same headers and data to the
|
|
# HTTP server.
|
|
|
|
use FindBin;
|
|
use lib "$FindBin::RealBin/../../../src";
|
|
|
|
my $port = 7654;
|
|
my @output=();
|
|
my $pid;
|
|
|
|
{
|
|
package MockOptions;
|
|
sub new { bless {}, shift }
|
|
sub add_options { }
|
|
sub add_help { }
|
|
}
|
|
|
|
{
|
|
package MockOutput;
|
|
|
|
sub new { bless {}, shift }
|
|
sub add_option_msg { }
|
|
sub output_add {
|
|
my ($self, %options) = @_;
|
|
|
|
push @output, $options{long_msg};
|
|
|
|
}
|
|
sub is_status { }
|
|
sub display { }
|
|
sub exit { }
|
|
sub option_exit { }
|
|
sub is_debug { 1 }
|
|
sub test_eval { }
|
|
}
|
|
|
|
use centreon::plugins::http;
|
|
use centreon::plugins::misc;
|
|
|
|
my $http;
|
|
|
|
sub curl_client
|
|
{
|
|
my $curlbackend = centreon::plugins::http->new(options=>MockOptions->new(), output=> MockOutput->new(), default_backend => 'curl',);
|
|
$curlbackend->set_options(port => $port);
|
|
return $curlbackend;
|
|
}
|
|
|
|
sub test_backend
|
|
{
|
|
my (%options) = @_;
|
|
|
|
@output=();
|
|
|
|
my $curl = curl_client();
|
|
|
|
if ($options{headers} && ref $options{headers} eq 'ARRAY') {
|
|
$curl->add_header(key => $_->{key}, value => $_->{value}) foreach @{$options{headers}}
|
|
}
|
|
|
|
$curl->request(%options);
|
|
# Retrieve headers and data from centreon curl backend output.
|
|
my @cupscmd = map { /:\s(.+)$/; $1 } grep { defined && /^curl request.*:/ } @output;
|
|
my @sendheader = map { s/^=> Send header: //; s/[\r\n]//g; $_ } grep { defined && /^=> Send header: / } @output;
|
|
my @senddata = map { s/^=> Send data: //; s/[\r\n]//g; $_ } grep { defined && /^=> Send data: / } @output;
|
|
return { command => @cupscmd == 1 ? $cupscmd[0] : '',
|
|
sendheader => @sendheader == 1 ? $sendheader[0] : '',
|
|
senddata => @senddata == 1 ? $senddata[0] : '',
|
|
};
|
|
}
|
|
|
|
sub test_curl
|
|
{
|
|
my ($cmd) = @_;
|
|
|
|
# Retrieve headers and data from curl output.
|
|
# We need to remove the User-Agent header and add the --trace-ascii option,
|
|
# otherwise curl does not display the data part.
|
|
open my $pipe, '-|', 'sh', '-c', $cmd. ' -H User-Agent: --trace-ascii - 2>&1', or die;
|
|
|
|
my $state = 0;
|
|
my (@send_header, @send_data);
|
|
foreach my $read (<$pipe>) {
|
|
if ($read =~ /^=> Send header/) {
|
|
$state = 1;
|
|
next;
|
|
} elsif ($read =~ /^=> Send data/) {
|
|
$state = 2;
|
|
next;
|
|
} elsif ($read =~ /^[=<]/ || $read =~ /^=> R/) {
|
|
$state = 0;
|
|
next;
|
|
}
|
|
next unless $read =~ /^0[^:]+:\s(.*)/;
|
|
if ($state == 1) {
|
|
push @send_header, $1;
|
|
} elsif ($state == 2) {
|
|
push @send_data, $1;
|
|
}
|
|
}
|
|
|
|
close($pipe);
|
|
|
|
return {
|
|
sendheader => (join '', @send_header),
|
|
senddata => (join '', @send_data)
|
|
};
|
|
}
|
|
|
|
sub test_full
|
|
{
|
|
my ($title, $contains, %options) = @_;
|
|
print "test $title\n";
|
|
|
|
my $backend = test_backend(%options);
|
|
|
|
# Backend output shoud contain valid curl command
|
|
if ($contains && ref $contains eq 'ARRAY') {
|
|
my $match = 0;
|
|
foreach (@$contains) {
|
|
$match++ if $backend->{command} =~ /$_/;
|
|
}
|
|
ok($match == @$contains, "Command contains required parameters");
|
|
} else {
|
|
ok($backend->{command} =~ /^curl/, "Command ok");
|
|
}
|
|
|
|
# Backend output should contain a header and/or a data part
|
|
ok($backend->{sendheader} || $backend->{senddata}, "Retrieved header/data with backend");
|
|
my $curl = test_curl($backend->{command});
|
|
|
|
# Curl output should contain a header and/or a data part
|
|
ok($curl->{sendheader} || $curl->{senddata}, "Retrieved header/data with curl");
|
|
|
|
# We update boundary lines, which normally changes between requests
|
|
$backend->{sendheader} =~ s/boundary=----[-a-zA-Z0-9]+/boundary=----XXXXXX/;
|
|
$curl->{sendheader}=~ s/boundary=----[-a-zA-Z0-9]+/boundary=----XXXXXX/;
|
|
|
|
# We update aws signature lines, which normally changes between requests
|
|
$backend->{sendheader} =~ s/(user-agent;)?x-osc-date, Signature=[-a-f0-9]+X-Osc-Date: [\dTZ]+/x-osc-date, Signature=AAAAAAX-Osc-Date: 20250620T140600Z/;
|
|
$curl->{sendheader} =~ s/(user-agent;)?x-osc-date, Signature=[-a-f0-9]+X-Osc-Date: [\dTZ]+/x-osc-date, Signature=AAAAAAX-Osc-Date: 20250620T140600Z/;
|
|
|
|
$backend->{senddata} =~ s/-------[-a-zA-Z0-9]+/--------XXXXXX/g;
|
|
$curl->{senddata}=~ s/-------[-a-zA-Z0-9]+/--------XXXXXX/g;
|
|
|
|
# Backend and curl outputs should be the same
|
|
ok($backend->{sendheader} eq $curl->{sendheader}, "Headers part match");
|
|
ok($backend->{senddata} eq $curl->{senddata}, "Data part match\n");
|
|
}
|
|
|
|
sub setup_env
|
|
{
|
|
$pid = fork();
|
|
|
|
# Simulate an HTTP server otherwise curl will not generate any output
|
|
if ($pid == 0) {
|
|
my $client;
|
|
$SIG{'TERM'} = sub {
|
|
close($client);
|
|
exit(0);
|
|
};
|
|
|
|
my $server = IO::Socket::INET->new( LocalHost => '127.0.0.1',
|
|
LocalPort => $port, Proto => 'TCP',
|
|
Reuse => 1, Listen => 50 );
|
|
|
|
die unless $server;
|
|
while (1) {
|
|
$client = $server->accept();
|
|
next unless $client;
|
|
<$client>;
|
|
sleep 1;
|
|
close $client if $client;
|
|
}
|
|
}
|
|
}
|
|
|
|
setup_env();
|
|
|
|
my $tmpfile = "/tmp/curllogger.cookies";
|
|
copy("$FindBin::RealBin/curllogger.cookies", "$tmpfile");
|
|
|
|
# All requests to be tested
|
|
foreach ( { title => "GET with timeout",
|
|
options => { full_url => "http://localhost:$port/fake", timeout => 10 } },
|
|
{ title => "GET with headers",
|
|
options => { full_url => "http://localhost:$port/fake",
|
|
headers => [ { key => "header1", value => "valeur 1" }, { key => "header2", value => "valeur 2" } ] } },
|
|
{ title => "POST with post_params",
|
|
options => { full_url => "http://localhost:$port/fake", method => "POST",
|
|
post_params => { "key 1" => "value 1", "key 2" => "value 2" } } },
|
|
{ title => "PATCH with timeout",
|
|
options => { method => 'PATCH', full_url => "http://localhost:$port/fake", timeout => 10 } },
|
|
{ title => "DELETE with timeout",
|
|
options => { method => 'DELETE', full_url => "http://localhost:$port/fake", timeout => 10 } },
|
|
{ title => "GET with get_params",
|
|
options => { full_url => "http://localhost:$port/fake", get_params => [ 'para1', 'valeur1', 'para2', 'valeur2' ] } },
|
|
{ title => "GET with no_follow",
|
|
options => { full_url => "http://localhost:$port/fake", no_follow => 1 } },
|
|
{ title => "GET with cookies_file",
|
|
options => { full_url => "http://localhost:$port/fake", cookies_file => $tmpfile },
|
|
contains => [ '--cookie-jar' ] },
|
|
{ title => "POST with query_form_post",
|
|
options => { full_url => "http://localhost:$port/fake", query_form_post => "une data",
|
|
headers => [ { key => "header1", value => "valeur 1" }, { key => "content-type", value => "text/html" } ] } },
|
|
{ title => "GET with cert",
|
|
options => { full_url => "http://localhost:$port/fake", insecure => 1, cacert_file => '/tmp/ca-fake.crt',
|
|
cert_file => '/tmp/cert-fake.crt', key_file => '/tmp/key-fake.pem', cert_pwd => 't@t@' },
|
|
contains => [ '--insecure', '--cert', '--cacert' , '--key', '--pass', ] },
|
|
{ title => "GET with pkcs12",
|
|
options => { full_url => "http://localhost:$port/fake", cert_pkcs12 => 'P12' },
|
|
contains => [ '--cert-type' ] },
|
|
{ title => "GET with proxyurl",
|
|
options => { full_url => "http://localhost:$port/fake", proxyurl => "http://localhost:$port" } },
|
|
{ title => "GET with authent basic",
|
|
options => { full_url => "http://localhost:$port/fake", credentials => 1, basic => 1, username => 'User',
|
|
password => 'Pa$$w@rd' },
|
|
contains => [ '--basic' ] },
|
|
{ title => "GET with authent ntlmv2",
|
|
options => { full_url => "http://localhost:$port/fake", credentials => 1, ntlmv2 => 1, username => 'User',
|
|
password => 'Pa$$w@rd' },
|
|
contains => [ '--ntlm' ] },
|
|
{ title => "GET with authent digest",
|
|
options => { full_url => "http://localhost:$port/fake", credentials => 1, digest => 1, username => 'User',
|
|
password => 'Pa$$w@rd' },
|
|
contains => [ '--digest' ] },
|
|
{ title => "GET with authent anyauth",
|
|
options => { full_url => "http://localhost:$port/fake", credentials => 1, username => 'User',
|
|
password => 'Pa$$w@rd' },
|
|
contains => [ '--anyauth' ] },
|
|
{ title => "POST with form",
|
|
options => { full_url => "http://localhost:$port/fake", method => "POST",
|
|
form => [ { copyname => 'part 1', copycontents => 'content 1' }, { copyname => 'part 2',
|
|
copycontents => 'content 2' }, ] } },
|
|
) {
|
|
test_full($_->{title}, $_->{contains} // '', %{$_->{options}});
|
|
}
|
|
|
|
# This test is skipped if the platform does not support CURLOPT_AWS_SIGV4 ( libcurl >= 7.75.0 required ).
|
|
SKIP: {
|
|
my $test = { title => "GET with curl_opt",
|
|
options => { full_url => "http://fake.execute-api.eu-west-1.amazonaws.com:$port/fake", credentials => 1,
|
|
username => 'User', http_peer_addr => "127.0.0.1",
|
|
password => 'Pa$$w@rd' , curl_opt => [ "CURLOPT_AWS_SIGV4 => osc" ] } };
|
|
|
|
eval "CURLOPT_AWS_SIGV4";
|
|
if ($@) {
|
|
print "test ".$test->{title}."\n";
|
|
skip "CURLOPT_AWS_SIGV4 is unsupported on this platform", 5;
|
|
}
|
|
|
|
test_full($test->{title}, $test->{contains} // '', %{$test->{options}});
|
|
};
|
|
|
|
unlink $tmpfile;
|
|
|
|
kill 'TERM', $pid;
|
|
waitpid ($pid, 0);
|
|
|
|
done_testing();
|