Skip to content

Commit d1bd9ee

Browse files
committed
use tempdir for multipart ref:plack/Plack#537
1 parent f1c30fe commit d1bd9ee

6 files changed

Lines changed: 71 additions & 71 deletions

File tree

Build.PL

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ use utf8;
1212
use Module::Build;
1313
use File::Basename;
1414
use File::Spec;
15-
use CPAN::Meta;
16-
use CPAN::Meta::Prereqs;
1715

1816
my %args = (
1917
license => 'perl',
@@ -34,7 +32,7 @@ my %args = (
3432
test_files => ((-d '.git' || $ENV{RELEASE_TESTING}) && -d 'xt') ? 't/ xt/' : 't/',
3533
recursive_test_files => 1,
3634

37-
35+
3836
);
3937
if (-d 'share') {
4038
$args{share_dir} = 'share';
@@ -53,20 +51,15 @@ my $builder = Module::Build->subclass(
5351
)->new(%args);
5452
$builder->create_build_script();
5553

56-
my $mbmeta = CPAN::Meta->load_file('MYMETA.json');
57-
my $meta = CPAN::Meta->load_file('META.json');
58-
my $prereqs_hash = CPAN::Meta::Prereqs->new(
59-
$meta->prereqs
60-
)->with_merged_prereqs(
61-
CPAN::Meta::Prereqs->new($mbmeta->prereqs)
62-
)->as_string_hash;
63-
my $mymeta = CPAN::Meta->new(
64-
{
65-
%{$meta->as_struct},
66-
prereqs => $prereqs_hash
67-
}
68-
);
69-
print "Merging cpanfile prereqs to MYMETA.yml\n";
70-
$mymeta->save('MYMETA.yml', { version => 1.4 });
71-
print "Merging cpanfile prereqs to MYMETA.json\n";
72-
$mymeta->save('MYMETA.json', { version => 2 });
54+
use File::Copy;
55+
56+
print "cp META.json MYMETA.json\n";
57+
copy("META.json","MYMETA.json") or die "Copy failed(META.json): $!";
58+
59+
if (-f 'META.yml') {
60+
print "cp META.yml MYMETA.yml\n";
61+
copy("META.yml","MYMETA.yml") or die "Copy failed(META.yml): $!";
62+
} else {
63+
print "There is no META.yml... You may install this module from the repository...\n";
64+
}
65+

META.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"Masahiro Nagano <kazeburo@gmail.com>"
55
],
66
"dynamic_config" : 0,
7-
"generated_by" : "Minilla/v0.11.0, CPAN::Meta::Converter version 2.132830",
7+
"generated_by" : "Minilla/v2.4.1, CPAN::Meta::Converter version 2.141170",
88
"license" : [
99
"perl_5"
1010
],
@@ -28,15 +28,14 @@
2828
"prereqs" : {
2929
"configure" : {
3030
"requires" : {
31-
"CPAN::Meta" : "0",
32-
"CPAN::Meta::Prereqs" : "0",
3331
"Module::Build" : "0.38"
3432
}
3533
},
3634
"develop" : {
3735
"requires" : {
3836
"Test::CPAN::Meta" : "0",
39-
"Test::MinimumVersion" : "0.10108",
37+
"Test::MinimumVersion::Fast" : "0.04",
38+
"Test::PAUSE::Permissions" : "0.04",
4039
"Test::Pod" : "1.41",
4140
"Test::Spellunker" : "v0.2.7"
4241
}

README.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ HTTP::Entity::Parser - PSGI compliant HTTP Entity Parser
66

77
use HTTP::Entity::Parser;
88

9-
109
my $parser = HTTP::Entity::Parser->new;
1110
$parser->register('application/x-www-form-urlencoded','HTTP::Entity::Parser::UrlEncoded');
1211
$parser->register('multipart/form-data','HTTP::Entity::Parser::MultiPart');
@@ -20,12 +19,10 @@ HTTP::Entity::Parser - PSGI compliant HTTP Entity Parser
2019
# DESCRIPTION
2120

2221
HTTP::Entity::Parser is PSGI compliant HTTP Entity parser. This module also has compatibility
23-
with [HTTP::Body](http://search.cpan.org/perldoc?HTTP::Body). Unlike HTTP::Body, HTTP::Entity::Parser reads HTTP entity from
22+
with [HTTP::Body](https://metacpan.org/pod/HTTP::Body). Unlike HTTP::Body, HTTP::Entity::Parser reads HTTP entity from
2423
PSGI's env `$env->{'psgi.input'}` and parse it.
2524
This module support application/x-www-form-urlencoded, multipart/form-data and application/json.
2625

27-
28-
2926
# METHODS
3027

3128
- new()
@@ -93,7 +90,7 @@ This module support application/x-www-form-urlencoded, multipart/form-data and a
9390

9491
For `multipart/form-data`. It is used for HTTP POST contains file upload.
9592

96-
MultiPart parser use [HTTP::MultiPartParser](http://search.cpan.org/perldoc?HTTP::MultiPartParser).
93+
MultiPart parser use [HTTP::MultiPartParser](https://metacpan.org/pod/HTTP::MultiPartParser).
9794

9895
- JSON
9996

@@ -109,10 +106,10 @@ HTTP::Entity::Parser is able to choose parsers by the instance, HTTP::Body requi
109106

110107
# SEE ALSO
111108

112-
- [HTTP::Body](http://search.cpan.org/perldoc?HTTP::Body)
113-
- [HTTP::MultiPartParser](http://search.cpan.org/perldoc?HTTP::MultiPartParser)
114-
- [Plack::Request](http://search.cpan.org/perldoc?Plack::Request)
115-
- [WWW::Form::UrlEncoded](http://search.cpan.org/perldoc?WWW::Form::UrlEncoded)
109+
- [HTTP::Body](https://metacpan.org/pod/HTTP::Body)
110+
- [HTTP::MultiPartParser](https://metacpan.org/pod/HTTP::MultiPartParser)
111+
- [Plack::Request](https://metacpan.org/pod/Plack::Request)
112+
- [WWW::Form::UrlEncoded](https://metacpan.org/pod/WWW::Form::UrlEncoded)
116113

117114
HTTP::Entity::Parser uses this for parse application/x-www-form-urlencoded
118115

lib/HTTP/Entity/Parser.pm

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ sub parse {
4949
last;
5050
}
5151
}
52-
52+
5353
if ( !$parser ) {
5454
$parser = HTTP::Entity::Parser::OctetStream->new();
5555
}
@@ -74,7 +74,6 @@ sub parse {
7474
$cl -= $read;
7575
$parser->add($chunk);
7676
$buffer->print($chunk) if $buffer;
77-
7877
if ($read == 0 && $spin++ > 2000) {
7978
Carp::croak "Bad Content-Length: maybe client disconnect? ($cl bytes remaining)";
8079
}
@@ -99,7 +98,7 @@ sub parse {
9998
$parser->add($loaded);
10099
$buffer->print($loaded);
101100
$chunk_buffer =~ s/^\015\012//;
102-
$length += $chunk_len;
101+
$length += $chunk_len;
103102
}
104103
}
105104
$env->{CONTENT_LENGTH} = $length;

lib/HTTP/Entity/Parser/MultiPart.pm

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ sub new {
2323
}
2424
my $boundary = $1;
2525

26+
my $template = File::Spec->catdir(File::Spec->tmpdir, "HTTP-Entity-Parser-MultiPart-XXXXX");
27+
my $dir = File::Temp->newdir($template, CLEANUP => 1);
28+
# Temporary dir will remove after the request.
29+
push @{$env->{'http.entity.parser.multipart.tempdir'}}, $dir;
30+
$self->{tempdir} = "$dir";
31+
2632
my $part;
2733
my $parser = HTTP::MultiPartParser->new(
2834
boundary => $boundary,
@@ -51,12 +57,9 @@ sub new {
5157

5258
if ( exists $disposition_param{filename}) {
5359
$part->{filename} = $disposition_param{filename};
54-
my ($tempfh, $tempname) = tempfile(UNLINK => 1);
60+
my ($tempfh, $tempname) = tempfile(UNLINK => 0, DIR => $self->{tempdir});
5561
$part->{fh} = $tempfh;
5662
$part->{tempname} = $tempname;
57-
# Save temporary files to $env.
58-
# Temporary files will remove after the request.
59-
push @{$env->{'http.entity.parser.multipart.filehandles'}}, $part->{fh};
6063
}
6164
},
6265
on_body => sub {

t/01_content_type/multipart.t

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use HTTP::Entity::Parser::MultiPart;
55
use Hash::MultiValue;
66
use HTTP::Headers;
77
use t::Util;
8+
use File::Basename;
89

910
my $content = qq{------BOUNDARY
1011
Content-Disposition: form-data; name="hoge"
@@ -59,41 +60,49 @@ SHOGUN6
5960
$content =~ s/\r\n/\n/g;
6061
$content =~ s/\n/\r\n/g;
6162

62-
my $env = {
63-
CONTENT_LENGTH => length($content),
64-
CONTENT_TYPE => 'multipart/form-data; boundary=----BOUNDARY',
65-
};
66-
67-
# read from file.
68-
my $parser = HTTP::Entity::Parser::MultiPart->new($env);
69-
$parser->add($_) for split //, $content;
70-
my ($params, $uploads) = $parser->finalize();
71-
72-
is_deeply( Hash::MultiValue->new(@$params)->as_hashref_multi, {
73-
hoge => ['fuga', 'hige'],
74-
nobuko => ['iwaki'],
75-
});
76-
77-
$uploads = Hash::MultiValue->new(@$uploads);
78-
79-
my @test_upload_file = $uploads->get_all('test_upload_file');
80-
is 0+@test_upload_file, 2;
81-
is slurp($test_upload_file[0]->{tempname}), 'SHOGUN';
82-
is slurp($test_upload_file[1]->{tempname}), 'SHOGUN2';
63+
my $tmpdir;
8364

8465
{
85-
my $test_upload_file3 = $uploads->{'test_upload_file3'};
86-
is slurp($test_upload_file3->{tempname}), 'SHOGUN3';
87-
88-
my @test_upload_file6 = $uploads->{'test_upload_file6'};
89-
is slurp($test_upload_file6[0]->{tempname}), 'SHOGUN6';
90-
my $header = HTTP::Headers->new(@{$test_upload_file6[0]->{headers}});
91-
is $header->header('Content-Type'), 'text/plain';
92-
is $header->content_type, 'text/plain';
93-
is $header->header('X'), 'Y:Z';
94-
is $header->header('Foo'), 'bar baz';
66+
my $env = {
67+
CONTENT_LENGTH => length($content),
68+
CONTENT_TYPE => 'multipart/form-data; boundary=----BOUNDARY',
69+
};
70+
71+
# read from file.
72+
my $parser = HTTP::Entity::Parser::MultiPart->new($env);
73+
$parser->add($_) for split //, $content;
74+
my ($params, $uploads) = $parser->finalize();
75+
76+
is_deeply( Hash::MultiValue->new(@$params)->as_hashref_multi, {
77+
hoge => ['fuga', 'hige'],
78+
nobuko => ['iwaki'],
79+
});
80+
81+
$uploads = Hash::MultiValue->new(@$uploads);
82+
83+
my @test_upload_file = $uploads->get_all('test_upload_file');
84+
is 0+@test_upload_file, 2;
85+
is slurp($test_upload_file[0]->{tempname}), 'SHOGUN';
86+
is slurp($test_upload_file[1]->{tempname}), 'SHOGUN2';
87+
88+
{
89+
my $test_upload_file3 = $uploads->{'test_upload_file3'};
90+
is slurp($test_upload_file3->{tempname}), 'SHOGUN3';
91+
92+
my @test_upload_file6 = $uploads->{'test_upload_file6'};
93+
is slurp($test_upload_file6[0]->{tempname}), 'SHOGUN6';
94+
my $header = HTTP::Headers->new(@{$test_upload_file6[0]->{headers}});
95+
is $header->header('Content-Type'), 'text/plain';
96+
is $header->content_type, 'text/plain';
97+
is $header->header('X'), 'Y:Z';
98+
is $header->header('Foo'), 'bar baz';
99+
}
100+
101+
$tmpdir = dirname($test_upload_file[0]->{tempname});
95102
}
96103

104+
ok(! -d $tmpdir);
105+
97106
done_testing();
98107

99108

0 commit comments

Comments
 (0)