line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Clustericious::Plugin::AutodataHandler; |
2
|
|
|
|
|
|
|
|
3
|
25
|
|
|
25
|
|
20207
|
use strict; |
|
25
|
|
|
|
|
65
|
|
|
25
|
|
|
|
|
669
|
|
4
|
25
|
|
|
25
|
|
124
|
use warnings; |
|
25
|
|
|
|
|
51
|
|
|
25
|
|
|
|
|
641
|
|
5
|
25
|
|
|
25
|
|
135
|
use base 'Mojolicious::Plugin'; |
|
25
|
|
|
|
|
89
|
|
|
25
|
|
|
|
|
2923
|
|
6
|
25
|
|
|
25
|
|
265
|
use Mojo::ByteStream 'b'; |
|
25
|
|
|
|
|
53
|
|
|
25
|
|
|
|
|
1222
|
|
7
|
25
|
|
|
25
|
|
220
|
use Clustericious::Log; |
|
25
|
|
|
|
|
119
|
|
|
25
|
|
|
|
|
175
|
|
8
|
25
|
|
|
25
|
|
21446
|
use PerlX::Maybe qw( maybe ); |
|
25
|
|
|
|
|
38162
|
|
|
25
|
|
|
|
|
1431
|
|
9
|
25
|
|
|
25
|
|
1308
|
use Path::Class qw( dir ); |
|
25
|
|
|
|
|
25232
|
|
|
25
|
|
|
|
|
21860
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# ABSTRACT: Handle data types automatically |
12
|
|
|
|
|
|
|
our $VERSION = '1.27'; # VERSION |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub _default_coders |
16
|
|
|
|
|
|
|
{ |
17
|
|
|
|
|
|
|
my %coders = |
18
|
372
|
|
|
|
|
727
|
map { $_ => 1 } |
19
|
372
|
|
|
|
|
1059
|
map { $_ =~ s/\.pm$//; $_ } |
|
372
|
|
|
|
|
718
|
|
20
|
372
|
|
|
|
|
1252
|
map { $_->basename } |
21
|
372
|
|
|
|
|
24010
|
grep { ! $_->is_dir } |
22
|
186
|
|
|
|
|
51094
|
map { $_->children( no_hidden => 1 ) } |
23
|
784
|
|
|
|
|
16782
|
grep { -d $_ } |
24
|
62
|
|
|
62
|
|
181
|
map { dir $_, 'Clustericious', 'Coder' } @INC; |
|
784
|
|
|
|
|
30318
|
|
25
|
62
|
|
|
|
|
1463
|
[ keys %coders ]; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub register |
29
|
|
|
|
|
|
|
{ |
30
|
62
|
|
|
62
|
1
|
7101
|
my ($self, $app, $conf) = @_; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
my @coders = $app->isa('Clustericious::App') |
33
|
|
|
|
|
|
|
? $app->config->coders( default => __PACKAGE__->_default_coders ) |
34
|
62
|
100
|
33
|
|
|
565
|
: @{ $conf->{coders} // __PACKAGE__->_default_coders }; |
|
2
|
|
|
|
|
16
|
|
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my %types = ( |
37
|
|
|
|
|
|
|
'application/x-www-form-urlencoded' => { |
38
|
2
|
|
|
2
|
|
59
|
decode => sub { my ($data, $c) = @_; $c->req->params->to_hash } |
|
2
|
|
|
|
|
7
|
|
39
|
|
|
|
|
|
|
} |
40
|
62
|
|
|
|
|
454
|
); |
41
|
62
|
|
|
|
|
131
|
my %formats; |
42
|
|
|
|
|
|
|
|
43
|
62
|
|
|
|
|
148
|
foreach my $coder (@coders) |
44
|
|
|
|
|
|
|
{ |
45
|
124
|
|
|
|
|
2693
|
require join('/', qw( Clustericious Coder ), "$coder.pm"); |
46
|
124
|
|
|
|
|
759
|
my $coder = join('::', qw( Clustericious Coder ), $coder)->coder; |
47
|
|
|
|
|
|
|
$types{$coder->{type}} = { |
48
|
|
|
|
|
|
|
maybe encode => $coder->{encode}, |
49
|
|
|
|
|
|
|
maybe decode => $coder->{decode}, |
50
|
|
|
|
|
|
|
}, |
51
|
|
|
|
|
|
|
$formats{$coder->{format}} = $coder->{type} |
52
|
124
|
50
|
|
|
|
954
|
if $coder->{format}; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
62
|
|
50
|
|
|
329
|
my $default_decode = $conf->{default_decode} // 'application/x-www-form-urlencoded'; |
56
|
62
|
|
50
|
|
|
241
|
my $default_encode = $conf->{default_encode} // 'application/json'; # TODO: not used |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
my $find_type = sub { |
59
|
35
|
|
|
35
|
|
260
|
my ($c) = @_; |
60
|
|
|
|
|
|
|
|
61
|
35
|
|
|
|
|
120
|
my $headers = $c->tx->req->content->headers; |
62
|
|
|
|
|
|
|
|
63
|
35
|
|
100
|
|
|
610
|
foreach my $type (map { /^([^;]*)/ } # get only stuff before ; |
|
45
|
|
100
|
|
|
1020
|
|
64
|
|
|
|
|
|
|
split(',', $headers->header('Accept') || ''), |
65
|
|
|
|
|
|
|
$headers->content_type || '') |
66
|
|
|
|
|
|
|
{ |
67
|
37
|
100
|
100
|
|
|
196
|
return $type if $types{$type} and $types{$type}->{encode}; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
23
|
|
100
|
|
|
94
|
my $format = $c->stash->{format} // 'json'; |
71
|
23
|
100
|
|
|
|
320
|
$format = 'json' unless $formats{$format}; |
72
|
|
|
|
|
|
|
|
73
|
23
|
|
|
|
|
70
|
$formats{$format}; |
74
|
62
|
|
|
|
|
258
|
}; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
$app->renderer->add_handler('autodata' => sub { |
78
|
35
|
|
|
35
|
|
4141
|
my ($r, $c, $output, $data) = @_; |
79
|
|
|
|
|
|
|
|
80
|
35
|
|
|
|
|
109
|
my $type = $find_type->($c); |
81
|
35
|
50
|
|
|
|
133
|
LOGDIE "no encoder for $type" unless $types{$type}->{encode}; |
82
|
35
|
|
|
|
|
110
|
$$output = $types{$type}->{encode}->($c->stash("autodata")); |
83
|
35
|
|
|
|
|
150
|
$c->tx->res->headers->content_type($type); |
84
|
62
|
|
|
|
|
285
|
}); |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
my $parse_autodata = sub { |
87
|
6
|
|
|
6
|
|
269
|
my ($c) = @_; |
88
|
|
|
|
|
|
|
|
89
|
6
|
|
33
|
|
|
24
|
my $content_type = $c->req->headers->content_type || $default_decode; |
90
|
6
|
100
|
|
|
|
184
|
if ($content_type =~ /^([^;]+);/) { |
91
|
|
|
|
|
|
|
# strip charset |
92
|
1
|
|
|
|
|
5
|
$content_type = $1; |
93
|
|
|
|
|
|
|
} |
94
|
6
|
|
33
|
|
|
28
|
my $entry = $types{$content_type} || $types{$default_decode}; |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# TODO: avoid passing $c in, only used by |
97
|
|
|
|
|
|
|
# application/x-www-form-urlencoded above |
98
|
6
|
|
|
|
|
19
|
$c->stash->{autodata} = $entry->{decode}->($c->req->body, $c); |
99
|
62
|
|
|
|
|
1540
|
}; |
100
|
|
|
|
|
|
|
|
101
|
62
|
|
|
|
|
216
|
$app->plugins->on( parse_autodata => $parse_autodata ); |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
$app->plugins->on( add_autodata_type => sub { |
104
|
0
|
|
|
0
|
|
0
|
my($plugins, $args) = @_; |
105
|
|
|
|
|
|
|
|
106
|
0
|
0
|
|
|
|
0
|
LOGDIE "No extension provided" unless defined $args->{extension}; |
107
|
0
|
|
|
|
|
0
|
my $ext = $args->{extension}; |
108
|
0
|
|
0
|
|
|
0
|
my $mime = $args->{mime_type} // 'application/x-' . $ext; |
109
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
0
|
$formats{$ext} = $mime; |
111
|
|
|
|
|
|
|
|
112
|
0
|
0
|
|
|
|
0
|
if(defined $args->{encode}) { |
113
|
0
|
|
|
|
|
0
|
$types{$mime}->{encode} = $args->{encode}; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
0
|
0
|
|
|
|
0
|
if(defined $args->{decode}) { |
117
|
0
|
|
|
|
|
0
|
$types{$mime}->{decode} = $args->{decode}; |
118
|
|
|
|
|
|
|
} |
119
|
62
|
|
|
|
|
754
|
}); |
120
|
|
|
|
|
|
|
|
121
|
62
|
|
|
|
|
766
|
$app->helper( parse_autodata => $parse_autodata ); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
$app->hook(before_render => sub { |
124
|
175
|
|
|
175
|
|
23538
|
my($c, $args) = @_; |
125
|
175
|
100
|
100
|
|
|
491
|
$c->stash->{handler} = "autodata" if exists($c->stash->{autodata}) || exists($args->{autodata}); |
126
|
62
|
|
|
|
|
1239
|
}); |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
1; |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
__END__ |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
=pod |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=encoding UTF-8 |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=head1 NAME |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Clustericious::Plugin::AutodataHandler - Handle data types automatically |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head1 VERSION |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
version 1.27 |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=head1 SYNOPSIS |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
package YourApp::Routes; |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
use Clustericious::RouteBuilder; |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
get '/some/route' => sub { |
152
|
|
|
|
|
|
|
my $c = shift; |
153
|
|
|
|
|
|
|
$c->stash->{autodata} = { x => 1, y => 'hello, z => [1,2,3] }; |
154
|
|
|
|
|
|
|
}; |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
=head1 DESCRIPTION |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
Adds a renderer that automatically serializes that "autodata" in the |
159
|
|
|
|
|
|
|
stash into a format based on HTTP Accept and Content-Type headers. |
160
|
|
|
|
|
|
|
Also adds a helper called C<parse_autodata> that handles incoming data by |
161
|
|
|
|
|
|
|
Content-Type. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
Supports application/json, text/x-yaml and |
164
|
|
|
|
|
|
|
application/x-www-form-urlencoded (in-bound only). |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
When C<parse_autodata> is called from within a route like this: |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
$self->parse_autodata; |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
POST data is parsed according to the type in the 'Content-Type' |
171
|
|
|
|
|
|
|
header with the data left in stash->{autodata}. It is also |
172
|
|
|
|
|
|
|
returned by the above call. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
If a route leaves data in stash->{autodata}, it is rendered by this |
175
|
|
|
|
|
|
|
handler, which chooses the type with the first acceptable type listed |
176
|
|
|
|
|
|
|
in the Accept header, the Content-Type header, or the default. (By |
177
|
|
|
|
|
|
|
default, the default is application/json, but you can override that |
178
|
|
|
|
|
|
|
too). |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head1 AUTHOR |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
Original author: Brian Duggan |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Current maintainer: Graham Ollis E<lt>plicease@cpan.orgE<gt> |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Contributors: |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Curt Tilmes |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
Yanick Champoux |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
This software is copyright (c) 2013 by NASA GSFC. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
197
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=cut |