File Coverage

blib/lib/Net/Prober/Probe/HTTP.pm
Criterion Covered Total %
statement 79 94 84.0
branch 23 46 50.0
condition 14 32 43.7
subroutine 10 10 100.0
pod 0 3 0.0
total 126 185 68.1


line stmt bran cond sub pod time code
1             package Net::Prober::Probe::HTTP;
2             $Net::Prober::Probe::HTTP::VERSION = '0.16';
3 2     2   546 use strict;
  2         2  
  2         102  
4 2     2   22 use warnings;
  2         16  
  2         61  
5              
6 2     2   8 use base 'Net::Prober::Probe::TCP';
  2         2  
  2         884  
7              
8 2     2   11 use Carp ();
  2         2  
  2         28  
9 2     2   7 use Digest::MD5 ();
  2         2  
  2         24  
10 2     2   6 use LWPx::ParanoidAgent ();
  2         3  
  2         1356  
11              
12             sub defaults {
13 7     7 0 8 my ($self) = @_;
14 7         20 my $defaults = $self->SUPER::defaults;
15              
16             my %http_defaults = (
17 7         7 %{ $defaults },
  7         48  
18             headers => undef,
19             md5 => undef,
20             method => 'GET',
21             port => 80,
22             scheme => 'http',
23             url => '/',
24             match => undef,
25             body => undef,
26             up_status_re => '^[23]\d\d$',
27             );
28              
29 7         28 return \%http_defaults;
30             }
31              
32             sub agent {
33              
34 3     3 0 18 my $ua = LWPx::ParanoidAgent->new();
35 3   50     647 my $ver = $Net::Prober::VERSION || 'dev';
36 3         15 $ua->agent("Net::Prober/$ver");
37 3         135 $ua->max_redirect(0);
38              
39 3         43 return $ua;
40             }
41              
42             sub _prepare_request {
43 4     4   13 my ($self, $args) = @_;
44              
45 4         51 my ($host, $port, $timeout, $scheme, $url, $method, $body, $headers) =
46             $self->parse_args($args, qw(host port timeout scheme url method body headers));
47              
48 4   50     11 $method ||= "GET";
49              
50 4 50       9 if (defined $scheme) {
51 4 50       10 if ($scheme eq 'http') {
    0          
52 4   100     11 $port ||= 80;
53             }
54             elsif ($scheme eq 'https') {
55 0   0     0 $port ||= 443;
56             }
57             }
58              
59 4 50       8 if (defined $port) {
60 4 50       10 $scheme = $port == 443 ? "https" : "http";
61             }
62              
63 4         19 $url =~ s{^/+}{};
64              
65             # We don't want to add :80 or :443 because some pesky Asian CDN
66             # doesn't like when Host header contains those default ports
67 4         10 my $probe_url = "$scheme://$host/$url";
68 4 100 66     15 if ($port != 80 && $port != 443) {
69 1         3 $probe_url = "$scheme://$host:$port/$url";
70             }
71              
72 4         10 my @req_args = ($method, $probe_url);
73              
74 4 100 66     13 if ($headers && ref $headers eq "ARRAY") {
75 1         14 my $req_headers = HTTP::Headers->new();
76 1         6 $req_headers->header(@{ $headers });
  1         5  
77 1         52 push @req_args, $req_headers;
78             }
79              
80 4 50       7 if ($body) {
81 0         0 push @req_args, $body;
82             }
83              
84 4         34 return HTTP::Request->new(@req_args);
85             }
86              
87             sub probe {
88 3     3 0 4 my ($self, $args) = @_;
89              
90 3         12 my ($expected_md5, $content_match, $up_status_re, $timeout) =
91             $self->parse_args($args, qw(md5 match up_status_re timeout));
92              
93 3         12 $self->time_now();
94              
95 3         8 my $ua = $self->agent();
96              
97 3 50 33     17 if (defined $timeout && $timeout > 0) {
98 3         12 $ua->timeout($timeout);
99             }
100              
101 3         24 my $req = $self->_prepare_request($args);
102              
103             # Fire in the hole!
104 3         366 my $resp = $ua->request($req);
105              
106 3         575171 my $elapsed = $self->time_elapsed();
107 3         11 my $content = $resp->content();
108 3         63 my $status = $resp->code();
109              
110 3         19 my $good = 0;
111 3         3 my $reason;
112              
113 3 50 33     31 if (! $up_status_re || ! defined $status || ! $status) {
    50 33        
114 0   0     0 $good = $resp->is_redirect() || $resp->is_success();
115 0 0       0 if (! $good) {
116 0         0 $reason = "Response HTTP status code wasn't successful (2xx or 3xx)";
117             }
118             }
119             elsif ($up_status_re && defined $status) {
120 3         3 my $match_re;
121             eval {
122 3         38 $match_re = qr{$up_status_re}ms;
123 3 50       38 } or do {
124 0         0 Carp::croak("Invalid regex for HTTP status match '$up_status_re'\n");
125             };
126 3         14 $good = $status =~ $match_re;
127 3 50       9 if (! $good) {
128 0         0 $reason = "Response HTTP status code didn't match the specified regex ('$up_status_re')";
129             }
130             }
131              
132 3 50 33     15 if ($good and defined $expected_md5) {
133 0         0 my $md5 = Digest::MD5::md5_hex($content);
134 0 0       0 if ($md5 ne $expected_md5) {
135 0         0 $good = 0;
136 0         0 $reason = "Response body MD5 sum wasn't the expected ($expected_md5)";
137             }
138             }
139              
140 3 100 66     12 if ($good and defined $content_match) {
141 2         2 my $match_re;
142             eval {
143 2         29 $match_re = qr{$content_match}ms;
144 2 50       3 } or do {
145 0         0 Carp::croak("Invalid regex for http content match '$content_match'\n");
146             };
147 2 50       13 if ($content !~ $match_re) {
148 0         0 $good = 0;
149 0         0 $reason = "Content didn't match the specified '$content_match' regex";
150             }
151             }
152              
153 3         10 my %status = (
154             status => $resp->status_line,
155             content => $content,
156             elapsed => $elapsed,
157             );
158              
159 3 50       150 my $md5 = $content
160             ? Digest::MD5::md5_hex($content)
161             : undef;
162              
163 3 50       10 $status{md5} = $md5 if $md5;
164 3 50       6 $status{reason} = $reason if defined $reason;
165              
166 3 50       5 if ($good) {
167 3         16 return $self->probe_ok(%status);
168             }
169              
170 0           return $self->probe_failed(%status);
171             }
172              
173             1;
174              
175             __END__