File Coverage

blib/lib/Kossy/Response.pm
Criterion Covered Total %
statement 50 58 86.2
branch 23 36 63.8
condition 8 15 53.3
subroutine 11 11 100.0
pod 3 3 100.0
total 95 123 77.2


line stmt bran cond sub pod time code
1             package Kossy::Response;
2              
3 11     11   78 use strict;
  11         21  
  11         381  
4 11     11   54 use warnings;
  11         23  
  11         341  
5 11     11   56 use parent qw/Plack::Response/;
  11         20  
  11         56  
6 11     11   133341 use Encode;
  11         47105  
  11         865  
7 11     11   76 use HTTP::Headers::Fast;
  11         23  
  11         211  
8 11     11   51 use Cookie::Baker;
  11         19  
  11         7863  
9              
10             our $VERSION = '0.50';
11              
12             our $DIRECT;
13             our $SECURITY_HEADER = 1;
14              
15             sub new {
16 34     34 1 93 my ($class, $rc, $headers, $content) = @_;
17 34 100       85 if ( defined $headers ) {
18 30 100       92 if (ref $headers eq 'ARRAY') {
    50          
19 12 50       36 Carp::carp("Odd number of headers") if @$headers % 2 != 0;
20 12         44 $headers = HTTP::Headers::Fast->new(@$headers);
21             } elsif (ref $headers eq 'HASH') {
22 0         0 $headers = HTTP::Headers::Fast->new(%$headers);
23             }
24             }
25             bless {
26 34 50       872 defined $rc ? ( status => $rc ) : (),
    100          
    100          
27             defined $content ? ( body => $content ) : (),
28             defined $headers ? ( headers => $headers ) : (),
29             }, $class;
30             }
31              
32             sub headers {
33 30     30 1 62 my $self = shift;
34              
35 30 50       66 if (@_) {
36 0         0 my $headers = shift;
37 0 0       0 if (ref $headers eq 'ARRAY') {
    0          
38 0 0       0 Carp::carp("Odd number of headers") if @$headers % 2 != 0;
39 0         0 $headers = HTTP::Headers::Fast->new(@$headers);
40             } elsif (ref $headers eq 'HASH') {
41 0         0 $headers = HTTP::Headers::Fast->new(%$headers);
42             }
43 0         0 return $self->{headers} = $headers;
44             } else {
45 30   66     232 return $self->{headers} ||= HTTP::Headers::Fast->new();
46             }
47             }
48              
49             sub _body {
50 29     29   135 my $self = shift;
51 29         75 my $body = $self->body;
52 29 100       147 $body = [] unless defined $body;
53 29 100 33     140 if (!ref $body or Scalar::Util::blessed($body) && overload::Method($body, q("")) && !$body->can('getline')) {
      33        
      66        
54 14 100       99 return [ Encode::encode_utf8($body) ] if Encode::is_utf8($body);
55 9         128 return [ $body ];
56             } else {
57 15         176 return $body;
58             }
59             }
60              
61             sub finalize {
62 29     29 1 51 my $self = shift;
63 29 50       63 return $DIRECT if $DIRECT;
64 29 50       112 Carp::croak "missing status" unless $self->status();
65              
66 29         154 my @headers;
67             $self->headers->scan(sub{
68 38     38   673 my ($k,$v) = @_;
69 38 50 66     130 return if $SECURITY_HEADER && $k eq 'X-XSS-Protection';
70 38         74 $v =~ s/\015\012[\040|\011]+/chr(32)/ge; # replace LWS with a single SP
  0         0  
71 38         111 $v =~ s/\015|\012//g; # remove CR and LF since the char is invalid here
72 38         104 push @headers, $k, $v;
73 29         64 });
74              
75 29         262 while (my($name, $val) = each %{$self->cookies}) {
  30         108  
76 1         31 my $cookie = bake_cookie($name, $val);
77 1         80 push @headers, 'Set-Cookie' => $cookie;
78             }
79              
80 29 100       327 push @headers, 'X-XSS-Protection' => 1 if $SECURITY_HEADER;
81              
82             return [
83 29         83 $self->status,
84             \@headers,
85             $self->_body,
86             ];
87             }
88              
89             1;