8a882c3a6d9018a4b2dd75bce458478418f7ce47
[catagits/Catalyst-Action-REST.git] / lib / Catalyst / Action / DeserializeMultiPart.pm
1 package Catalyst::Action::DeserializeMultiPart;
2
3 use Moose;
4 use namespace::autoclean;
5
6 extends 'Catalyst::Action::Deserialize';
7 use HTTP::Body;
8
9 our $VERSION = '0.91';
10 $VERSION = eval $VERSION;
11
12 our $NO_HTTP_BODY_TYPES_INITIALIZATION;
13 $HTTP::Body::TYPES->{'multipart/mixed'} = 'HTTP::Body::MultiPart' unless $NO_HTTP_BODY_TYPES_INITIALIZATION;
14
15 override execute => sub {
16     my $self = shift;
17     my ( $controller, $c ) = @_;
18     if($c->request->content_type =~ m{^multipart/}i && !defined($c->request->body)){
19         my $REST_part = $self->attributes->{DeserializePart} || [];
20         my($REST_body) = $c->request->upload($REST_part->[0] || 'REST');
21         if($REST_body){
22             $c->request->_body->body( $REST_body->fh );
23             $c->request->content_type( $REST_body->type );
24         }
25     }
26     super;
27 };
28
29 __PACKAGE__->meta->make_immutable;
30
31 1;
32
33 =head1 NAME
34
35 Catalyst::Action::DeserializeMultiPart - Deserialize Data in a Multi-Part Request
36
37 =head1 SYNOPSIS
38
39     package Foo::Controller::Bar;
40
41     __PACKAGE__->config(
42         # see Catalyst::Action::Deserialize for standard config
43     );
44
45     sub begin :ActionClass('DeserializeMultiPart') DeserializePart('REST') {}
46
47 =head1 DESCRIPTION
48
49 This action will deserialize multi-part HTTP POST, PUT, OPTIONS and DELETE
50 requests.  It is a simple extension of L<Catalyst::Action::Deserialize>
51 with the exception that rather than using the entire request body (which
52 may contain multiple sections), it will look for a single part in the request
53 body named according to the C<DeserializePart> attribute on that action
54 (defaulting to C<REST>).  If a part is found under that name, it then
55 proceeds to deserialize the request as normal based on the content-type
56 of that individual part.  If no such part is found, the request would
57 be processed as if no data was sent.
58
59 This module's code will only come into play if the following conditions are met:
60
61 =over 4
62
63 =item * The C<Content-type> of the request is C<multipart/*>
64
65 =item * The request body (as returned by C<$c->request->body> is not defined
66
67 =item * There is a part of the request body (as returned by C<$c->request->upload($DeserializePart)>) available
68
69 =back
70
71 =head1 CONFIGURING HTTP::Body
72
73 By default, L<HTTP::Body> parses C<multipart/*> requests as an
74 L<HTTP::Body::OctetStream>.  L<HTTP::Body::OctetStream> does not separate
75 out the individual parts of the request body.  In order to make use of
76 the individual parts, L<HTTP::Body> must be told which content types
77 to map to L<HTTP::Body::MultiPart>.  This module makes the assumption
78 that you would like to have all C<multipart/mixed> requests parsed by
79 L<HTTP::Body::MultiPart> module.  This is done by a package variable
80 inside L<HTTP::Body>: C<$HTTP::Body::Types> (a HASH ref).  Feel free to
81 add other content-types to this hash if needed or if you would prefer
82 that C<multipart/mixed> NOT be added to this hash, simply delete it
83 after loading this module.
84
85     # in your controller
86     use Catalyst::Action::DeserializeMultiPart;
87
88     delete $HTTP::Body::Types->{'multipart/mixed'};
89     $HTTP::Body::Types->{'multipart/my-crazy-content-type'} = 'HTTP::Body::MultiPart';
90
91 =head1 SEE ALSO
92
93 This is a simple sub-class of L<Catalyst::Action::Deserialize>.
94
95 =head1 AUTHORS
96
97 See L<Catalyst::Action::REST> for authors.
98
99 =head1 LICENSE
100
101 You may distribute this code under the same terms as Perl itself.
102
103 =cut