File Coverage

blib/lib/Mojo/Content/Single.pm
Criterion Covered Total %
statement 30 30 100.0
branch 7 8 87.5
condition 6 8 75.0
subroutine 10 10 100.0
pod 6 6 100.0
total 59 62 95.1


line stmt bran cond sub pod time code
1             package Mojo::Content::Single;
2 56     56   51678 use Mojo::Base 'Mojo::Content';
  56         129  
  56         375  
3              
4 56     56   1133 use Mojo::Asset::Memory;
  56         151  
  56         418  
5 56     56   25065 use Mojo::Content::MultiPart;
  56         167  
  56         491  
6              
7             has asset => sub { Mojo::Asset::Memory->new(auto_upgrade => 1) };
8             has auto_upgrade => 1;
9              
10 60     60 1 607 sub body_contains { shift->asset->contains(shift) >= 0 }
11              
12             sub body_size {
13 1814     1814 1 2949 my $self = shift;
14 1814 50 0     3931 return ($self->headers->content_length || 0) if $self->is_dynamic;
15 1814   100     7237 return $self->{body_size} //= $self->asset->size;
16             }
17              
18             sub clone {
19 14     14 1 27 my $self = shift;
20 14 100       49 return undef unless my $clone = $self->SUPER::clone();
21 10         27 return $clone->asset($self->asset);
22             }
23              
24             sub get_body_chunk {
25 2546     2546 1 4937 my ($self, $offset) = @_;
26 2546 100       6498 return $self->generate_body_chunk($offset) if $self->is_dynamic;
27 2381         6375 return $self->asset->get_chunk($offset);
28             }
29              
30             sub new {
31 3936     3936 1 11014 my $self = shift->SUPER::new(@_);
32             $self->{read}
33 3936     1103   22473 = $self->on(read => sub { $_[0]->asset($_[0]->asset->add_chunk($_[1])) });
  1103         3095  
34 3936         16447 return $self;
35             }
36              
37             sub parse {
38 2408     2408 1 4103 my $self = shift;
39              
40             # Parse headers
41 2408         7870 $self->_parse_until_body(@_);
42              
43             # Parse body
44 2408 100 100     6570 return $self->SUPER::parse
45             unless $self->auto_upgrade && defined $self->boundary;
46              
47             # Content needs to be upgraded to multipart
48 40         261 $self->unsubscribe(read => $self->{read});
49 40         306 my $multi = Mojo::Content::MultiPart->new(%$self);
50 40         169 $self->emit(upgrade => $multi);
51 40         471 return $multi->parse;
52             }
53              
54             1;
55              
56             =encoding utf8
57              
58             =head1 NAME
59              
60             Mojo::Content::Single - HTTP content
61              
62             =head1 SYNOPSIS
63              
64             use Mojo::Content::Single;
65              
66             my $single = Mojo::Content::Single->new;
67             $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!");
68             say $single->headers->content_length;
69              
70             =head1 DESCRIPTION
71              
72             L is a container for HTTP content, based on
73             L and
74             L.
75              
76             =head1 EVENTS
77              
78             L inherits all events from L and can emit
79             the following new ones.
80              
81             =head2 upgrade
82              
83             $single->on(upgrade => sub {
84             my ($single, $multi) = @_;
85             ...
86             });
87              
88             Emitted when content gets upgraded to a L object.
89              
90             $single->on(upgrade => sub {
91             my ($single, $multi) = @_;
92             return unless $multi->headers->content_type =~ /multipart\/([^;]+)/i;
93             say "Multipart: $1";
94             });
95              
96             =head1 ATTRIBUTES
97              
98             L inherits all attributes from L and
99             implements the following new ones.
100              
101             =head2 asset
102              
103             my $asset = $single->asset;
104             $single = $single->asset(Mojo::Asset::Memory->new);
105              
106             The actual content, defaults to a L object with
107             L enabled.
108              
109             =head2 auto_upgrade
110              
111             my $bool = $single->auto_upgrade;
112             $single = $single->auto_upgrade($bool);
113              
114             Try to detect multipart content and automatically upgrade to a
115             L object, defaults to a true value.
116              
117             =head1 METHODS
118              
119             L inherits all methods from L and
120             implements the following new ones.
121              
122             =head2 body_contains
123              
124             my $bool = $single->body_contains('1234567');
125              
126             Check if content contains a specific string.
127              
128             =head2 body_size
129              
130             my $size = $single->body_size;
131              
132             Content size in bytes.
133              
134             =head2 clone
135              
136             my $clone = $single->clone;
137              
138             Return a new L object cloned from this content if
139             possible, otherwise return C.
140              
141             =head2 get_body_chunk
142              
143             my $bytes = $single->get_body_chunk(0);
144              
145             Get a chunk of content starting from a specific position. Note that it might
146             not be possible to get the same chunk twice if content was generated
147             dynamically.
148              
149             =head2 new
150              
151             my $single = Mojo::Content::Single->new;
152             my $single = Mojo::Content::Single->new(asset => Mojo::Asset::File->new);
153             my $single = Mojo::Content::Single->new({asset => Mojo::Asset::File->new});
154              
155             Construct a new L object and subscribe to event
156             L with default content parser.
157              
158             =head2 parse
159              
160             $single = $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!");
161             my $multi
162             = $single->parse("Content-Type: multipart/form-data\x0d\x0a\x0d\x0a");
163              
164             Parse content chunk and upgrade to L object if
165             necessary.
166              
167             =head1 SEE ALSO
168              
169             L, L, L.
170              
171             =cut