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' };
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 );
121 Add string to internal buffer. Will call spin unless done. returns
122 length before adding self.
129 if ( $self->{chunked} ) {
130 $self->{chunk_buffer} .= $_[0];
132 while ( $self->{chunk_buffer} =~ m/^([\da-fA-F]+).*\x0D\x0A/ ) {
133 my $chunk_len = hex($1);
135 if ( $chunk_len == 0 ) {
137 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
139 # End of data, there may be trailing headers
140 if ( my ($headers) = $self->{chunk_buffer} =~ m/(.*)\x0D\x0A/s ) {
141 if ( my $message = HTTP::Message->parse( $headers ) ) {
142 $self->{trailing_headers} = $message->headers;
146 $self->{chunk_buffer} = '';
148 # Set content_length equal to the amount of data we read,
149 # so the spin methods can finish up.
150 $self->{content_length} = $self->{length};
153 # Make sure we have the whole chunk in the buffer (+CRLF)
154 if ( length( $self->{chunk_buffer} ) >= $chunk_len ) {
156 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
158 # Pull chunk data out of chunk buffer into real buffer
159 $self->{buffer} .= substr $self->{chunk_buffer}, 0, $chunk_len, '';
161 # Strip remaining CRLF
162 $self->{chunk_buffer} =~ s/^\x0D\x0A//;
164 $self->{length} += $chunk_len;
167 # Not enough data for this chunk, wait for more calls to add()
172 unless ( $self->{state} eq 'done' ) {
180 my $cl = $self->content_length;
182 if ( defined $_[0] ) {
183 $self->{length} += length( $_[0] );
185 # Don't allow buffer data to exceed content-length
186 if ( $self->{length} > $cl ) {
187 $_[0] = substr $_[0], 0, $cl - $self->{length};
188 $self->{length} = $cl;
191 $self->{buffer} .= $_[0];
194 unless ( $self->state eq 'done' ) {
198 return ( $self->length - $cl );
203 accessor for the body.
209 $self->{body} = shift if @_;
210 return $self->{body};
215 Returns 1 if the request is chunked.
220 return shift->{chunked};
225 Returns the content-length for the body data if known.
226 Returns -1 if the request is chunked.
231 return shift->{content_length};
236 Returns the content-type of the body data.
241 return shift->{content_type};
256 Returns the total length of data we expect to read if known.
257 In the case of a chunked request, returns the amount of data
263 return shift->{length};
266 =item trailing_headers
268 If a chunked request body had trailing headers, trailing_headers will
269 return an HTTP::Headers object populated with those headers.
273 sub trailing_headers {
274 return shift->{trailing_headers};
279 Abstract method to spin the io handle.
284 Carp::croak('Define abstract method spin() in implementation');
289 Returns the current state of the parser.
295 $self->{state} = shift if @_;
296 return $self->{state};
301 Get/set body parameters.
310 my ( $name, $value ) = @_;
312 if ( exists $self->{param}->{$name} ) {
313 for ( $self->{param}->{$name} ) {
314 $_ = [$_] unless ref($_) eq "ARRAY";
319 $self->{param}->{$name} = $value;
323 return $self->{param};
328 Get/set file uploads.
337 my ( $name, $upload ) = @_;
339 if ( exists $self->{upload}->{$name} ) {
340 for ( $self->{upload}->{$name} ) {
341 $_ = [$_] unless ref($_) eq "ARRAY";
342 push( @$_, $upload );
346 $self->{upload}->{$name} = $upload;
350 return $self->{upload};
355 Specify a different path for temporary files. Defaults to the system temporary path.
361 $self->{tmpdir} = shift if @_;
362 return $self->{tmpdir};
369 Christian Hansen, C<ch@ngmedia.com>
371 Sebastian Riedel, C<sri@cpan.org>
373 Andy Grundman, C<andy@hybridized.org>
377 This library is free software. You can redistribute it and/or modify
378 it under the same terms as perl itself.