File: Types.pm

package info (click to toggle)
libmojolicious-perl 8.12%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 3,720 kB
  • sloc: perl: 12,099; makefile: 14
file content (198 lines) | stat: -rw-r--r-- 4,977 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package Mojolicious::Types;
use Mojo::Base -base;

has mapping => sub {
  {
    appcache => ['text/cache-manifest'],
    atom     => ['application/atom+xml'],
    bin      => ['application/octet-stream'],
    css      => ['text/css'],
    gif      => ['image/gif'],
    gz       => ['application/x-gzip'],
    htm      => ['text/html'],
    html     => ['text/html;charset=UTF-8'],
    ico      => ['image/x-icon'],
    jpeg     => ['image/jpeg'],
    jpg      => ['image/jpeg'],
    js       => ['application/javascript'],
    json     => ['application/json;charset=UTF-8'],
    mp3      => ['audio/mpeg'],
    mp4      => ['video/mp4'],
    ogg      => ['audio/ogg'],
    ogv      => ['video/ogg'],
    pdf      => ['application/pdf'],
    png      => ['image/png'],
    rss      => ['application/rss+xml'],
    svg      => ['image/svg+xml'],
    txt      => ['text/plain;charset=UTF-8'],
    webm     => ['video/webm'],
    woff     => ['font/woff'],
    woff2    => ['font/woff2'],
    xml      => ['application/xml', 'text/xml'],
    zip      => ['application/zip']
  };
};

sub content_type {
  my ($self, $c, $o) = (shift, shift, shift // {});

  my $headers = $c->res->headers;
  return undef if $headers->content_type;

  my $type = $o->{file} ? $self->file_type($o->{file}) : $self->type($o->{ext});
  $headers->content_type($type // $self->type('txt'));
}

sub detect {
  my ($self, $accept) = @_;

  # Extract and prioritize MIME types
  my %types;
  /^\s*([^,; ]+)(?:\s*\;\s*q\s*=\s*(\d+(?:\.\d+)?))?\s*$/i
    and $types{lc $1} = $2 // 1
    for split ',', $accept // '';
  my @detected = sort { $types{$b} <=> $types{$a} } sort keys %types;

  # Detect extensions from MIME types
  my %reverse;
  my $mapping = $self->mapping;
  for my $ext (sort keys %$mapping) {
    my @types = @{$mapping->{$ext}};
    push @{$reverse{$_}}, $ext for map { s/\;.*$//; lc $_ } @types;
  }

  return [map { @{$reverse{$_} // []} } @detected];
}

sub file_type { $_[1] =~ /\.(\w+)$/ ? $_[0]->type($1) : undef }

sub type {
  my ($self, $ext, $type) = @_;
  return $self->mapping->{lc $ext}[0] unless $type;
  $self->mapping->{lc $ext} = ref $type ? $type : [$type];
  return $self;
}

1;

=encoding utf8

=head1 NAME

Mojolicious::Types - MIME types

=head1 SYNOPSIS

  use Mojolicious::Types;

  my $types = Mojolicious::Types->new;
  $types->type(foo => 'text/foo');
  say $types->type('foo');

=head1 DESCRIPTION

L<Mojolicious::Types> manages MIME types for L<Mojolicious>.

  appcache -> text/cache-manifest
  atom     -> application/atom+xml
  bin      -> application/octet-stream
  css      -> text/css
  gif      -> image/gif
  gz       -> application/x-gzip
  htm      -> text/html
  html     -> text/html;charset=UTF-8
  ico      -> image/x-icon
  jpeg     -> image/jpeg
  jpg      -> image/jpeg
  js       -> application/javascript
  json     -> application/json;charset=UTF-8
  mp3      -> audio/mpeg
  mp4      -> video/mp4
  ogg      -> audio/ogg
  ogv      -> video/ogg
  pdf      -> application/pdf
  png      -> image/png
  rss      -> application/rss+xml
  svg      -> image/svg+xml
  txt      -> text/plain;charset=UTF-8
  webm     -> video/webm
  woff     -> font/woff
  woff2    -> font/woff2
  xml      -> application/xml,text/xml
  zip      -> application/zip

The most common ones are already defined.

=head1 ATTRIBUTES

L<Mojolicious::Types> implements the following attributes.

=head2 mapping

  my $mapping = $types->mapping;
  $types      = $types->mapping({png => ['image/png']});

MIME type mapping.

=head1 METHODS

L<Mojolicious::Types> inherits all methods from L<Mojo::Base> and implements
the following new ones.

=head2 content_type

  $types->content_type(Mojolicious::Controller->new, {ext => 'json'});

Detect MIME type for L<Mojolicious::Controller> object unless a C<Content-Type>
response header has already been set, defaults to using the MIME type for the
C<txt> extension if no better alternative could be found. Note that this method
is EXPERIMENTAL and might change without warning!

These options are currently available:

=over 2

=item ext

  ext => 'json'

File extension to get MIME type for.

=item file

  file => 'foo/bar.png'

File path to get MIME type for.

=back

=head2 detect

  my $exts = $types->detect('text/html, application/json;q=9');

Detect file extensions from C<Accept> header value.

  # List detected extensions prioritized
  say for @{$types->detect('application/json, text/xml;q=0.1', 1)};

=head2 file_type

  my $type = $types->file_type('foo/bar.png');

Get MIME type for file path. Note that this method is EXPERIMENTAL and might
change without warning!

=head2 type

  my $type = $types->type('png');
  $types   = $types->type(png => 'image/png');
  $types   = $types->type(json => ['application/json', 'text/x-json']);

Get or set MIME types for file extension, alternatives are only used for
detection.

=head1 SEE ALSO

L<Mojolicious>, L<Mojolicious::Guides>, L<https://mojolicious.org>.

=cut