File Coverage

blib/lib/Mojolicious/Types.pm
Criterion Covered Total %
statement 33 33 100.0
branch 8 8 100.0
condition 10 13 76.9
subroutine 6 6 100.0
pod 4 4 100.0
total 61 64 95.3


line stmt bran cond sub pod time code
1             package Mojolicious::Types;
2 54     54   9825 use Mojo::Base -base;
  54         192  
  54         2171  
3              
4 54     54   469 use Mojo::File qw(path);
  54         146  
  54         72574  
5              
6             has mapping => sub {
7             {
8             appcache => ['text/cache-manifest'],
9             atom => ['application/atom+xml'],
10             bin => ['application/octet-stream'],
11             css => ['text/css'],
12             gif => ['image/gif'],
13             gz => ['application/x-gzip'],
14             htm => ['text/html'],
15             html => ['text/html;charset=UTF-8'],
16             ico => ['image/x-icon'],
17             jpeg => ['image/jpeg'],
18             jpg => ['image/jpeg'],
19             js => ['application/javascript'],
20             json => ['application/json;charset=UTF-8'],
21             mp3 => ['audio/mpeg'],
22             mp4 => ['video/mp4'],
23             ogg => ['audio/ogg'],
24             ogv => ['video/ogg'],
25             pdf => ['application/pdf'],
26             png => ['image/png'],
27             rss => ['application/rss+xml'],
28             sse => ['text/event-stream'],
29             svg => ['image/svg+xml'],
30             ttf => ['font/ttf'],
31             txt => ['text/plain;charset=UTF-8'],
32             webm => ['video/webm'],
33             woff => ['font/woff'],
34             woff2 => ['font/woff2'],
35             xml => ['application/xml', 'text/xml'],
36             zip => ['application/zip']
37             };
38             };
39              
40             sub content_type {
41 912   50 912 1 4311 my ($self, $c, $o) = (shift, shift, shift // {});
42              
43 912         3442 my $headers = $c->res->headers;
44 912 100       4033 return undef if $headers->content_type;
45              
46 851 100       5548 my $type = $o->{file} ? $self->file_type($o->{file}) : $self->type($o->{ext});
47 851   100     4188 $headers->content_type($type // 'application/octet-stream');
48             }
49              
50             sub detect {
51 160     160 1 33629 my ($self, $accept) = @_;
52              
53             # Extract and prioritize MIME types
54 160         415 my %types;
55 160   100     2690 /^\s*([^,; ]+)(?:\s*\;\s*q\s*=\s*(\d+(?:\.\d+)?))?\s*$/i and $types{lc $1} = $2 // 1 for split /,/, $accept // '';
      100        
      33        
56 160         790 my @detected = sort { $types{$b} <=> $types{$a} } sort keys %types;
  34         151  
57              
58             # Detect extensions from MIME types
59 160         299 my %reverse;
60 160         647 my $mapping = $self->mapping;
61 160         3247 for my $ext (sort keys %$mapping) {
62 4738         9362 my @types = @{$mapping->{$ext}};
  4738         9815  
63 4738         8802 push @{$reverse{$_}}, $ext for map { s/\;.*$//; lc $_ } @types;
  4909         12638  
  4909         20838  
  4909         17418  
64             }
65              
66 160   100     1366 return [map { @{$reverse{$_} // []} } @detected];
  127         205  
  127         2347  
67             }
68              
69 87     87 1 13176 sub file_type { $_[0]->type(path($_[1])->extname) }
70              
71             sub type {
72 872     872 1 10463 my ($self, $ext, $type) = @_;
73 872 100       4766 return $self->mapping->{lc $ext}[0] unless $type;
74 5 100       62 $self->mapping->{lc $ext} = ref $type ? $type : [$type];
75 5         31 return $self;
76             }
77              
78             1;
79              
80             =encoding utf8
81              
82             =head1 NAME
83              
84             Mojolicious::Types - MIME types
85              
86             =head1 SYNOPSIS
87              
88             use Mojolicious::Types;
89              
90             my $types = Mojolicious::Types->new;
91             $types->type(foo => 'text/foo');
92             say $types->type('foo');
93              
94             =head1 DESCRIPTION
95              
96             L manages MIME types for L.
97              
98             appcache -> text/cache-manifest
99             atom -> application/atom+xml
100             bin -> application/octet-stream
101             css -> text/css
102             gif -> image/gif
103             gz -> application/x-gzip
104             htm -> text/html
105             html -> text/html;charset=UTF-8
106             ico -> image/x-icon
107             jpeg -> image/jpeg
108             jpg -> image/jpeg
109             js -> application/javascript
110             json -> application/json;charset=UTF-8
111             mp3 -> audio/mpeg
112             mp4 -> video/mp4
113             ogg -> audio/ogg
114             ogv -> video/ogg
115             pdf -> application/pdf
116             png -> image/png
117             rss -> application/rss+xml
118             sse -> text/event-stream
119             svg -> image/svg+xml
120             ttf -> font/ttf
121             txt -> text/plain;charset=UTF-8
122             webm -> video/webm
123             woff -> font/woff
124             woff2 -> font/woff2
125             xml -> application/xml,text/xml
126             zip -> application/zip
127              
128             The most common ones are already defined.
129              
130             =head1 ATTRIBUTES
131              
132             L implements the following attributes.
133              
134             =head2 mapping
135              
136             my $mapping = $types->mapping;
137             $types = $types->mapping({png => ['image/png']});
138              
139             MIME type mapping.
140              
141             =head1 METHODS
142              
143             L inherits all methods from L and implements the following new ones.
144              
145             =head2 content_type
146              
147             $types->content_type(Mojolicious::Controller->new, {ext => 'json'});
148              
149             Detect MIME type for L object unless a C response header has already been set,
150             defaults to using C if no better alternative could be found. These options are currently
151             available:
152              
153             =over 2
154              
155             =item ext
156              
157             ext => 'json'
158              
159             File extension to get MIME type for.
160              
161             =item file
162              
163             file => 'foo/bar.png'
164              
165             File path to get MIME type for.
166              
167             =back
168              
169             =head2 detect
170              
171             my $exts = $types->detect('text/html, application/json;q=9');
172              
173             Detect file extensions from C header value.
174              
175             # List detected extensions prioritized
176             say for @{$types->detect('application/json, text/xml;q=0.1', 1)};
177              
178             =head2 file_type
179              
180             my $type = $types->file_type('foo/bar.png');
181              
182             Get MIME type for file path.
183              
184             =head2 type
185              
186             my $type = $types->type('png');
187             $types = $types->type(png => 'image/png');
188             $types = $types->type(json => ['application/json', 'text/x-json']);
189              
190             Get or set MIME types for file extension, alternatives are only used for detection.
191              
192             =head1 SEE ALSO
193              
194             L, L, L.
195              
196             =cut