File Coverage

blib/lib/CGI/Header/Adapter.pm
Criterion Covered Total %
statement 72 75 96.0
branch 16 36 44.4
condition 8 22 36.3
subroutine 11 11 100.0
pod 5 5 100.0
total 112 149 75.1


line stmt bran cond sub pod time code
1             package CGI::Header::Adapter;
2 2     2   34017 use strict;
  2         5  
  2         69  
3 2     2   10 use warnings;
  2         2  
  2         52  
4 2     2   1506 use parent 'CGI::Header';
  2         538  
  2         8  
5 2     2   81 use Carp qw/croak/;
  2         4  
  2         1511  
6              
7             sub crlf {
8 12     12 1 15 $CGI::CRLF;
9             }
10              
11             sub finalize {
12 1     1 1 2015 croak 'call to abstract method ', __PACKAGE__, '::finalize';
13             }
14              
15             sub as_string {
16 1     1 1 2 my $self = shift;
17 1         4 my $query = $self->query;
18 1         4 my $crlf = $self->crlf;
19 1         2 my $headers = $self->as_arrayref;
20              
21 1         2 my @lines;
22              
23             # add Status-Line required by NPH scripts
24 1 50 33     6 if ( $self->nph or $query->nph ) {
25 1         8 my $protocol = $query->server_protocol;
26 1   50     92 my $status = $self->process_newline( {@$headers}->{'Status'} || '200 OK' );
27 1         5 push @lines, "$protocol $status$crlf";
28             }
29              
30             # add response headers
31 1         4 for ( my $i = 0; $i < @$headers; $i += 2 ) {
32 10         12 my $field = $headers->[$i];
33 10         18 my $value = $self->process_newline( $headers->[$i+1] );
34 10         29 push @lines, "$field: $value$crlf";
35             }
36              
37 1         2 push @lines, $crlf; # add an empty line
38              
39 1         7 join q{}, @lines;
40             }
41              
42             sub process_newline {
43 11     11 1 12 my $self = shift;
44 11         7 my $value = shift;
45 11         18 my $crlf = $self->crlf;
46              
47             # CR escaping for values, per RFC 822:
48             # > Unfolding is accomplished by regarding CRLF immediately
49             # > followed by a LWSP-char as equivalent to the LWSP-char.
50 11         28 $value =~ s/$crlf(\s)/$1/g;
51              
52             # All other uses of newlines are invalid input.
53 11 50       46 if ( $value =~ /$crlf|\015|\012/ ) {
54             # shorten very long values in the diagnostic
55 0 0       0 $value = substr($value, 0, 72) . '...' if length $value > 72;
56 0         0 croak "Invalid header value contains a newline not followed by whitespace: $value";
57             }
58              
59 11         21 $value;
60             }
61              
62             sub as_arrayref {
63 2     2 1 6 my $self = shift;
64 2         7 my $query = $self->query;
65 2         4065 my %header = %{ $self->header };
  2         6  
66              
67 2         10 my ( $attachment, $charset, $cookies, $expires, $nph, $p3p, $status, $target, $type )
68             = delete @header{qw/attachment charset cookies expires nph p3p status target type/};
69              
70 2         3 my @headers;
71              
72 2   33     5 $nph ||= $query->nph;
73              
74 2 50       30 push @headers, 'Server', $query->server_software if $nph;
75 2 50       86 push @headers, 'Status', $status if $status;
76 2 50       5 push @headers, 'Window-Target', $target if $target;
77              
78 2 50       7 if ( $p3p ) {
79 2 50       4 my $tags = ref $p3p eq 'ARRAY' ? join ' ', @{$p3p} : $p3p;
  0         0  
80 2         6 push @headers, 'P3P', qq{policyref="/w3c/p3p.xml", CP="$tags"};
81             }
82              
83 2 50       5 my @cookies = ref $cookies eq 'ARRAY' ? @{$cookies} : $cookies;
  2         4  
84 2 50       3 @cookies = map { $self->_bake_cookie($_) || () } @cookies;
  2         8  
85              
86 2         115 push @headers, map { ('Set-Cookie', $_) } @cookies;
  2         5  
87 2 50       8 push @headers, 'Expires', $self->_date($expires) if $expires;
88 2 0 33     119 push @headers, 'Date', $self->_date if $expires or @cookies or $nph;
      33        
89 2 50       78 push @headers, 'Pragma', 'no-cache' if $query->cache;
90              
91 2 50       155 if ( $attachment ) {
92 2         4 my $value = qq{attachment; filename="$attachment"};
93 2         4 push @headers, 'Content-Disposition', $value;
94             }
95              
96 2         5 push @headers, map { ucfirst $_, $header{$_} } keys %header;
  2         6  
97              
98 2 50 33     13 unless ( defined $type and $type eq q{} ) {
99 2   50     5 my $value = $type || 'text/html';
100 2 50       4 $charset = $query->charset if !defined $charset;
101 2 50 33     12 $value .= "; charset=$charset" if $charset && $value !~ /\bcharset\b/;
102 2         3 push @headers, 'Content-Type', $value;
103             }
104              
105 2         16 \@headers;
106             }
107              
108             sub _bake_cookie {
109 2     2   2 my ( $self, $cookie ) = @_;
110 2 50       9 ref $cookie eq 'CGI::Cookie' ? $cookie->as_string : $cookie;
111             }
112              
113             sub _date {
114 4     4   5 my ( $self, $expires ) = @_;
115 4         10 CGI::Util::expires( $expires, 'http' );
116             }
117              
118             1;
119              
120             __END__