10 'application/octet-stream' => 'HTTP::Body::OctetStream',
11 'application/x-www-form-urlencoded' => 'HTTP::Body::UrlEncoded',
12 'multipart/form-data' => 'HTTP::Body::MultiPart',
13 'multipart/related' => 'HTTP::Body::XFormsMultipart',
14 'application/xml' => 'HTTP::Body::XForms'
17 require HTTP::Body::OctetStream;
18 require HTTP::Body::UrlEncoded;
19 require HTTP::Body::MultiPart;
20 require HTTP::Body::XFormsMultipart;
21 require HTTP::Body::XForms;
28 HTTP::Body - HTTP Body Parser
34 sub handler : method {
35 my ( $class, $r ) = @_;
37 my $content_type = $r->headers_in->get('Content-Type');
38 my $content_length = $r->headers_in->get('Content-Length');
40 my $body = HTTP::Body->new( $content_type, $content_length );
41 my $length = $content_length;
45 $r->read( my $buffer, ( $length < 8192 ) ? $length : 8192 );
47 $length -= length($buffer);
52 my $uploads = $body->upload; # hashref
53 my $params = $body->param; # hashref
54 my $body = $body->body; # IO::Handle
59 HTTP::Body parses chunks of HTTP POST data and supports
60 application/octet-stream, application/x-www-form-urlencoded, and
63 Chunked bodies are supported by not passing a length value to new().
65 It is currently used by L<Catalyst> to parse POST bodies.
69 When parsing multipart bodies, temporary files are created to store any
70 uploaded files. You must delete these temporary files yourself after
79 Constructor. Takes content type and content length as parameters,
80 returns a L<HTTP::Body> object.
85 my ( $class, $content_type, $content_length ) = @_;
88 Carp::croak( $class, '->new( $content_type, [ $content_length ] )' );
92 foreach my $supported ( keys %{$TYPES} ) {
93 if ( index( lc($content_type), $supported ) >= 0 ) {
98 my $body = $TYPES->{ $type || 'application/octet-stream' };
100 eval "require $body";
110 chunked => !defined $content_length,
111 content_length => defined $content_length ? $content_length : -1,
112 content_type => $content_type,
115 state => 'buffering',
117 tmpdir => File::Spec->tmpdir(),
120 bless( $self, $body );
127 Add string to internal buffer. Will call spin unless done. returns
128 length before adding self.
135 if ( $self->{chunked} ) {
136 $self->{chunk_buffer} .= $_[0];
138 while ( $self->{chunk_buffer} =~ m/^([\da-fA-F]+).*\x0D\x0A/ ) {
139 my $chunk_len = hex($1);
141 if ( $chunk_len == 0 ) {
143 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
145 # End of data, there may be trailing headers
146 if ( my ($headers) = $self->{chunk_buffer} =~ m/(.*)\x0D\x0A/s ) {
147 if ( my $message = HTTP::Message->parse( $headers ) ) {
148 $self->{trailing_headers} = $message->headers;
152 $self->{chunk_buffer} = '';
154 # Set content_length equal to the amount of data we read,
155 # so the spin methods can finish up.
156 $self->{content_length} = $self->{length};
159 # Make sure we have the whole chunk in the buffer (+CRLF)
160 if ( length( $self->{chunk_buffer} ) >= $chunk_len ) {
162 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
164 # Pull chunk data out of chunk buffer into real buffer
165 $self->{buffer} .= substr $self->{chunk_buffer}, 0, $chunk_len, '';
167 # Strip remaining CRLF
168 $self->{chunk_buffer} =~ s/^\x0D\x0A//;
170 $self->{length} += $chunk_len;
173 # Not enough data for this chunk, wait for more calls to add()
178 unless ( $self->{state} eq 'done' ) {
186 my $cl = $self->content_length;
188 if ( defined $_[0] ) {
189 $self->{length} += length( $_[0] );
191 # Don't allow buffer data to exceed content-length
192 if ( $self->{length} > $cl ) {
193 $_[0] = substr $_[0], 0, $cl - $self->{length};
194 $self->{length} = $cl;
197 $self->{buffer} .= $_[0];
200 unless ( $self->state eq 'done' ) {
204 return ( $self->length - $cl );
209 accessor for the body.
215 $self->{body} = shift if @_;
216 return $self->{body};
221 Returns 1 if the request is chunked.
226 return shift->{chunked};
231 Returns the content-length for the body data if known.
232 Returns -1 if the request is chunked.
237 return shift->{content_length};
242 Returns the content-type of the body data.
247 return shift->{content_type};
262 Returns the total length of data we expect to read if known.
263 In the case of a chunked request, returns the amount of data
269 return shift->{length};
272 =item trailing_headers
274 If a chunked request body had trailing headers, trailing_headers will
275 return an HTTP::Headers object populated with those headers.
279 sub trailing_headers {
280 return shift->{trailing_headers};
285 Abstract method to spin the io handle.
290 Carp::croak('Define abstract method spin() in implementation');
295 Returns the current state of the parser.
301 $self->{state} = shift if @_;
302 return $self->{state};
307 Get/set body parameters.
316 my ( $name, $value ) = @_;
318 if ( exists $self->{param}->{$name} ) {
319 for ( $self->{param}->{$name} ) {
320 $_ = [$_] unless ref($_) eq "ARRAY";
325 $self->{param}->{$name} = $value;
329 return $self->{param};
334 Get/set file uploads.
343 my ( $name, $upload ) = @_;
345 if ( exists $self->{upload}->{$name} ) {
346 for ( $self->{upload}->{$name} ) {
347 $_ = [$_] unless ref($_) eq "ARRAY";
348 push( @$_, $upload );
352 $self->{upload}->{$name} = $upload;
356 return $self->{upload};
361 Specify a different path for temporary files. Defaults to the system temporary path.
367 $self->{tmpdir} = shift if @_;
368 return $self->{tmpdir};
375 Christian Hansen, C<ch@ngmedia.com>
377 Sebastian Riedel, C<sri@cpan.org>
379 Andy Grundman, C<andy@hybridized.org>
383 This library is free software. You can redistribute it and/or modify
384 it under the same terms as perl itself.