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 60     60   55221 use Mojo::Base 'Mojo::Content';
  60         165  
  60         420  
3              
4 60     60   1207 use Mojo::Asset::Memory;
  60         149  
  60         383  
5 60     60   28229 use Mojo::Content::MultiPart;
  60         250  
  60         571  
6              
7             has asset => sub { Mojo::Asset::Memory->new(auto_upgrade => 1) };
8             has auto_upgrade => 1;
9              
10 60     60 1 208 sub body_contains { shift->asset->contains(shift) >= 0 }
11              
12             sub body_size {
13 2038     2038 1 3481 my $self = shift;
14 2038 50 0     4466 return ($self->headers->content_length || 0) if $self->is_dynamic;
15 2038   100     8730 return $self->{body_size} //= $self->asset->size;
16             }
17              
18             sub clone {
19 17     17 1 36 my $self = shift;
20 17 100       68 return undef unless my $clone = $self->SUPER::clone();
21 13         58 return $clone->asset($self->asset);
22             }
23              
24             sub get_body_chunk {
25 2849     2849 1 5616 my ($self, $offset) = @_;
26 2849 100       7259 return $self->generate_body_chunk($offset) if $self->is_dynamic;
27 2662         7487 return $self->asset->get_chunk($offset);
28             }
29              
30             sub new {
31 4447     4447 1 25637 my $self = shift->SUPER::new(@_);
32 4447     1182   26532 $self->{read} = $self->on(read => sub { $_[0]->asset($_[0]->asset->add_chunk($_[1])) });
  1182         3730  
33 4447         18709 return $self;
34             }
35              
36             sub parse {
37 2637     2637 1 4841 my $self = shift;
38              
39             # Parse headers
40 2637         9484 $self->_parse_until_body(@_);
41              
42             # Parse body
43 2637 100 100     7594 return $self->SUPER::parse unless $self->auto_upgrade && defined $self->boundary;
44              
45             # Content needs to be upgraded to multipart
46 41         311 $self->unsubscribe(read => $self->{read});
47 41         328 my $multi = Mojo::Content::MultiPart->new(%$self);
48 41         207 $self->emit(upgrade => $multi);
49 41         188 return $multi->parse;
50             }
51              
52             1;
53              
54             =encoding utf8
55              
56             =head1 NAME
57              
58             Mojo::Content::Single - HTTP content
59              
60             =head1 SYNOPSIS
61              
62             use Mojo::Content::Single;
63              
64             my $single = Mojo::Content::Single->new;
65             $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!");
66             say $single->headers->content_length;
67              
68             =head1 DESCRIPTION
69              
70             L is a container for HTTP content, based on L and
71             L.
72              
73             =head1 EVENTS
74              
75             L inherits all events from L and can emit the following new ones.
76              
77             =head2 upgrade
78              
79             $single->on(upgrade => sub ($single, $multi) {...});
80              
81             Emitted when content gets upgraded to a L object.
82              
83             $single->on(upgrade => sub ($single, $multi) {
84             return unless $multi->headers->content_type =~ /multipart\/([^;]+)/i;
85             say "Multipart: $1";
86             });
87              
88             =head1 ATTRIBUTES
89              
90             L inherits all attributes from L and implements the following new ones.
91              
92             =head2 asset
93              
94             my $asset = $single->asset;
95             $single = $single->asset(Mojo::Asset::Memory->new);
96              
97             The actual content, defaults to a L object with L enabled.
98              
99             =head2 auto_upgrade
100              
101             my $bool = $single->auto_upgrade;
102             $single = $single->auto_upgrade($bool);
103              
104             Try to detect multipart content and automatically upgrade to a L object, defaults to a true
105             value.
106              
107             =head1 METHODS
108              
109             L inherits all methods from L and implements the following new ones.
110              
111             =head2 body_contains
112              
113             my $bool = $single->body_contains('1234567');
114              
115             Check if content contains a specific string.
116              
117             =head2 body_size
118              
119             my $size = $single->body_size;
120              
121             Content size in bytes.
122              
123             =head2 clone
124              
125             my $clone = $single->clone;
126              
127             Return a new L object cloned from this content if possible, otherwise return C.
128              
129             =head2 get_body_chunk
130              
131             my $bytes = $single->get_body_chunk(0);
132              
133             Get a chunk of content starting from a specific position. Note that it might not be possible to get the same chunk
134             twice if content was generated dynamically.
135              
136             =head2 new
137              
138             my $single = Mojo::Content::Single->new;
139             my $single = Mojo::Content::Single->new(asset => Mojo::Asset::File->new);
140             my $single = Mojo::Content::Single->new({asset => Mojo::Asset::File->new});
141              
142             Construct a new L object and subscribe to event L with default content
143             parser.
144              
145             =head2 parse
146              
147             $single = $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!");
148             my $multi = $single->parse("Content-Type: multipart/form-data\x0d\x0a\x0d\x0a");
149              
150             Parse content chunk and upgrade to L object if necessary.
151              
152             =head1 SEE ALSO
153              
154             L, L, L.
155              
156             =cut