summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorAhmet Oeztuerk <Ahmet.Oeztuerk@consol.de>2025-12-09 00:11:20 +0100
committerAhmet Oeztuerk <Ahmet.Oeztuerk@consol.de>2025-12-09 00:13:15 +0100
commitf7df5579ab1d029eeaad785a6d016884c8f36c7d (patch)
tree7250f60a8a3491bbe626006160993aacb9a3d4bb /plugins
parente0b30cc6e82113491261c872a371a2fa0b4db3ba (diff)
downloadmonitoring-plugins-f7df5579ab1d029eeaad785a6d016884c8f36c7d.tar.gz
check_curl add tests for uri field parsing
plugins/tests/check_curl.t forks and runs a http(s) server that responds to specific uri endpoints. Added another endpoint under /redirect_with_increment with dynamic redirection points. This endpoint will parse different parts of the uri that come after the path: parameters, query and the fragment. If applicable, seperate elements within each field are parsed into key/value pairs. value is incremented in redirected URI. Tests if check_url redirection logic retains different parts of the url when parsing the uri and building the new redirected URL. Current tests show that it ignores the fragment part.
Diffstat (limited to 'plugins')
-rwxr-xr-xplugins/tests/check_curl.t194
1 files changed, 193 insertions, 1 deletions
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t
index 52c5ad1c..bc0101a2 100755
--- a/plugins/tests/check_curl.t
+++ b/plugins/tests/check_curl.t
@@ -20,6 +20,11 @@ use Test::More;
20use NPTest; 20use NPTest;
21use FindBin qw($Bin); 21use FindBin qw($Bin);
22 22
23use URI;
24use URI::QueryParam;
25use HTTP::Daemon;
26use HTTP::Daemon::SSL;
27
23$ENV{'LC_TIME'} = "C"; 28$ENV{'LC_TIME'} = "C";
24 29
25my $common_tests = 75; 30my $common_tests = 75;
@@ -186,6 +191,149 @@ sub run_server {
186 $c->send_response('moved to /redirect2'); 191 $c->send_response('moved to /redirect2');
187 } elsif ($r->url->path eq "/redir_timeout") { 192 } elsif ($r->url->path eq "/redir_timeout") {
188 $c->send_redirect( "/timeout" ); 193 $c->send_redirect( "/timeout" );
194 } elsif ($r->url->path =~ m{^/redirect_with_increment}) {
195 # <scheme>://<username>:<password>@<host>:<port>/<path>;<parameters>?<query>#<fragment>
196 # Find every parameter, query , and fragment keys and increment them
197
198 my $content = "";
199
200 # Use URI to help with query/fragment; parse path params manually.
201 my $original_url = $r->url->as_string;
202 $content .= " original_url: ${original_url}\n";
203 my $uri = URI->new($original_url);
204 $content .= " uri: ${uri}\n";
205
206 my $path = $uri->path // '';
207 my $query = $uri->query // '';
208 my $fragment = $uri->fragment // '';
209
210 $content .= " path: ${path}\n";
211 $content .= " query: ${query}\n";
212 $content .= " fragment: ${fragment}\n";
213
214 # Sets and returns the scheme-specific part of the $uri (everything between the scheme and the fragment) as an escaped string.
215 #my $opaque = $uri->opaque;
216 #$content .= " opaque: ${opaque}\n";
217
218 # group 1 is captured: anything that is not '/' : ([^/]*)
219 # / matches the / directly
220 # group 2 is captured: anything : (.*)
221 #my ($before_slash, $after_slash) = $opaque =~ m{^/([^/]*)/(.*)$};
222 #$before_slash //= '';
223 #$after_slash //= '';
224 #$content .= " before_slash: ${before_slash}\n";
225 #$content .= " after_slash: ${after_slash}\n";
226
227 # split the uri part and parameters. uri package cannot do this
228 # group 1 is captured: anything without a semicolon: ([^;])
229 # group 2 is uncaptured: (?:;(.*))?
230 # (? )? prevents the capture
231 # in between the ';' matches the first ever semicolon
232 # group3 is captured: any character stirng : (.*)
233 my ($before_params, $params) = $uri =~ m{^([^;]*)(?:;(.*))?\?};
234 $before_params //= '';
235 $params //= '';
236 $content .= " before_params: ${before_params}\n";
237 $content .= " params: ${params}\n";
238 my @parameter_pairs;
239 if (defined $params && length $params) {
240 for my $p (split /;/, $params) {
241 my ($key,$value) = split /=/, $p, 2;
242 $value //= '';
243 push @parameter_pairs, [ $key, $value ];
244 $content .= " parameter: ${key} -> ${value}\n";
245 }
246 }
247
248 # query parameters are offered directly from the library
249 my @query_form = $uri->query_form;
250 my @query_parameter_pairs;
251 while (@query_form) {
252 my $key = shift @query_form;
253 my $value = shift @query_form;
254 $value //= ''; # there can be valueless keys
255 push @query_parameter_pairs, [ $key, $value ];
256 $content .= " query: ${key} -> ${value}\n";
257 }
258
259 # fragment: try to split into key=value pairs on ';' or '&' if present
260 my @fragment_pairs;
261 my $fragment_seperator = '';
262 if ($fragment ne '') {
263 $fragment_seperator = ($fragment =~ /&/ ? '&' : ';');
264 for my $f (split /[&;]/, $fragment) {
265 next unless length $f;
266 my ($key,$value) = split /=/, $f, 2;
267 $value //= '';
268 push @fragment_pairs, [ $key, $value ];
269 $content .= " fragment: ${key} -> ${value}\n";
270 }
271 }
272
273 # helper to increment value
274 my $increment = sub {
275 my ($v) = @_;
276 return $v if !defined $v || $v eq '';
277 # numeric integer
278 if ($v =~ /^-?\d+$/) {
279 return $v + 1;
280 }
281 # otherwise -> increment as if its an ascii character
282 # sed replacement syntax, but the $& holds the matched character
283 if (length($v)) {
284 (my $new_v = $v) =~ s/./chr(ord($&) + 1)/ge;
285 return $new_v;
286 }
287 };
288
289 # increment values in pairs
290 for my $pair (@parameter_pairs) {
291 $pair->[1] = $increment->($pair->[1]);
292 $content .= " parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n";
293 }
294 for my $pair (@query_parameter_pairs) {
295 $pair->[1] = $increment->($pair->[1]);
296 $content .= " query parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n";
297 }
298 for my $pair (@fragment_pairs) {
299 $pair->[1] = $increment->($pair->[1]);
300 $content .= " fragment new: " . $pair->[0] . " -> " . $pair->[1] . "\n";
301 }
302
303 # rebuild strings
304 my $new_parameter_str = join(';', map { $_->[0] . '=' . $_->[1] } @parameter_pairs);
305 $content .= " new_parameter_str: ${new_parameter_str}\n";
306
307 # library can rebuild from an array
308 my @new_query_form;
309 for my $p (@query_parameter_pairs) { push @new_query_form, $p->[0], $p->[1] }
310
311 my $new_fragment_str = '';
312 if (@fragment_pairs) {
313 $new_fragment_str = join($fragment_seperator, map { $_->[0] . '=' . $_->[1] } @fragment_pairs);
314 }
315 $content .= " new_fragment_str: ${new_fragment_str}\n";
316
317 # construct new URI using the library
318 my $new_uri = URI->new('');
319 $new_uri->path( $before_params . ($new_parameter_str ? ';' . $new_parameter_str : '') );
320 $new_uri->query_form( \@new_query_form ) if @new_query_form;
321 $new_uri->fragment( $new_fragment_str ) if $new_fragment_str ne '';
322 $content .= " new_uri: ${new_uri}\n";
323
324 # Redirect until fail_count or redirect_count reaches 3
325 if ($new_uri =~ /fail_count=3/){
326 $c->send_error(HTTP::Status->RC_FORBIDDEN, "fail count reached 3, url path:" . $r->url->path );
327 } elsif ($new_uri =~ /redirect_count=3/){
328 $c->send_response(HTTP::Response->new( 200, 'OK', undef , $content ));
329 } elsif ($new_uri =~ /location_redirect_count=3/){
330 $c->send_basic_header(302);
331 $c->send_header("Location", "$new_uri" );
332 $c->send_crlf;
333 $c->send_response("$content \n moved to $new_uri");
334 } else {
335 $c->send_redirect( $new_uri->as_string, 301, $content );
336 }
189 } elsif ($r->url->path eq "/timeout") { 337 } elsif ($r->url->path eq "/timeout") {
190 # Keep $c from being destroyed, but prevent severe leaks 338 # Keep $c from being destroyed, but prevent severe leaks
191 unshift @persist, $c; 339 unshift @persist, $c;
@@ -215,7 +363,7 @@ sub run_server {
215 return($chunk); 363 return($chunk);
216 })); 364 }));
217 } else { 365 } else {
218 $c->send_error(HTTP::Status->RC_FORBIDDEN); 366 $c->send_error(HTTP::Status->RC_FORBIDDEN, "unknown url path:" . $r->url->path );
219 } 367 }
220 $c->close; 368 $c->close;
221 } 369 }
@@ -482,6 +630,50 @@ sub run_common_tests {
482 is( $result->return_code, 0, $cmd); 630 is( $result->return_code, 0, $cmd);
483 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); 631 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output );
484 632
633 # Redirect with increment tests. These are for checking if the url parameters, query parameters and fragment are parsed.
634 # The server at this point has dynamic redirection. It tries to increment values that it sees in these fields, then redirects.
635 # It also appends some debug log and writes it into HTTP content, pass the -vvv parameter to see them.
636
637 $cmd = "$command -p $port_http -u '/redirect_with_increment/path1/path2/path3/path4' --onredirect=follow -vvv";
638 $result = NPTest->testCmd( "$cmd" );
639 is( $result->return_code, 1, $cmd);
640 like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count was not present, got redirected to / : ".$result->output );
641
642 $cmd = "$command -p $port_http -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
643 $result = NPTest->testCmd( "$cmd" );
644 is( $result->return_code, 0, $cmd);
645 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count went up to 3: ".$result->output );
646
647 $cmd = "$command -p $port_http -u '/redirect_with_increment/path1/path2;location_redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
648 $result = NPTest->testCmd( "$cmd" );
649 is( $result->return_code, 0, $cmd);
650 like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output );
651
652 $cmd = "$command -p $port_http -u '/redirect_with_increment/path1/path2;redirect_count=0;fail_count=2' --onredirect=follow -vvv";
653 $result = NPTest->testCmd( "$cmd" );
654 is( $result->return_code, 1, $cmd);
655 like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, early due to fail_count reaching 3: ".$result->output );
656
657 $cmd = "$command -p $port_http -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
658 $result = NPTest->testCmd( "$cmd" );
659 is( $result->return_code, 0, $cmd);
660 like( $result->output, '/.*;p1=3;p2=cd\?*/', "Output correct, parsed and incremented both parameters p1 and p2 : ".$result->output );
661
662 $cmd = "$command -p $port_http -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
663 $result = NPTest->testCmd( "$cmd" );
664 is( $result->return_code, 0, $cmd);
665 like( $result->output, '/.*\?qp1=12&qp2=mn*/', "Output correct, parsed and incremented both query parameters qp1 and qp2 : ".$result->output );
666
667 $cmd = "$command -p $port_http -u '/redirect_with_increment;redirect_count=0;?qp0=0&qp1=1&qp2=2&qp3=3&qp4=4&qp5=5' --onredirect=follow -vvv";
668 $result = NPTest->testCmd( "$cmd" );
669 is( $result->return_code, 0, $cmd);
670 like( $result->output, '/.*\?qp0=2&qp1=3&qp2=4&qp3=5&qp4=6&qp5=7*/', "Output correct, parsed and incremented query parameters qp1,qp2,qp3,qp4,qp5 in order : ".$result->output );
671
672 $cmd = "$command -p $port_http -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv";
673 $result = NPTest->testCmd( "$cmd" );
674 is( $result->return_code, 0, $cmd);
675 like( $result->output, '/.*#f1=vguv*/', "Output correct, parsed and incremented fragment f1 : ".$result->output );
676
485 # These tests may block 677 # These tests may block
486 # stickyport - on full urlS port is set back to 80 otherwise 678 # stickyport - on full urlS port is set back to 80 otherwise
487 $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected"; 679 $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected";