line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## Asynchronous HTTP Request and Promise - ~/lib/HTTP/Promise/Headers/ContentDisposition.pm |
3
|
|
|
|
|
|
|
## Version v0.1.0 |
4
|
|
|
|
|
|
|
## Copyright(c) 2022 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
6
|
|
|
|
|
|
|
## Created 2022/05/07 |
7
|
|
|
|
|
|
|
## Modified 2022/05/07 |
8
|
|
|
|
|
|
|
## All rights reserved. |
9
|
|
|
|
|
|
|
## |
10
|
|
|
|
|
|
|
## |
11
|
|
|
|
|
|
|
## This program is free software; you can redistribute it and/or modify it |
12
|
|
|
|
|
|
|
## under the same terms as Perl itself. |
13
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
14
|
|
|
|
|
|
|
package HTTP::Promise::Headers::ContentDisposition; |
15
|
|
|
|
|
|
|
BEGIN |
16
|
|
|
|
|
|
|
{ |
17
|
7
|
|
|
7
|
|
3506
|
use strict; |
|
7
|
|
|
|
|
29
|
|
|
7
|
|
|
|
|
267
|
|
18
|
7
|
|
|
7
|
|
148
|
use warnings; |
|
7
|
|
|
|
|
19
|
|
|
7
|
|
|
|
|
273
|
|
19
|
7
|
|
|
7
|
|
51
|
use warnings::register; |
|
7
|
|
|
|
|
17
|
|
|
7
|
|
|
|
|
1596
|
|
20
|
7
|
|
|
7
|
|
53
|
use parent qw( HTTP::Promise::Headers::Generic ); |
|
7
|
|
|
|
|
12
|
|
|
7
|
|
|
|
|
58
|
|
21
|
7
|
|
|
7
|
|
719
|
our $VERSION = 'v0.1.0'; |
22
|
|
|
|
|
|
|
}; |
23
|
|
|
|
|
|
|
|
24
|
7
|
|
|
7
|
|
55
|
use strict; |
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
281
|
|
25
|
7
|
|
|
7
|
|
48
|
use warnings; |
|
7
|
|
|
|
|
17
|
|
|
7
|
|
|
|
|
5676
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub init |
28
|
|
|
|
|
|
|
{ |
29
|
45
|
|
|
45
|
1
|
85387
|
my $self = shift( @_ ); |
30
|
45
|
|
|
|
|
630
|
$self->{filename_charset} = undef; |
31
|
45
|
|
|
|
|
140
|
$self->{filename_lang} = undef; |
32
|
45
|
100
|
100
|
|
|
344
|
@_ = () if( @_ == 1 && $self->_is_a( $_[0] => 'Module::Generic::Null' ) ); |
33
|
45
|
100
|
|
|
|
1760
|
if( @_ ) |
34
|
|
|
|
|
|
|
{ |
35
|
39
|
|
|
|
|
104
|
my $str = shift( @_ ); |
36
|
39
|
50
|
33
|
|
|
220
|
return( $self->error( "No value was provided for Content-Disposition field." ) ) if( !defined( $str ) || !length( "$str" ) ); |
37
|
39
|
|
|
|
|
329
|
my $params = $self->_get_args_as_hash( @_ ); |
38
|
39
|
|
50
|
|
|
442
|
my $hv = $self->_parse_header_value( $str ) || |
39
|
|
|
|
|
|
|
return( $self->pass_error ); |
40
|
39
|
50
|
|
|
|
369
|
$hv->params( $params ) if( scalar( keys( %$params ) ) ); |
41
|
39
|
|
|
|
|
242
|
$self->_hv( $hv ); |
42
|
|
|
|
|
|
|
} |
43
|
45
|
50
|
|
|
|
1869
|
$self->SUPER::init( @_ ) || return( $self->pass_error ); |
44
|
45
|
|
|
|
|
261
|
$self->_field_name( 'Content-Disposition' ); |
45
|
45
|
|
|
|
|
36660
|
return( $self ); |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
8
|
|
|
8
|
1
|
264805
|
sub as_string { return( shift->_hv_as_string( [qw( name filename )] ) ); } |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub disposition |
51
|
|
|
|
|
|
|
{ |
52
|
12
|
|
|
12
|
1
|
491127
|
my $self = shift( @_ ); |
53
|
12
|
100
|
|
|
|
52
|
if( @_ ) |
54
|
|
|
|
|
|
|
{ |
55
|
5
|
|
50
|
|
|
24
|
my $dispo = shift( @_ ) || return( $self->error( "No content disposition was provided." ) ); |
56
|
5
|
|
|
|
|
26
|
my $hv = $self->_hv; |
57
|
5
|
100
|
|
|
|
139
|
if( $hv ) |
58
|
|
|
|
|
|
|
{ |
59
|
4
|
|
|
|
|
33
|
$hv->value( $dispo ); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
else |
62
|
|
|
|
|
|
|
{ |
63
|
1
|
|
50
|
|
|
9
|
$hv = $self->_new_hv( $dispo ) || return( $self->pass_error ); |
64
|
1
|
|
|
|
|
177
|
$self->_hv( $hv ); |
65
|
|
|
|
|
|
|
} |
66
|
5
|
|
|
|
|
3680
|
return( $dispo ); |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
else |
69
|
|
|
|
|
|
|
{ |
70
|
|
|
|
|
|
|
# No header value object, means there is just nothing set yet |
71
|
7
|
|
50
|
|
|
31
|
my $hv = $self->_hv || return( '' ); |
72
|
7
|
|
|
|
|
327
|
return( $hv->value_data ); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub filename |
77
|
|
|
|
|
|
|
{ |
78
|
13
|
|
|
13
|
1
|
77480
|
my $self = shift( @_ ); |
79
|
13
|
100
|
|
|
|
44
|
if( @_ ) |
80
|
|
|
|
|
|
|
{ |
81
|
1
|
|
|
|
|
4
|
my( $fname, $lang ) = @_; |
82
|
1
|
50
|
|
|
|
5
|
if( !defined( $fname ) ) |
83
|
|
|
|
|
|
|
{ |
84
|
0
|
|
|
|
|
0
|
$self->params->delete( 'filename' ); |
85
|
0
|
|
|
|
|
0
|
$self->params->delete( 'filename*' ); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
else |
88
|
|
|
|
|
|
|
{ |
89
|
1
|
|
33
|
|
|
4
|
$lang //= $self->filename_lang; |
90
|
1
|
50
|
|
|
|
10
|
if( my $enc = $self->_filename_encode( $fname, $lang ) ) |
91
|
|
|
|
|
|
|
{ |
92
|
1
|
50
|
|
|
|
297
|
$self->_set_get_param( 'filename*' => $enc ) || return( $self->pass_error ); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
else |
95
|
|
|
|
|
|
|
{ |
96
|
0
|
|
|
|
|
0
|
$self->_set_get_qparam( filename => $fname ); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
else |
101
|
|
|
|
|
|
|
{ |
102
|
12
|
|
|
|
|
81
|
my $v = $self->_set_get_qparam( 'filename' ); |
103
|
12
|
100
|
66
|
|
|
92
|
if( defined( $v ) && length( $v ) ) |
|
|
100
|
|
|
|
|
|
104
|
|
|
|
|
|
|
{ |
105
|
|
|
|
|
|
|
# decode if necessary |
106
|
9
|
|
|
|
|
26
|
my( $f_charset, $f_lang ); |
107
|
9
|
|
|
|
|
71
|
( $v, $f_charset, $f_lang ) = $self->_filename_decode( $v ); |
108
|
9
|
|
|
|
|
44
|
$self->filename_charset( $f_charset ); |
109
|
9
|
|
|
|
|
26624
|
$self->filename_lang( $f_lang ); |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
elsif( $v = $self->_set_get_param( 'filename*' ) ) |
112
|
|
|
|
|
|
|
{ |
113
|
1
|
|
|
|
|
519
|
my( $f_charset, $f_lang ); |
114
|
1
|
|
|
|
|
6
|
( $v, $f_charset, $f_lang ) = $self->_filename_decode( $v ); |
115
|
1
|
|
|
|
|
6
|
$self->filename_charset( $f_charset ); |
116
|
1
|
|
|
|
|
929
|
$self->filename_lang( $f_lang ); |
117
|
|
|
|
|
|
|
} |
118
|
12
|
|
|
|
|
11235
|
return( $v ); |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub filename_charset |
123
|
|
|
|
|
|
|
{ |
124
|
11
|
|
|
11
|
1
|
31
|
my $self = shift( @_ ); |
125
|
11
|
100
|
|
|
|
37
|
if( @_ ) |
126
|
|
|
|
|
|
|
{ |
127
|
10
|
|
|
|
|
22
|
my $v = shift( @_ ); |
128
|
10
|
100
|
|
|
|
29
|
if( !defined( $v ) ) |
129
|
|
|
|
|
|
|
{ |
130
|
5
|
|
|
|
|
38
|
return( $self->_set_get_scalar_as_object( 'filename_charset', $v ) ); |
131
|
|
|
|
|
|
|
} |
132
|
5
|
100
|
66
|
|
|
36
|
return( $self->error( "Only supported charset is 'utf-8'." ) ) if( lc( $v ) ne 'utf-8' && lc( $v ) ne 'utf8' ); |
133
|
|
|
|
|
|
|
# Convenience |
134
|
1
|
50
|
|
|
|
6
|
$v = 'utf-8' if( lc( $v ) eq 'utf8' ); |
135
|
1
|
|
|
|
|
4
|
$v = uc( $v ); |
136
|
1
|
|
|
|
|
6
|
return( $self->_set_get_scalar_as_object( 'filename_charset', $v ) ); |
137
|
|
|
|
|
|
|
} |
138
|
1
|
|
|
|
|
5
|
return( $self->_set_get_scalar_as_object( 'filename_charset' ) ); |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
11
|
|
|
11
|
1
|
1128
|
sub filename_lang { return( shift->_set_get_scalar_as_object( 'filename_lang', @_ ) ); } |
142
|
|
|
|
|
|
|
|
143
|
18
|
|
|
18
|
1
|
76607
|
sub name { return( shift->_set_get_param( name => @_ ) ); } |
144
|
|
|
|
|
|
|
|
145
|
0
|
|
|
0
|
1
|
|
sub param { return( shift->_set_get_param( @_ ) ); } |
146
|
|
|
|
|
|
|
|
147
|
0
|
|
|
0
|
1
|
|
sub params { return( shift->_set_get_params( @_ ) ); } |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
1; |
150
|
|
|
|
|
|
|
# NOTE: POD |
151
|
|
|
|
|
|
|
__END__ |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=encoding utf-8 |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head1 NAME |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
HTTP::Promise::Headers::ContentDisposition - Content-Disposition Header Field |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=head1 SYNOPSIS |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
use HTTP::Promise::Headers::ContentDisposition; |
162
|
|
|
|
|
|
|
my $cd = HTTP::Promise::Headers::ContentDisposition->new || |
163
|
|
|
|
|
|
|
die( HTTP::Promise::Headers::ContentDisposition->error, "\n" ); |
164
|
|
|
|
|
|
|
my $dispo = $cd->disposition; |
165
|
|
|
|
|
|
|
# For example, attachment |
166
|
|
|
|
|
|
|
$cd->disposition( 'inline' ); |
167
|
|
|
|
|
|
|
$cd->filename( 'some-file.txt' ); |
168
|
|
|
|
|
|
|
$cd->disposition( 'form-data' ); |
169
|
|
|
|
|
|
|
$cd->name( 'someField' ); |
170
|
|
|
|
|
|
|
my $name = $cd->name; |
171
|
|
|
|
|
|
|
# Same thing |
172
|
|
|
|
|
|
|
my $name = $cd->param( 'name' ); |
173
|
|
|
|
|
|
|
$cd->params( name => 'someField', filename => 'some-file.txt' ); |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 VERSION |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
v0.1.0 |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 DESCRIPTION |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
The following description is taken from Mozilla documentation. |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Content-Disposition: inline |
184
|
|
|
|
|
|
|
Content-Disposition: attachment |
185
|
|
|
|
|
|
|
Content-Disposition: attachment; filename="filename.jpg" |
186
|
|
|
|
|
|
|
Content-Disposition: form-data; name="fieldName" |
187
|
|
|
|
|
|
|
Content-Disposition: form-data; name="fieldName"; filename="filename.jpg" |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head1 METHODS |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=head2 as_string |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Returns a string representation of the Content-Disposition object. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head2 disposition |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Sets or gets the type of C<Content-Disposition> this is. For example: C<attachment>, C<form-data> |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=head2 name |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
Is followed by a string containing the name of the HTML field in the form that the content of this subpart refers to. When dealing with multiple files in the same field (for example, the multiple attribute of an <input type="file"> element), there can be several subparts with the same name. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
A name with a value of '_charset_' indicates that the part is not an HTML field, but the default charset to use for parts without explicit charset information. |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head2 filename |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Without any argument, this returns the string containing the original name of the file transmitted. The C<filename> is always optional and must not be used blindly by the application: path information should be stripped, and conversion to the server file system rules should be done. This parameter provides mostly indicative information. When used in combination with C<Content-Disposition: attachment>, it is used as the default C<filename> for an eventual "Save As" dialog presented to the user. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
If the property C<filename*> is set instead, then it will be decoded and used instead, and the value for L</filename_charset> and L</filename_lang> will be set. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
When setting the filename value, this takes an optional language iso 639 code (see L<rfc5987|https://tools.ietf.org/html/rfc5987> and L<rfc2231|https://tools.ietf.org/html/rfc2231>). |
212
|
|
|
|
|
|
|
If the filename contains non ascii characters, it will be automatically encoded according to L<rfc5987|https://tools.ietf.org/html/rfc5987>. and the property C<filename*> set instead. That property, by rfc standard, takes precedence over the C<filename> one. |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
The language provided, if any, will be used then. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
For example: |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
$h->disposition( 'form-data' ); |
219
|
|
|
|
|
|
|
$h->name( 'fileField' ); |
220
|
|
|
|
|
|
|
$h->filename( q{file.txt} ); |
221
|
|
|
|
|
|
|
say "$h"; |
222
|
|
|
|
|
|
|
# form-data; name="fileField"; filename="file.txt" |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
$h->disposition( 'form-data' ); |
225
|
|
|
|
|
|
|
$h->name( 'fileField' ); |
226
|
|
|
|
|
|
|
$h->filename( q{ファイル.txt} ); |
227
|
|
|
|
|
|
|
say "$h"; |
228
|
|
|
|
|
|
|
# form-data; name="fileField"; filename*="UTF-8''%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt" |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
$h->disposition( 'form-data' ); |
231
|
|
|
|
|
|
|
$h->name( 'fileField' ); |
232
|
|
|
|
|
|
|
$h->filename( q{ファイル.txt}, 'ja-JP' ); |
233
|
|
|
|
|
|
|
say "$h"; |
234
|
|
|
|
|
|
|
# form-data; name="fileField"; filename*="UTF-8'ja-JP'%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt" |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# Using default value |
237
|
|
|
|
|
|
|
$h->filename_lang( 'ja-JP' ); |
238
|
|
|
|
|
|
|
$h->disposition( 'form-data' ); |
239
|
|
|
|
|
|
|
$h->name( 'fileField' ); |
240
|
|
|
|
|
|
|
$h->filename( q{ファイル.txt} ); |
241
|
|
|
|
|
|
|
say "$h"; |
242
|
|
|
|
|
|
|
# form-data; name="fileField"; filename*="UTF-8'ja-JP'%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt" |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
$headers->header( Content_Disposition => "$h" ); |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
The C<Content-Disposition> header value would then contain a property C<filename*> (with the trailing wildcard). |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
See also L<HTTP::Promise::Headers/decode_filename> and L<HTTP::Promise::Headers/encode_filename> which are used to decode and encode filenames. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=head2 filename_charset |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Sets or gets the encoded filename charset. |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
This is used when the filename contains non-ascii characters, such as Japanese, Korean, or Cyrillic. |
255
|
|
|
|
|
|
|
Although theoretically one can set any character set, by design this only accepts C<UTF-8> (case insensitive). |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
This is set automatically when calling L</filename>. You actually need to call L</filename> first to have a value set. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
Returns a L<scalar object|Module::Generic::Scalar> containing the filename charset. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
=head2 filename_lang |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
Sets or gets the encoded filename language. This takes an iso 639 language code (see L<rfc1766|https://tools.ietf.org/html/rfc1766>). |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
This is set automatically when calling L</filename>. You actually need to call L</filename> first to have a value set. |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
Returns a L<scalar object|Module::Generic::Scalar> containing the filename language. |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=head2 param |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Sets or gets an arbitrary C<Content-Disposition> property. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
Note that if you use this, you bypass other specialised method who do some additional processing, so be mindful. |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
=head2 params |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
Sets or gets multiple arbitrary C<Content-Disposition> properties at once. |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
If called without any arguments, this returns the L<hash object|Module::Generic::Hash> used to store the C<Content-Disposition> properties. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=head1 AUTHOR |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=head1 SEE ALSO |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
See L<rfc6266, section 4|https://tools.ietf.org/html/rfc6266#section-4>, L<rfc7578, section 4.2|https://tools.ietf.org/html/rfc7578#section-4.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition> |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
L<HTTP::Promise>, L<HTTP::Promise::Request>, L<HTTP::Promise::Response>, L<HTTP::Promise::Message>, L<HTTP::Promise::Entity>, L<HTTP::Promise::Headers>, L<HTTP::Promise::Body>, L<HTTP::Promise::Body::Form>, L<HTTP::Promise::Body::Form::Data>, L<HTTP::Promise::Body::Form::Field>, L<HTTP::Promise::Status>, L<HTTP::Promise::MIME>, L<HTTP::Promise::Parser>, L<HTTP::Promise::IO>, L<HTTP::Promise::Stream>, L<HTTP::Promise::Exception> |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
Copyright(c) 2022 DEGUEST Pte. Ltd. |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
All rights reserved. |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=cut |