1 package HTTP::Body::MultiPart;
11 HTTP::Body::Multipart - HTTP Body MultipartParser
15 use HTTP::Body::Multipart;
19 HTTP Body Multipart Parser.
32 unless ( $self->content_type =~ /boundary=\"?([^\";,]+)\"?/ ) {
33 my $content_type = $self->content_type;
34 Carp::croak("Invalid boundary in content_type: '$content_type'");
37 $self->{boundary} = $1;
38 $self->{state} = 'preamble';
52 if ( $self->{state} =~ /^(preamble|boundary|header|body)$/ ) {
53 my $method = "parse_$1";
54 return unless $self->$method;
58 Carp::croak('Unknown state');
68 return shift->{boundary};
76 return "--" . shift->boundary;
84 return shift->boundary_begin . "--";
101 return $self->crlf . $self->boundary_begin;
110 return $self->crlf . $self->boundary_end;
120 my $index = index( $self->{buffer}, $self->boundary_begin );
122 unless ( $index >= 0 ) {
126 # replace preamble with CRLF so we can match dash-boundary as delimiter
127 substr( $self->{buffer}, 0, $index, $self->crlf );
129 $self->{state} = 'boundary';
141 if ( index( $self->{buffer}, $self->delimiter_begin . $self->crlf ) == 0 ) {
143 substr( $self->{buffer}, 0, length( $self->delimiter_begin ) + 2, '' );
145 $self->{state} = 'header';
150 if ( index( $self->{buffer}, $self->delimiter_end . $self->crlf ) == 0 ) {
152 substr( $self->{buffer}, 0, length( $self->delimiter_end ) + 2, '' );
154 $self->{state} = 'done';
169 my $crlf = $self->crlf;
170 my $index = index( $self->{buffer}, $crlf . $crlf );
172 unless ( $index >= 0 ) {
176 my $header = substr( $self->{buffer}, 0, $index );
178 substr( $self->{buffer}, 0, $index + 4, '' );
181 for ( split /$crlf/, $header ) {
190 my $token = qr/[^][\x00-\x1f\x7f()<>@,;:\\"\/?={} \t]+/;
192 for my $header (@headers) {
194 $header =~ s/^($token):[\t ]*//;
196 ( my $field = $1 ) =~ s/\b(\w)/uc($1)/eg;
198 if ( exists $self->{part}->{headers}->{$field} ) {
199 for ( $self->{part}->{headers}->{$field} ) {
200 $_ = [$_] unless ref($_) eq "ARRAY";
201 push( @$_, $header );
205 $self->{part}->{headers}->{$field} = $header;
209 $self->{state} = 'body';
221 my $index = index( $self->{buffer}, $self->delimiter_begin );
225 # make sure we have enough buffer to detect end delimiter
227 length( $self->{buffer} ) - ( length( $self->delimiter_end ) + 2 );
229 unless ( $length > 0 ) {
233 $self->{part}->{data} .= substr( $self->{buffer}, 0, $length, '' );
234 $self->{part}->{size} += $length;
235 $self->{part}->{done} = 0;
237 $self->handler( $self->{part} );
242 $self->{part}->{data} .= substr( $self->{buffer}, 0, $index, '' );
243 $self->{part}->{size} += $index;
244 $self->{part}->{done} = 1;
246 $self->handler( $self->{part} );
248 $self->{state} = 'boundary';
258 my ( $self, $part ) = @_;
260 # skip parts without content
261 if ( $part->{done} && $part->{size} == 0 ) {
265 unless ( $self->{seen}->{"$part"}++ ) {
267 my $disposition = $part->{headers}->{'Content-Disposition'};
268 my ($name) = $disposition =~ / name="?([^\";]+)"?/;
269 my ($filename) = $disposition =~ / filename="?([^\"]+)"?/;
271 $part->{name} = $name;
272 $part->{filename} = $filename;
276 my $fh = File::Temp->new( UNLINK => 0 );
279 $part->{tempname} = $fh->filename;
283 if ( $part->{filename} && ( my $length = length( $part->{data} ) ) ) {
284 $part->{fh}->write( substr( $part->{data}, 0, $length, '' ), $length );
287 if ( $part->{done} ) {
289 if ( $part->{filename} ) {
293 delete @{$part}{qw[ data done fh ]};
295 $self->upload( $part->{name}, $part );
299 $self->param( $part->{name}, $part->{data} );
308 Christian Hansen, C<ch@ngmedia.com>
312 This library is free software . You can redistribute it and/or modify
313 it under the same terms as perl itself.