File Coverage

blib/lib/EasyDNS/DDNS/HTTP.pm
Criterion Covered Total %
statement 43 47 91.4
branch 6 8 75.0
condition 11 23 47.8
subroutine 11 12 91.6
pod 0 4 0.0
total 71 94 75.5


line stmt bran cond sub pod time code
1             package EasyDNS::DDNS::HTTP;
2              
3 3     3   172298 use strict;
  3         7  
  3         116  
4 3     3   16 use warnings;
  3         12  
  3         142  
5              
6 3     3   2273 use HTTP::Tiny;
  3         153589  
  3         152  
7 3     3   1697 use MIME::Base64 qw(encode_base64);
  3         2860  
  3         291  
8              
9 3     3   895 use Retry::Policy;
  3         8263  
  3         116  
10              
11 3     3   386 use EasyDNS::DDNS::Util ();
  3         7  
  3         1520  
12              
13             sub new {
14 2     2 0 290660 my ($class, %args) = @_;
15              
16 2   50     19 my $timeout = $args{timeout} // 10;
17              
18             my $http = $args{http} || HTTP::Tiny->new(
19             timeout => $timeout,
20             verify_SSL => 1,
21 2   33     14 agent => $args{agent} // 'sdseasydyn/0.001',
22             );
23              
24             my $retry = $args{retry} || Retry::Policy->new(
25             max_attempts => $args{max_attempts} // 5,
26             base_delay_ms => $args{base_delay_ms} // 200,
27             max_delay_ms => $args{max_delay_ms} // 10_000,
28 2   33     9 jitter => $args{jitter} // 'full',
29             );
30              
31             my $self = bless {
32             timeout => $timeout,
33             http => $http,
34             retry => $retry,
35 2   50     19 verbose => $args{verbose} // 0,
36             }, $class;
37              
38 2         9 return $self;
39             }
40              
41             sub basicAuthHeader {
42 0     0 0 0 my ($self, $user, $token) = @_;
43 0         0 my $raw = $user . ":" . $token;
44 0         0 return "Basic " . encode_base64($raw, "");
45             }
46              
47             sub get {
48 2     2 0 15 my ($self, $url, %opt) = @_;
49 2         11 return $self->request('GET', $url, %opt);
50             }
51              
52             sub request {
53 2     2 0 8 my ($self, $method, $url, %opt) = @_;
54              
55 2   50     13 my $headers = $opt{headers} || {};
56 2         4 my $content = $opt{content};
57 2   33     17 my $desc = $opt{desc} || EasyDNS::DDNS::Util::redact_basic_auth_in_url($url);
58              
59             my $res = $self->{retry}->run(sub {
60 4     4   15434 my ($attempt) = @_;
61              
62 4         32 $self->_v("HTTP $method attempt=$attempt $desc");
63              
64 4 50       55 my $r = $self->{http}->request($method, $url, {
65             headers => $headers,
66             (defined $content ? (content => $content) : ()),
67             });
68              
69             # Network/timeout failures show up as success==0 in HTTP::Tiny.
70 4 100       61 if (!$r->{success}) {
71 1         10 die "transient: network/timeout\n";
72             }
73              
74 3   50     14 my $code = $r->{status} // 0;
75              
76             # Retry on 429 + 5xx.
77 3 100 66     43 if ($code == 429 || ($code >= 500 && $code <= 599)) {
      66        
78 1         11 die "transient: http_$code\n";
79             }
80              
81 2         6 return $r;
82 2         35 });
83              
84 2         75 return $res;
85             }
86              
87             sub _v {
88 4     4   53 my ($self, $msg) = @_;
89 4 50       20 return if !$self->{verbose};
90 0           print STDERR "$msg\n";
91             }
92              
93             1;
94              
95             __END__