8 'application/octet-stream' => 'HTTP::Body::OctetStream',
9 'application/x-www-form-urlencoded' => 'HTTP::Body::UrlEncoded',
10 'multipart/form-data' => 'HTTP::Body::MultiPart',
11 'multipart/related' => 'HTTP::Body::XFormsMultipart',
12 'application/xml' => 'HTTP::Body::XForms'
15 require HTTP::Body::OctetStream;
16 require HTTP::Body::UrlEncoded;
17 require HTTP::Body::MultiPart;
18 require HTTP::Body::XFormsMultipart;
19 require HTTP::Body::XForms;
26 HTTP::Body - HTTP Body Parser
32 sub handler : method {
33 my ( $class, $r ) = @_;
35 my $content_type = $r->headers_in->get('Content-Type');
36 my $content_length = $r->headers_in->get('Content-Length');
38 my $body = HTTP::Body->new( $content_type, $content_length );
39 my $length = $content_length;
43 $r->read( my $buffer, ( $length < 8192 ) ? $length : 8192 );
45 $length -= length($buffer);
50 my $uploads = $body->upload; # hashref
51 my $params = $body->param; # hashref
52 my $body = $body->body; # IO::Handle
57 HTTP::Body parses chunks of HTTP POST data and supports
58 application/octet-stream, application/x-www-form-urlencoded, and
61 Chunked bodies are supported by not passing a length value to new().
63 It is currently used by L<Catalyst> to parse POST bodies.
67 When parsing multipart bodies, temporary files are created to store any
68 uploaded files. You must delete these temporary files yourself after
69 processing them, or set $body->cleanup(1) to automatically delete them
78 Constructor. Takes content type and content length as parameters,
79 returns a L<HTTP::Body> object.
84 my ( $class, $content_type, $content_length ) = @_;
87 Carp::croak( $class, '->new( $content_type, [ $content_length ] )' );
91 foreach my $supported ( keys %{$TYPES} ) {
92 if ( index( lc($content_type), $supported ) >= 0 ) {
97 my $body = $TYPES->{ $type || 'application/octet-stream' };
104 chunked => !defined $content_length,
105 content_length => defined $content_length ? $content_length : -1,
106 content_type => $content_type,
109 state => 'buffering',
111 tmpdir => File::Spec->tmpdir(),
114 bless( $self, $body );
122 if ( $self->{cleanup} ) {
124 for my $upload ( values %{ $self->{upload} } ) {
125 push @temps, map { $_->{tempname} || () }
126 ( ref $upload eq 'ARRAY' ? @{$upload} : $upload );
129 unlink map { $_ } grep { -e $_ } @temps;
135 Add string to internal buffer. Will call spin unless done. returns
136 length before adding self.
143 if ( $self->{chunked} ) {
144 $self->{chunk_buffer} .= $_[0];
146 while ( $self->{chunk_buffer} =~ m/^([\da-fA-F]+).*\x0D\x0A/ ) {
147 my $chunk_len = hex($1);
149 if ( $chunk_len == 0 ) {
151 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
153 # End of data, there may be trailing headers
154 if ( my ($headers) = $self->{chunk_buffer} =~ m/(.*)\x0D\x0A/s ) {
155 if ( my $message = HTTP::Message->parse( $headers ) ) {
156 $self->{trailing_headers} = $message->headers;
160 $self->{chunk_buffer} = '';
162 # Set content_length equal to the amount of data we read,
163 # so the spin methods can finish up.
164 $self->{content_length} = $self->{length};
167 # Make sure we have the whole chunk in the buffer (+CRLF)
168 if ( length( $self->{chunk_buffer} ) >= $chunk_len ) {
170 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
172 # Pull chunk data out of chunk buffer into real buffer
173 $self->{buffer} .= substr $self->{chunk_buffer}, 0, $chunk_len, '';
175 # Strip remaining CRLF
176 $self->{chunk_buffer} =~ s/^\x0D\x0A//;
178 $self->{length} += $chunk_len;
181 # Not enough data for this chunk, wait for more calls to add()
186 unless ( $self->{state} eq 'done' ) {
194 my $cl = $self->content_length;
196 if ( defined $_[0] ) {
197 $self->{length} += length( $_[0] );
199 # Don't allow buffer data to exceed content-length
200 if ( $self->{length} > $cl ) {
201 $_[0] = substr $_[0], 0, $cl - $self->{length};
202 $self->{length} = $cl;
205 $self->{buffer} .= $_[0];
208 unless ( $self->state eq 'done' ) {
212 return ( $self->length - $cl );
217 accessor for the body.
223 $self->{body} = shift if @_;
224 return $self->{body};
229 Returns 1 if the request is chunked.
234 return shift->{chunked};
239 Set to 1 to enable automatic deletion of temporary files at DESTROY-time.
245 $self->{cleanup} = shift if @_;
246 return $self->{cleanup};
251 Returns the content-length for the body data if known.
252 Returns -1 if the request is chunked.
257 return shift->{content_length};
262 Returns the content-type of the body data.
267 return shift->{content_type};
282 Returns the total length of data we expect to read if known.
283 In the case of a chunked request, returns the amount of data
289 return shift->{length};
292 =item trailing_headers
294 If a chunked request body had trailing headers, trailing_headers will
295 return an HTTP::Headers object populated with those headers.
299 sub trailing_headers {
300 return shift->{trailing_headers};
305 Abstract method to spin the io handle.
310 Carp::croak('Define abstract method spin() in implementation');
315 Returns the current state of the parser.
321 $self->{state} = shift if @_;
322 return $self->{state};
327 Get/set body parameters.
336 my ( $name, $value ) = @_;
338 if ( exists $self->{param}->{$name} ) {
339 for ( $self->{param}->{$name} ) {
340 $_ = [$_] unless ref($_) eq "ARRAY";
345 $self->{param}->{$name} = $value;
349 return $self->{param};
354 Get/set file uploads.
363 my ( $name, $upload ) = @_;
365 if ( exists $self->{upload}->{$name} ) {
366 for ( $self->{upload}->{$name} ) {
367 $_ = [$_] unless ref($_) eq "ARRAY";
368 push( @$_, $upload );
372 $self->{upload}->{$name} = $upload;
376 return $self->{upload};
381 Specify a different path for temporary files. Defaults to the system temporary path.
387 $self->{tmpdir} = shift if @_;
388 return $self->{tmpdir};
395 Since its original creation this module has been taken over by the Catalyst
396 development team. If you want to contribute patches, these will be your
397 primary contact points:
401 Join #catalyst-dev on irc.perl.org.
405 http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
409 Christian Hansen, C<chansen@cpan.org>
411 Sebastian Riedel, C<sri@cpan.org>
413 Andy Grundman, C<andy@hybridized.org>
417 Simon Elliott C<cpan@papercreatures.com>
419 Kent Fredric <kentnl@cpan.org>
425 This library is free software. You can redistribute it and/or modify
426 it under the same terms as perl itself.