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 51     51   425 use Mojo::Base -base;
  51         178  
  51         447  
3              
4 51     51   432 use Mojo::File qw(path);
  51         190  
  51         48192  
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             svg => ['image/svg+xml'],
29             ttf => ['font/ttf'],
30             txt => ['text/plain;charset=UTF-8'],
31             webm => ['video/webm'],
32             woff => ['font/woff'],
33             woff2 => ['font/woff2'],
34             xml => ['application/xml', 'text/xml'],
35             zip => ['application/zip']
36             };
37             };
38              
39             sub content_type {
40 883   50 883 1 3265 my ($self, $c, $o) = (shift, shift, shift // {});
41              
42 883         2527 my $headers = $c->res->headers;
43 883 100       3155 return undef if $headers->content_type;
44              
45 821 100       4246 my $type = $o->{file} ? $self->file_type($o->{file}) : $self->type($o->{ext});
46 821   100     3089 $headers->content_type($type // 'application/octet-stream');
47             }
48              
49             sub detect {
50 158     158 1 8802 my ($self, $accept) = @_;
51              
52             # Extract and prioritize MIME types
53 158         251 my %types;
54 158   100     1939 /^\s*([^,; ]+)(?:\s*\;\s*q\s*=\s*(\d+(?:\.\d+)?))?\s*$/i and $types{lc $1} = $2 // 1 for split /,/, $accept // '';
      100        
      33        
55 158         675 my @detected = sort { $types{$b} <=> $types{$a} } sort keys %types;
  33         98  
56              
57             # Detect extensions from MIME types
58 158         266 my %reverse;
59 158         440 my $mapping = $self->mapping;
60 158         2123 for my $ext (sort keys %$mapping) {
61 4518         5705 my @types = @{$mapping->{$ext}};
  4518         7872  
62 4518         6267 push @{$reverse{$_}}, $ext for map { s/\;.*$//; lc $_ } @types;
  4687         7643  
  4687         9664  
  4687         14104  
63             }
64              
65 158   100     920 return [map { @{$reverse{$_} // []} } @detected];
  124         168  
  124         1637  
66             }
67              
68 88     88 1 3412 sub file_type { $_[0]->type(path($_[1])->extname) }
69              
70             sub type {
71 842     842 1 6074 my ($self, $ext, $type) = @_;
72 842 100       3275 return $self->mapping->{lc $ext}[0] unless $type;
73 5 100       35 $self->mapping->{lc $ext} = ref $type ? $type : [$type];
74 5         15 return $self;
75             }
76              
77             1;
78              
79             =encoding utf8
80              
81             =head1 NAME
82              
83             Mojolicious::Types - MIME types
84              
85             =head1 SYNOPSIS
86              
87             use Mojolicious::Types;
88              
89             my $types = Mojolicious::Types->new;
90             $types->type(foo => 'text/foo');
91             say $types->type('foo');
92              
93             =head1 DESCRIPTION
94              
95             L manages MIME types for L.
96              
97             appcache -> text/cache-manifest
98             atom -> application/atom+xml
99             bin -> application/octet-stream
100             css -> text/css
101             gif -> image/gif
102             gz -> application/x-gzip
103             htm -> text/html
104             html -> text/html;charset=UTF-8
105             ico -> image/x-icon
106             jpeg -> image/jpeg
107             jpg -> image/jpeg
108             js -> application/javascript
109             json -> application/json;charset=UTF-8
110             mp3 -> audio/mpeg
111             mp4 -> video/mp4
112             ogg -> audio/ogg
113             ogv -> video/ogg
114             pdf -> application/pdf
115             png -> image/png
116             rss -> application/rss+xml
117             svg -> image/svg+xml
118             ttf -> font/ttf
119             txt -> text/plain;charset=UTF-8
120             webm -> video/webm
121             woff -> font/woff
122             woff2 -> font/woff2
123             xml -> application/xml,text/xml
124             zip -> application/zip
125              
126             The most common ones are already defined.
127              
128             =head1 ATTRIBUTES
129              
130             L implements the following attributes.
131              
132             =head2 mapping
133              
134             my $mapping = $types->mapping;
135             $types = $types->mapping({png => ['image/png']});
136              
137             MIME type mapping.
138              
139             =head1 METHODS
140              
141             L inherits all methods from L and implements the following new ones.
142              
143             =head2 content_type
144              
145             $types->content_type(Mojolicious::Controller->new, {ext => 'json'});
146              
147             Detect MIME type for L object unless a C response header has already been set,
148             defaults to using C if no better alternative could be found. These options are currently
149             available:
150              
151             =over 2
152              
153             =item ext
154              
155             ext => 'json'
156              
157             File extension to get MIME type for.
158              
159             =item file
160              
161             file => 'foo/bar.png'
162              
163             File path to get MIME type for.
164              
165             =back
166              
167             =head2 detect
168              
169             my $exts = $types->detect('text/html, application/json;q=9');
170              
171             Detect file extensions from C header value.
172              
173             # List detected extensions prioritized
174             say for @{$types->detect('application/json, text/xml;q=0.1', 1)};
175              
176             =head2 file_type
177              
178             my $type = $types->file_type('foo/bar.png');
179              
180             Get MIME type for file path.
181              
182             =head2 type
183              
184             my $type = $types->type('png');
185             $types = $types->type(png => 'image/png');
186             $types = $types->type(json => ['application/json', 'text/x-json']);
187              
188             Get or set MIME types for file extension, alternatives are only used for detection.
189              
190             =head1 SEE ALSO
191              
192             L, L, L.
193              
194             =cut