File Coverage

blib/lib/HTTP/Body/Builder/MultiPart.pm
Criterion Covered Total %
statement 66 75 88.0
branch 13 20 65.0
condition n/a
subroutine 14 15 93.3
pod 5 7 71.4
total 98 117 83.7


line stmt bran cond sub pod time code
1             package HTTP::Body::Builder::MultiPart;
2 1     1   20788 use strict;
  1         2  
  1         27  
3 1     1   4 use warnings;
  1         2  
  1         24  
4 1     1   5 use utf8;
  1         2  
  1         5  
5 1     1   45 use 5.008_005;
  1         4  
6              
7 1     1   5 use File::Basename ();
  1         2  
  1         841  
8              
9             my $CRLF = "\015\012";
10              
11             sub new {
12 6     6 1 9550 my $class = shift;
13 6 50       22 my %args = @_==1 ? %{$_[0]} : @_;
  0         0  
14 6         11 my $content = delete $args{content};
15 6         12 my $files = delete $args{files};
16 6         22 my $self = bless {
17             boundary => 'xYzZY',
18             buffer_size => 2048,
19             %args
20             }, $class;
21 6 100       16 if ($content) {
22 1         2 for my $key (keys %{$content}) {
  1         3  
23 1 50       5 for my $value (ref $content->{$key} ? @{$content->{$key}} : $content->{$key}) {
  0         0  
24 1         3 $self->add_content($key => $value);
25             }
26             }
27             }
28 6 100       13 if ($files) {
29 1         2 for my $name (keys %{$files}) {
  1         3  
30 1         4 $self->add_file($name => $files->{$name});
31             }
32             }
33 6         19 return $self;
34             }
35              
36             sub add_content {
37 6     6 1 25 my ($self, $name, $value) = @_;
38 6         7 push @{$self->{content}}, [$name, $value];
  6         27  
39             }
40              
41             sub add_file {
42 5     5 1 18 my ($self, $name, $filename) = @_;
43 5         7 push @{$self->{file}}, [$name, $filename];
  5         16  
44             }
45              
46             sub content_type {
47 4     4 0 16 my $self = shift;
48 4         16 return 'multipart/form-data';
49             }
50              
51             sub _gen {
52 6     6   11 my ($self, $code) = @_;
53              
54 6         8 for my $row (@{$self->{content}}) {
  6         16  
55 6         31 $code->(join('', "--$self->{boundary}$CRLF",
56             qq{Content-Disposition: form-data; name="$row->[0]"$CRLF},
57             "$CRLF",
58             $row->[1] . $CRLF
59             ));
60             }
61 6         9 for my $row (@{$self->{file}}) {
  6         14  
62 5         153 my $filename = File::Basename::basename($row->[1]);
63 5         28 $code->(join('', "--$self->{boundary}$CRLF",
64             qq{Content-Disposition: form-data; name="$row->[0]"; filename="$filename"$CRLF},
65             "Content-Type: text/plain$CRLF",
66             "$CRLF",
67             ));
68             open my $fh, '<:raw', $row->[1]
69 5 50       187 or do {
70 0         0 $self->{errstr} = "Cannot open '$row->[1]' for reading: $!";
71 0         0 return;
72             };
73 5         9 my $buf;
74 5         7 while (1) {
75 10         95 my $r = read $fh, $buf, $self->{buffer_size};
76 10 50       28 if (not defined $r) {
    100          
77 0         0 $self->{errstr} = "Cannot open '$row->[1]' for reading: $!";
78 0         0 return;
79             } elsif ($r == 0) { # eof
80 5         9 last;
81             } else {
82 5         10 $code->($buf);
83             }
84             }
85 5         8 $code->($CRLF);
86             }
87 6         20 $code->("--$self->{boundary}--$CRLF");
88 6         21 return 1;
89             }
90              
91             sub as_string {
92 5     5 1 16 my ($self) = @_;
93 5         8 my $buf = '';
94 22     22   83 $self->_gen(sub { $buf .= $_[0] })
95 5 50       24 or return;
96 5         62 $buf;
97             }
98              
99 0     0 0 0 sub errstr { shift->{errstr} }
100              
101             sub write_file {
102 1     1 1 722 my ($self, $filename) = @_;
103              
104             open my $fh, '>:raw', $filename
105 1 50       49 or do {
106 0         0 $self->{errstr} = "Cannot open '$filename' for writing: $!";
107 0         0 return;
108             };
109 5     5   6 $self->_gen(sub { print {$fh} $_[0] })
  5         22  
110 1 50       7 or return;
111 1         48 close $fh;
112             }
113              
114             1;
115             __END__