10 'application/octet-stream' => 'HTTP::Body::OctetStream',
11 'application/x-www-form-urlencoded' => 'HTTP::Body::UrlEncoded',
12 'multipart/form-data' => 'HTTP::Body::MultiPart'
15 require HTTP::Body::OctetStream;
16 require HTTP::Body::UrlEncoded;
17 require HTTP::Body::MultiPart;
24 HTTP::Body - HTTP Body Parser
30 sub handler : method {
31 my ( $class, $r ) = @_;
33 my $content_type = $r->headers_in->get('Content-Type');
34 my $content_length = $r->headers_in->get('Content-Length');
36 my $body = HTTP::Body->new( $content_type, $content_length );
37 my $length = $content_length;
41 $r->read( my $buffer, ( $length < 8192 ) ? $length : 8192 );
43 $length -= length($buffer);
48 my $uploads = $body->upload; # hashref
49 my $params = $body->param; # hashref
50 my $body = $body->body; # IO::Handle
55 HTTP::Body parses chunks of HTTP POST data and supports
56 application/octet-stream, application/x-www-form-urlencoded, and
59 Chunked bodies are supported by not passing a length value to new().
61 It is currently used by L<Catalyst> to parse POST bodies.
69 Constructor. Takes content type and content length as parameters,
70 returns a L<HTTP::Body> object.
75 my ( $class, $content_type, $content_length ) = @_;
78 Carp::croak( $class, '->new( $content_type, [ $content_length ] )' );
82 foreach my $supported ( keys %{$TYPES} ) {
83 if ( index( lc($content_type), $supported ) >= 0 ) {
88 my $body = $TYPES->{ $type || 'application/octet-stream' };
100 chunked => !defined $content_length,
101 content_length => defined $content_length ? $content_length : -1,
102 content_type => $content_type,
105 state => 'buffering',
109 bless( $self, $body );
116 Add string to internal buffer. Will call spin unless done. returns
117 length before adding self.
124 if ( $self->{chunked} ) {
125 $self->{chunk_buffer} .= $_[0];
127 while ( $self->{chunk_buffer} =~ m/^([\da-fA-F]+).*\x0D\x0A/ ) {
128 my $chunk_len = hex($1);
130 if ( $chunk_len == 0 ) {
132 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
134 # End of data, there may be trailing headers
135 if ( my ($headers) = $self->{chunk_buffer} =~ m/(.*)\x0D\x0A/s ) {
136 if ( my $message = HTTP::Message->parse( $headers ) ) {
137 $self->{trailing_headers} = $message->headers;
141 $self->{chunk_buffer} = '';
143 # Set content_length equal to the amount of data we read,
144 # so the spin methods can finish up.
145 $self->{content_length} = $self->{length};
148 # Make sure we have the whole chunk in the buffer (+CRLF)
149 if ( length( $self->{chunk_buffer} ) >= $chunk_len ) {
151 $self->{chunk_buffer} =~ s/^([\da-fA-F]+).*\x0D\x0A//;
153 # Pull chunk data out of chunk buffer into real buffer
154 $self->{buffer} .= substr $self->{chunk_buffer}, 0, $chunk_len, '';
156 # Strip remaining CRLF
157 $self->{chunk_buffer} =~ s/^\x0D\x0A//;
159 $self->{length} += $chunk_len;
162 # Not enough data for this chunk, wait for more calls to add()
167 unless ( $self->{state} eq 'done' ) {
175 my $cl = $self->content_length;
177 if ( defined $_[0] ) {
178 $self->{length} += length( $_[0] );
180 # Don't allow buffer data to exceed content-length
181 if ( $self->{length} > $cl ) {
182 $_[0] = substr $_[0], 0, $cl - $self->{length};
183 $self->{length} = $cl;
186 $self->{buffer} .= $_[0];
189 unless ( $self->state eq 'done' ) {
193 return ( $self->length - $cl );
198 accessor for the body.
204 $self->{body} = shift if @_;
205 return $self->{body};
210 Returns 1 if the request is chunked.
215 return shift->{chunked};
220 Returns the content-length for the body data if known.
221 Returns -1 if the request is chunked.
226 return shift->{content_length};
231 Returns the content-type of the body data.
236 return shift->{content_type};
251 Returns the total length of data we expect to read if known.
252 In the case of a chunked request, returns the amount of data
258 return shift->{length};
261 =item trailing_headers
263 If a chunked request body had trailing headers, trailing_headers will
264 return an HTTP::Headers object populated with those headers.
268 sub trailing_headers {
269 return shift->{trailing_headers};
274 Abstract method to spin the io handle.
279 Carp::croak('Define abstract method spin() in implementation');
284 Returns the current state of the parser.
290 $self->{state} = shift if @_;
291 return $self->{state};
296 Get/set body parameters.
305 my ( $name, $value ) = @_;
307 if ( exists $self->{param}->{$name} ) {
308 for ( $self->{param}->{$name} ) {
309 $_ = [$_] unless ref($_) eq "ARRAY";
314 $self->{param}->{$name} = $value;
318 return $self->{param};
323 Get/set file uploads.
332 my ( $name, $upload ) = @_;
334 if ( exists $self->{upload}->{$name} ) {
335 for ( $self->{upload}->{$name} ) {
336 $_ = [$_] unless ref($_) eq "ARRAY";
337 push( @$_, $upload );
341 $self->{upload}->{$name} = $upload;
345 return $self->{upload};
352 Christian Hansen, C<ch@ngmedia.com>
354 Sebastian Riedel, C<sri@cpan.org>
356 Andy Grundman, C<andy@hybridized.org>
360 This library is free software. You can redistribute it and/or modify
361 it under the same terms as perl itself.