File Coverage

blib/lib/HTTP/UserAgentClientHints.pm
Criterion Covered Total %
statement 55 55 100.0
branch 19 20 95.0
condition 7 8 87.5
subroutine 13 13 100.0
pod 2 2 100.0
total 96 98 97.9


line stmt bran cond sub pod time code
1             package HTTP::UserAgentClientHints;
2 2     2   145304 use strict;
  2         12  
  2         91  
3 2     2   9 use warnings;
  2         4  
  2         40  
4 2     2   686 use HTTP::UserAgentClientHints::BrandVersion;
  2         5  
  2         46  
5 2     2   11 use HTTP::UserAgentClientHints::Util;
  2         7  
  2         121  
6              
7             our $VERSION = '0.04';
8              
9             my $HTTP_HEADER_PREFIX = 'Sec-CH-UA';
10              
11             my @FIELDS = qw/
12             UA
13             Mobile
14             Platform
15             Arch
16             Bitness
17             Model
18             Full-Version-List
19             Full-Version
20             /;
21              
22             # Build getters
23             for my $field (@FIELDS) {
24             my $method = __PACKAGE__->_as_method($field);
25 2     2   9 no strict 'refs'; ## no critic
  2         4  
  2         1288  
26             *{__PACKAGE__ . '::' . $method} = sub {
27 15     15   7297 my $self = shift;
28 15 100       41 if (exists $self->{_value}{$method}) {
29 3         12 return $self->{_value}{$method};
30             }
31 12         25 my $raw_value = $self->{_headers}->header($self->_as_http_header_key($field));
32 12         369 return $self->{_value}{$method} = $self->_normalize($raw_value, $field);
33             };
34             *{__PACKAGE__ . '::' . $method . '_raw'} = sub {
35 13     13   6509 my $self = shift;
36 13 100       37 if (exists $self->{_value_raw}{$method}) {
37 1         4 return $self->{_value_raw}{$method};
38             }
39 12         24 return $self->{_value_raw}{$method} = $self->{_headers}->header($self->_as_http_header_key($field));
40             };
41             }
42              
43             my $FULL_ACCEPT_CH = __PACKAGE__->_accept_ch;
44              
45             sub _as_method {
46 16     16   24 my ($self, $field) = @_;
47              
48 16         34 $field =~ s/-/_/g;
49 16         59 $field = lc $field;
50              
51 16         23 return $field;
52             }
53              
54             sub _as_http_header_key {
55 56     56   90 my ($self, $field) = @_;
56              
57 56 100 66     255 return $HTTP_HEADER_PREFIX . (!$field || $field eq 'UA' ? '' : "-$field");
58             }
59              
60             sub _normalize {
61 12     12   22 my ($self, $value, $field) = @_;
62              
63 12 100       32 return $value unless defined $value;
64              
65 10 100 100     55 if ($field eq 'UA' || $field eq 'Full-Version-List') {
    100          
    50          
66 2         8 $value = HTTP::UserAgentClientHints::BrandVersion->new($value);
67             }
68             elsif ($field =~ m!^(?:Platform|Arch|Bitness|Model|Full-Version)$!) {
69 6         15 $value = HTTP::UserAgentClientHints::Util->strip_quote($value);
70             }
71             elsif ($field eq 'Mobile') {
72 2         6 $value =~ s/^\?//;
73             }
74              
75 10         41 return $value;
76             }
77              
78             sub new {
79 3     3 1 1910 my ($class, $http_headers_obj) = @_;
80              
81 3 100       19 unless ($http_headers_obj->can('header')) {
82 1         10 die q|Argument object:| . ref($http_headers_obj) . q| doesn't have "header" method to get HTTP header value.|;
83             }
84              
85             bless {
86 2         9 _headers => $http_headers_obj,
87             _value_raw => {},
88             _value => {},
89             }, $class;
90             }
91              
92             sub accept_ch {
93 3 100   3 1 1555 return $FULL_ACCEPT_CH unless $_[1];
94              
95 2         8 return _accept_ch(@_);
96             }
97              
98             sub _accept_ch {
99 4     4   7 my ($self, $excepts) = @_;
100              
101 4   100     23 $excepts ||= [];
102              
103 4         8 unshift @{$excepts}, 'Sec-CH-UA', 'Sec-CH-UA-Mobile', 'Sec-CH-UA-Platform'; # Default fields
  4         10  
104              
105 4         8 my @accept_ch;
106 4         5 for my $field (@FIELDS) {
107 32         52 my $f = $self->_as_http_header_key($field);
108 32 100       41 next if grep { lc($f) eq lc($_) } @{$excepts};
  120         209  
  32         44  
109 17         28 push @accept_ch, $f;
110             }
111              
112 4         20 return join(', ', @accept_ch);
113             }
114              
115             1;
116              
117             __END__