File Coverage

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


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