line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
2
|
|
|
|
|
|
|
## Asynchronous HTTP Request and Promise - ~/lib/HTTP/Promise/Headers/Generic.pm |
3
|
|
|
|
|
|
|
## Version v0.1.1 |
4
|
|
|
|
|
|
|
## Copyright(c) 2022 DEGUEST Pte. Ltd. |
5
|
|
|
|
|
|
|
## Author: Jacques Deguest <jack@deguest.jp> |
6
|
|
|
|
|
|
|
## Created 2022/05/06 |
7
|
|
|
|
|
|
|
## Modified 2023/09/08 |
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::Generic; |
15
|
|
|
|
|
|
|
BEGIN |
16
|
|
|
|
|
|
|
{ |
17
|
11
|
|
|
11
|
|
6861
|
use strict; |
|
11
|
|
|
|
|
27
|
|
|
11
|
|
|
|
|
337
|
|
18
|
11
|
|
|
11
|
|
82
|
use warnings; |
|
11
|
|
|
|
|
23
|
|
|
11
|
|
|
|
|
403
|
|
19
|
11
|
|
|
11
|
|
86
|
use parent qw( Module::Generic ); |
|
11
|
|
|
|
|
47
|
|
|
11
|
|
|
|
|
146
|
|
20
|
11
|
|
|
11
|
|
101033
|
use vars qw( $VERSION $QV_ELEMENT $QV_VALUE ); |
|
11
|
|
|
|
|
25
|
|
|
11
|
|
|
|
|
938
|
|
21
|
11
|
|
|
11
|
|
88
|
use Encode (); |
|
11
|
|
|
|
|
24
|
|
|
11
|
|
|
|
|
261
|
|
22
|
11
|
|
|
11
|
|
578
|
use URI::Escape::XS (); |
|
11
|
|
|
|
|
99034
|
|
|
11
|
|
|
|
|
306
|
|
23
|
11
|
|
|
11
|
|
75
|
use Want; |
|
11
|
|
|
|
|
26
|
|
|
11
|
|
|
|
|
1616
|
|
24
|
|
|
|
|
|
|
use overload ( |
25
|
|
|
|
|
|
|
'""' => 'as_string', |
26
|
558
|
|
|
558
|
|
12463
|
'bool' => sub{1}, |
27
|
|
|
|
|
|
|
# No fallback on purpose |
28
|
11
|
|
|
11
|
|
89
|
); |
|
11
|
|
|
|
|
36
|
|
|
11
|
|
|
|
|
206
|
|
29
|
|
|
|
|
|
|
# Accept: audio/*; q=0.2, audio/basic |
30
|
11
|
|
|
11
|
|
2642
|
our $QV_ELEMENT = qr/(?:[^\;\,]+)/; |
31
|
11
|
|
|
|
|
63
|
our $QV_VALUE = qr/(?:0(?:\.[0-9]{0,3})?|1(?:\.0{0,3})?)/; |
32
|
11
|
|
|
|
|
316
|
our $VERSION = 'v0.1.1'; |
33
|
|
|
|
|
|
|
}; |
34
|
|
|
|
|
|
|
|
35
|
11
|
|
|
11
|
|
76
|
use strict; |
|
11
|
|
|
|
|
37
|
|
|
11
|
|
|
|
|
302
|
|
36
|
11
|
|
|
11
|
|
67
|
use warnings; |
|
11
|
|
|
|
|
24
|
|
|
11
|
|
|
|
|
33886
|
|
37
|
|
|
|
|
|
|
|
38
|
0
|
|
|
0
|
1
|
0
|
sub as_string { return( shift->value ); } |
39
|
|
|
|
|
|
|
|
40
|
0
|
|
|
0
|
1
|
0
|
sub field_name { return( shift->_set_get_scalar( '_name', @_ ) ); } |
41
|
|
|
|
|
|
|
|
42
|
2
|
|
|
2
|
1
|
23
|
sub uri_escape_utf8 { return( URI::Escape::XS::uri_escape( Encode::encode( 'UTF-8', $_[1] ) ) ); } |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# By default and superseded by inheriting classes such as Content-Type that has more |
45
|
|
|
|
|
|
|
# elaborate value with parameters |
46
|
0
|
|
|
0
|
1
|
0
|
sub value { return( shift->_set_get_scalar( '_value', @_ ) ); } |
47
|
|
|
|
|
|
|
|
48
|
168
|
|
|
168
|
|
979
|
sub _field_name { return( shift->_set_get_scalar( '_name', @_ ) ); } |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# rfc2231 <https://tools.ietf.org/html/rfc2231> |
51
|
|
|
|
|
|
|
sub _filename_decode |
52
|
|
|
|
|
|
|
{ |
53
|
10
|
|
|
10
|
|
24
|
my $self = shift( @_ ); |
54
|
10
|
|
|
|
|
21
|
my $fname = shift( @_ ); |
55
|
10
|
50
|
|
|
|
40
|
$self->_load_class( 'HTTP::Promise::Headers' ) || return( $self->pass_error ); |
56
|
10
|
|
|
|
|
426
|
my( $new_fname, $charset, $lang ) = HTTP::Promise::Headers->decode_filename( $fname ); |
57
|
10
|
50
|
|
|
|
36
|
if( defined( $new_fname ) ) |
58
|
|
|
|
|
|
|
{ |
59
|
10
|
|
|
|
|
19
|
$fname = $new_fname; |
60
|
|
|
|
|
|
|
} |
61
|
10
|
50
|
|
|
|
45
|
return( wantarray() ? ( $fname, $charset, $lang ) : $fname ); |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# rfc2231 <https://tools.ietf.org/html/rfc2231> |
65
|
|
|
|
|
|
|
sub _filename_encode |
66
|
|
|
|
|
|
|
{ |
67
|
2
|
|
|
2
|
|
6
|
my $self = shift( @_ ); |
68
|
2
|
|
|
|
|
7
|
my $fname = shift( @_ ); |
69
|
2
|
|
|
|
|
3
|
my $lang = shift( @_ ); |
70
|
2
|
50
|
|
|
|
17
|
if( $fname =~ /[^\x00-\x7f]/ ) |
71
|
|
|
|
|
|
|
{ |
72
|
2
|
50
|
|
|
|
8
|
$lang = '' if( !defined( $lang ) ); |
73
|
2
|
|
|
|
|
28
|
return( sprintf( "UTF-8'${lang}'%s", $self->uri_escape_utf8( $fname ) ) ); |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
# Nothing to be done. We return undef on purpose to indicate nothing was done |
76
|
0
|
|
|
|
|
0
|
return; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
316
|
|
|
316
|
|
1326
|
sub _hv { return( shift->_set_get_object_without_init( '_hv', 'Module::Generic::HeaderValue', @_ ) ); } |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub _hv_as_string |
82
|
|
|
|
|
|
|
{ |
83
|
48
|
|
|
48
|
|
157
|
my $self = shift( @_ ); |
84
|
48
|
|
|
|
|
314
|
my $hv = $self->_hv; |
85
|
48
|
50
|
|
|
|
1387
|
return( '' ) if( !$hv ); |
86
|
48
|
|
|
|
|
558
|
return( $hv->as_string( @_ ) ); |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub _get_header_value_object |
90
|
|
|
|
|
|
|
{ |
91
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
92
|
0
|
0
|
|
|
|
0
|
$self->_load_class( 'Module::Generic::HeaderValue' ) || |
93
|
|
|
|
|
|
|
return( $self->pass_error ); |
94
|
0
|
|
0
|
|
|
0
|
my $hv = Module::Generic::HeaderValue->new( shift( @_ ) ) || |
95
|
|
|
|
|
|
|
return( $self->pass_error( Module::Generic::HeaderValue->error ) ); |
96
|
0
|
|
|
|
|
0
|
return( $hv ); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
0
|
|
|
0
|
|
0
|
sub _make_boundary { return( Data::UUID->new->create_str ); } |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub _new_hv |
102
|
|
|
|
|
|
|
{ |
103
|
5
|
|
|
5
|
|
33
|
my $self = shift( @_ ); |
104
|
5
|
50
|
|
|
|
27
|
$self->_load_class( 'Module::Generic::HeaderValue' ) || return( $self->pass_error ); |
105
|
5
|
|
|
|
|
321
|
return( Module::Generic::HeaderValue->new( @_ ) ); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub _new_qv_object |
109
|
|
|
|
|
|
|
{ |
110
|
35
|
|
|
35
|
|
77
|
my $self = shift( @_ ); |
111
|
35
|
|
|
|
|
183
|
my $o = HTTP::Promise::Field::QualityValue->new( @_ ); |
112
|
35
|
50
|
|
|
|
259
|
return( $self->pass_error( HTTP::Promise::Field::QualityValue->error ) ) if( !defined( $o ) ); |
113
|
35
|
|
|
|
|
85
|
return( $o ); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub _parse_header_value |
117
|
|
|
|
|
|
|
{ |
118
|
87
|
|
|
87
|
|
258
|
my $self = shift( @_ ); |
119
|
87
|
|
|
|
|
204
|
my $this = shift( @_ ); |
120
|
87
|
50
|
33
|
|
|
546
|
return( $self->error( "No header value was provided to parse." ) ) if( !defined( $this ) || !length( "$this" ) ); |
121
|
87
|
50
|
|
|
|
804
|
$self->_load_class( 'Module::Generic::HeaderValue' ) || |
122
|
|
|
|
|
|
|
return( $self->pass_error ); |
123
|
87
|
|
50
|
|
|
19358
|
my $hv = Module::Generic::HeaderValue->new_from_header( $this, @_ ) || |
124
|
|
|
|
|
|
|
return( $self->pass_error( Module::Generic::HeaderValue->error ) ); |
125
|
87
|
|
|
|
|
579212
|
return( $hv ); |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
# rfc7231, section 5.3.1 |
129
|
|
|
|
|
|
|
# <https://tools.ietf.org/html/rfc7231#section-5.3.1> |
130
|
|
|
|
|
|
|
sub _parse_quality_value |
131
|
|
|
|
|
|
|
{ |
132
|
10
|
|
|
10
|
|
33
|
my $self = shift( @_ ); |
133
|
10
|
|
|
|
|
23
|
my $str = shift( @_ ); |
134
|
10
|
50
|
33
|
|
|
92
|
return( $self->error( "No header value was provided to parse." ) ) if( !defined( $str ) || !length( "$str" ) ); |
135
|
|
|
|
|
|
|
# No blank |
136
|
10
|
|
|
|
|
49
|
$str =~ s/[[:blank:]\h]]+//g; |
137
|
10
|
|
|
|
|
96
|
my $choices = $self->new_array; |
138
|
|
|
|
|
|
|
# Credits: HTTP::AcceptLanguage from Kazuhiro Osawa |
139
|
10
|
|
|
|
|
12470
|
for my $def ( split( /,[[:blank:]\h]*/, $str ) ) |
140
|
|
|
|
|
|
|
{ |
141
|
35
|
|
|
|
|
757
|
my( $element, $quality ) = $def =~ /\A($QV_ELEMENT)(?:;[[:blank:]\h]*[qQ]=($QV_VALUE))?\z/; |
142
|
|
|
|
|
|
|
# rfc7231, section 5.3.1: |
143
|
|
|
|
|
|
|
# "If no "q" parameter is present, the default weight is 1." |
144
|
|
|
|
|
|
|
# rfc7231, section 5.3.5 |
145
|
|
|
|
|
|
|
# "no value is the same as q=1" |
146
|
|
|
|
|
|
|
# $quality = 1 unless( defined( $quality ) ); |
147
|
|
|
|
|
|
|
# next unless( $element && $quality > 0 ); |
148
|
35
|
50
|
|
|
|
123
|
next unless( $element ); |
149
|
35
|
|
|
|
|
154
|
my $qv = $self->_new_qv_object( $element => $quality ); |
150
|
35
|
|
|
|
|
141
|
$choices->push( $qv ); |
151
|
|
|
|
|
|
|
} |
152
|
10
|
|
|
|
|
154
|
return( $choices ); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub _qstring_join |
156
|
|
|
|
|
|
|
{ |
157
|
6
|
|
|
6
|
|
136
|
my $self = shift( @_ ); |
158
|
6
|
|
|
|
|
13
|
my @parts = (); |
159
|
6
|
|
|
|
|
13
|
foreach my $s ( @_ ) |
160
|
|
|
|
|
|
|
{ |
161
|
26
|
|
|
|
|
36
|
$s =~ s/^"//; |
162
|
26
|
|
|
|
|
34
|
$s =~ s/(?!\\)"$//; |
163
|
26
|
|
|
|
|
30
|
$s =~ s/(?!\\)\"/\\"/g; |
164
|
26
|
|
|
|
|
59
|
push( @parts, qq{"${s}"} ); |
165
|
|
|
|
|
|
|
} |
166
|
6
|
|
|
|
|
65
|
return( join( ', ', @parts ) ); |
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# Returns an array of tokens that were initially surrounded by double quotes, and |
170
|
|
|
|
|
|
|
# separated by comma even if they contained double quotes inside. |
171
|
|
|
|
|
|
|
# Example for Clear-Site-Data header field: |
172
|
|
|
|
|
|
|
# "cache", "cookies", "storage", "executionContexts" |
173
|
|
|
|
|
|
|
# "cache\"", "oh "la" la", "storage\", \"", "executionContexts" |
174
|
|
|
|
|
|
|
sub _qstring_split |
175
|
|
|
|
|
|
|
{ |
176
|
2
|
|
|
2
|
|
45
|
my $self = shift( @_ ); |
177
|
2
|
|
|
|
|
23
|
my $str = shift( @_ ); |
178
|
2
|
|
|
|
|
27
|
my @parts = split( /(?<=(?<!\\)\")[[:blank:]\h]*,[[:blank:]\h]*(?=\")/, $str ); |
179
|
2
|
|
|
|
|
9
|
for( @parts ) |
180
|
|
|
|
|
|
|
{ |
181
|
|
|
|
|
|
|
#substr( $_, 0, 1, '' ); |
182
|
|
|
|
|
|
|
#substr( $_, -1, 1, '' ); |
183
|
|
|
|
|
|
|
# s/^"|"$//g; |
184
|
8
|
|
|
|
|
27
|
s/^"//; |
185
|
8
|
|
|
|
|
35
|
s/"$//; |
186
|
|
|
|
|
|
|
} |
187
|
2
|
|
|
|
|
31
|
return( @parts ); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub _qv_add |
191
|
|
|
|
|
|
|
{ |
192
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
193
|
0
|
|
|
|
|
0
|
my( $elem, $val ) = @_; |
194
|
0
|
|
0
|
|
|
0
|
my $qv = HTTP::Promise::Field::QualityValue->new( $elem => $val ) || |
195
|
|
|
|
|
|
|
return( $self->pass_error( HTTP::Promise::Field::QualityValue->error ) ); |
196
|
0
|
|
|
|
|
0
|
$self->elements->push( $qv ); |
197
|
0
|
|
|
|
|
0
|
return( $qv ); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub _qv_as_string |
201
|
|
|
|
|
|
|
{ |
202
|
15
|
|
|
15
|
|
40
|
my $self = shift( @_ ); |
203
|
15
|
|
|
|
|
39
|
my $all = $self->elements; |
204
|
15
|
50
|
|
|
|
1101
|
return( '' ) if( $all->is_empty ); |
205
|
15
|
|
|
52
|
|
378
|
my $res = $all->map(sub{ $_->as_string }); |
|
52
|
|
|
|
|
450
|
|
206
|
15
|
|
|
|
|
1927
|
return( $res->join( ', ' )->scalar ); |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
49
|
|
|
49
|
|
242
|
sub _qv_elements { return( shift->_set_get_object_array_object( '_qv_elements', 'HTTP::Promise::Field::QualityValue', @_ ) ); } |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub _qv_get |
212
|
|
|
|
|
|
|
{ |
213
|
5
|
|
|
5
|
|
13
|
my $self = shift( @_ ); |
214
|
5
|
|
|
|
|
11
|
my $this = shift( @_ ); |
215
|
5
|
50
|
33
|
|
|
30
|
return( $self->error( "No a property name to get was provided." ) ) if( !defined( $this ) || !length( "$this" ) ); |
216
|
5
|
|
|
|
|
26
|
my $all = $self->elements; |
217
|
5
|
100
|
|
|
|
343
|
if( $self->_is_a( $this => 'HTTP::Promise::Field::QualityValue' ) ) |
218
|
|
|
|
|
|
|
{ |
219
|
1
|
|
|
|
|
44
|
my $pos = $all->pos( $this ); |
220
|
1
|
50
|
|
|
|
46
|
return( $all->[$pos] ) if( defined( $pos ) ); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
else |
223
|
|
|
|
|
|
|
{ |
224
|
4
|
|
|
|
|
67
|
foreach( @$all ) |
225
|
|
|
|
|
|
|
{ |
226
|
7
|
100
|
|
|
|
2517
|
return( $_ ) if( $_->element eq $this ); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
} |
229
|
0
|
|
|
|
|
0
|
return( '' ); |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
sub _qv_match |
233
|
|
|
|
|
|
|
{ |
234
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
235
|
0
|
|
|
|
|
0
|
my $this = shift( @_ ); |
236
|
0
|
0
|
0
|
|
|
0
|
return( '' ) if( !defined( $this ) || !length( "$this" ) ); |
237
|
0
|
0
|
0
|
|
|
0
|
$this = [split( /(?:[[:blank:]]+|[[:blank:]]*\,[[:blank:]]*)/, "$this" )] if( !$self->_is_array( $this ) && ( !ref( $this ) || overload::Method( $this => '""' ) ) ); |
|
|
|
0
|
|
|
|
|
238
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Invalid argument provided. Provide either an array reference or a string or something that stringifies." ) ) if( !$self->_is_array( $this ) ); |
239
|
0
|
|
|
|
|
0
|
my $ordered = [map( lc( $_ ), @$this )]; |
240
|
0
|
0
|
|
|
|
0
|
return( '' ) if( !scalar( @$ordered ) ); |
241
|
0
|
0
|
|
|
|
0
|
my $acceptables = $self->can( 'sort' ) ? $self->sort : $self->_qv_sort; |
242
|
0
|
|
|
|
|
0
|
my $ok = $self->new_array; |
243
|
0
|
|
|
|
|
0
|
my $seen = {}; |
244
|
0
|
|
|
|
|
0
|
foreach my $e ( @$acceptables ) |
245
|
|
|
|
|
|
|
{ |
246
|
0
|
|
|
|
|
0
|
my $e_lc = $e->element->lc; |
247
|
0
|
0
|
|
|
|
0
|
if( $e->element->index( '*' ) != -1 ) |
248
|
|
|
|
|
|
|
{ |
249
|
0
|
|
|
|
|
0
|
my $wildcard_ok = $self->_qv_match_wildcard( $e_lc => $ordered, $this ); |
250
|
0
|
0
|
|
|
|
0
|
return( $self->pass_error ) if( !defined( $wildcard_ok ) ); |
251
|
0
|
0
|
|
|
|
0
|
$ok->push( $wildcard_ok->list ) if( !$wildcard_ok->is_empty ); |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
else |
254
|
|
|
|
|
|
|
{ |
255
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < scalar( @$ordered ); $i++ ) |
256
|
|
|
|
|
|
|
{ |
257
|
0
|
0
|
|
|
|
0
|
if( $e_lc eq $ordered->[$i] ) |
258
|
|
|
|
|
|
|
{ |
259
|
|
|
|
|
|
|
# We'll return the caller's original value, not the lowercase one we use for comparison |
260
|
0
|
|
|
|
|
0
|
$ok->push( $this->[$i] ); |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
} |
265
|
0
|
|
|
|
|
0
|
return( $ok->unique ); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# Works for language and content-type and content-encoding |
269
|
|
|
|
|
|
|
sub _qv_match_wildcard |
270
|
|
|
|
|
|
|
{ |
271
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
272
|
|
|
|
|
|
|
# $proposals contain the value offered in lower case, whereas $original contains |
273
|
|
|
|
|
|
|
# the original value and we return our value from there. Both $proposals and $original |
274
|
|
|
|
|
|
|
# are of the same size. |
275
|
0
|
|
|
|
|
0
|
my( $acceptable, $proposals, $original, $seen ) = @_; |
276
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Bad arguments. Usage: \$h->_qv_match_wildcard( \$acceptable, \$proposals, \$original )" ) ) unless( @_ == 3 ); |
277
|
0
|
0
|
|
|
|
0
|
return( $self->error( "This is not a wildcard acceptable value." ) ) if( $acceptable->index( '*' ) == -1 ); |
278
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Proposed values must be an array reference." ) ) unless( $self->_is_array( $proposals ) ); |
279
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Original array of proposed values must be an array reference." ) ) unless( $self->_is_array( $original ) ); |
280
|
0
|
|
|
|
|
0
|
my $ok = $self->new_array; |
281
|
0
|
0
|
|
|
|
0
|
if( $acceptable->index( '/' ) != -1 ) |
282
|
|
|
|
|
|
|
{ |
283
|
0
|
|
|
|
|
0
|
my( $main, $sub ) = $acceptable->element->split( qr/\// ); |
284
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < scalar( @$proposals ); $i++ ) |
285
|
|
|
|
|
|
|
{ |
286
|
0
|
|
|
|
|
0
|
my $supported = $proposals->[$i]; |
287
|
0
|
|
|
|
|
0
|
my( $this_main, $this_sub ) = split( /\//, "$supported", 2 ); |
288
|
0
|
0
|
|
|
|
0
|
if( $main eq '*' ) |
|
|
0
|
|
|
|
|
|
289
|
|
|
|
|
|
|
{ |
290
|
0
|
0
|
|
|
|
0
|
if( $sub eq '*' ) |
291
|
|
|
|
|
|
|
{ |
292
|
0
|
|
|
|
|
0
|
$ok->push( $original->[$i] ); |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
else |
295
|
|
|
|
|
|
|
{ |
296
|
0
|
0
|
|
|
|
0
|
$ok->push( $original->[$i] ) if( $this_sub eq $sub ); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
elsif( $main eq $this_main ) |
300
|
|
|
|
|
|
|
{ |
301
|
0
|
0
|
|
|
|
0
|
if( $sub eq '*' ) |
302
|
|
|
|
|
|
|
{ |
303
|
0
|
|
|
|
|
0
|
$ok->push( $original->[$i] ); |
304
|
|
|
|
|
|
|
} |
305
|
|
|
|
|
|
|
else |
306
|
|
|
|
|
|
|
{ |
307
|
0
|
0
|
|
|
|
0
|
$ok->push( $original->[$i] ) if( $this_sub eq $sub ); |
308
|
|
|
|
|
|
|
} |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
# simply return the proposal value since anything goes |
313
|
|
|
|
|
|
|
else |
314
|
|
|
|
|
|
|
{ |
315
|
0
|
|
|
|
|
0
|
$ok->push( $original->[0] ); |
316
|
|
|
|
|
|
|
} |
317
|
0
|
|
|
|
|
0
|
return( $ok ); |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub _qv_remove |
321
|
|
|
|
|
|
|
{ |
322
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
323
|
1
|
|
|
|
|
3
|
my $this = shift( @_ ); |
324
|
1
|
|
|
|
|
4
|
my $all = $self->elements; |
325
|
1
|
50
|
|
|
|
73
|
if( $self->_is_a( $this => 'HTTP::Promise::Field::QualityValue' ) ) |
326
|
|
|
|
|
|
|
{ |
327
|
0
|
|
|
|
|
0
|
return( $all->delete( $this ) ); |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
else |
330
|
|
|
|
|
|
|
{ |
331
|
1
|
|
|
|
|
18
|
my $e; |
332
|
1
|
|
|
|
|
5
|
for( my $i = 0; $i < scalar( @$all ); $i++ ) |
333
|
|
|
|
|
|
|
{ |
334
|
2
|
100
|
|
|
|
876
|
if( $all->[$i]->element eq "$this" ) |
335
|
|
|
|
|
|
|
{ |
336
|
1
|
|
|
|
|
814
|
$e = $all->splice( $i, 1 ); |
337
|
1
|
|
|
|
|
84
|
last; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
} |
340
|
1
|
|
|
|
|
9
|
return( $e ); |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
} |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub _qv_sort |
345
|
|
|
|
|
|
|
{ |
346
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
347
|
1
|
|
|
|
|
14
|
my $opts = $self->_get_args_as_hash( @_ ); |
348
|
1
|
50
|
|
|
|
12
|
$opts->{asc} = 0 if( !exists( $opts->{asc} ) ); |
349
|
1
|
|
|
|
|
5
|
my $all = $self->elements; |
350
|
|
|
|
|
|
|
my $sorted = $opts->{asc} |
351
|
0
|
|
0
|
0
|
|
0
|
? $all->sort(sub{ ( $_[0]->value // 1 ) <=> ( $_[1]->value // 1 ) }) |
|
|
|
0
|
|
|
|
|
352
|
1
|
50
|
100
|
5
|
|
107
|
: $all->sort(sub{ ( $_[1]->value // 1 ) <=> ( $_[0]->value // 1 ) }); |
|
5
|
|
100
|
|
|
3402
|
|
353
|
1
|
|
|
|
|
1023
|
$self->elements( $sorted ); |
354
|
1
|
|
|
|
|
235
|
return( $sorted ); |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub _set_get_param_boolean |
358
|
|
|
|
|
|
|
{ |
359
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
360
|
0
|
|
0
|
|
|
0
|
my $name = shift( @_ ) || return( $self->error( "No parameter name was provided." ) ); |
361
|
0
|
|
0
|
|
|
0
|
my $hv = $self->_hv || return( $self->error( "Header value object could not be found!" ) ); |
362
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
363
|
|
|
|
|
|
|
{ |
364
|
0
|
|
|
|
|
0
|
my $v = shift( @_ ); |
365
|
0
|
0
|
|
|
|
0
|
if( $v ) |
366
|
|
|
|
|
|
|
{ |
367
|
0
|
|
|
|
|
0
|
$hv->param( $name => undef ); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
else |
370
|
|
|
|
|
|
|
{ |
371
|
0
|
|
|
|
|
0
|
$hv->params->delete( $name ); |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
} |
374
|
0
|
|
|
|
|
0
|
return( $hv->param( $name ) ); |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
sub _set_get_param |
378
|
|
|
|
|
|
|
{ |
379
|
107
|
|
|
107
|
|
334
|
my $self = shift( @_ ); |
380
|
107
|
|
50
|
|
|
433
|
my $name = shift( @_ ) || return( $self->error( "No parameter name was provided." ) ); |
381
|
107
|
|
|
|
|
318
|
my $hv = $self->_hv; |
382
|
|
|
|
|
|
|
# If the HeaderValue object is not een set, and the caller just want to retrieve the |
383
|
|
|
|
|
|
|
# value of a property, we return an empty string (undef is for errors) |
384
|
107
|
50
|
66
|
|
|
3307
|
return( '' ) if( !scalar( @_ ) && !$hv ); |
385
|
107
|
50
|
|
|
|
959
|
return( $self->error( "Header value object (Module::Generic::HeaderValue) could not be found!" ) ) if( !$hv ); |
386
|
107
|
100
|
|
|
|
759
|
if( @_ ) |
387
|
|
|
|
|
|
|
{ |
388
|
18
|
|
|
|
|
90
|
$hv->param( $name => shift( @_ ) ); |
389
|
|
|
|
|
|
|
} |
390
|
107
|
|
|
|
|
16222
|
return( $hv->param( $name ) ); |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub _set_get_params |
394
|
|
|
|
|
|
|
{ |
395
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
396
|
0
|
|
0
|
|
|
0
|
my $hv = $self->_hv || return( $self->error( "Header value object could not be found!" ) ); |
397
|
0
|
|
|
|
|
0
|
my $params = $hv->params; |
398
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
399
|
|
|
|
|
|
|
{ |
400
|
0
|
|
|
|
|
0
|
while( my( $n, $v ) = splice( @_, 0, 2 ) ) |
401
|
|
|
|
|
|
|
{ |
402
|
0
|
|
|
|
|
0
|
$params->set( $n => $v ); |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
else |
406
|
|
|
|
|
|
|
{ |
407
|
0
|
|
|
|
|
0
|
return( $params ); |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub _set_get_properties_as_string |
412
|
|
|
|
|
|
|
{ |
413
|
28
|
|
|
28
|
|
72
|
my $self = shift( @_ ); |
414
|
28
|
|
|
|
|
151
|
my $opts = $self->_get_args_as_hash( @_ ); |
415
|
28
|
|
100
|
|
|
2433
|
my $sep = $opts->{separator} || $opts->{sep} || ','; |
416
|
28
|
|
100
|
|
|
128
|
my $eq = $opts->{equal} || '='; |
417
|
28
|
|
|
|
|
93
|
my $params = $self->params; |
418
|
28
|
|
|
|
|
21297
|
my $props = $self->properties; |
419
|
28
|
|
|
|
|
20707
|
my $quotes = {}; |
420
|
28
|
100
|
|
|
|
264
|
$quotes = $self->_needs_quotes if( $self->can( '_needs_quotes' ) ); |
421
|
28
|
|
|
|
|
10411
|
my @res = (); |
422
|
11
|
|
|
11
|
|
130
|
no overloading '""'; |
|
11
|
|
|
|
|
25
|
|
|
11
|
|
|
|
|
8133
|
|
423
|
28
|
|
|
|
|
112
|
foreach( @$params ) |
424
|
|
|
|
|
|
|
{ |
425
|
98
|
50
|
|
|
|
2700
|
if( !exists( $props->{ $_ } ) ) |
426
|
|
|
|
|
|
|
{ |
427
|
|
|
|
|
|
|
# warnings::warn( "Property is in our stack, but not in our repository of properties, skipping.\n" ) if( warnings::enabled( ref( $self ) ) ); |
428
|
|
|
|
|
|
|
# warn( "Property is in our stack, but not in our repository of properties, skipping.\n" ) if( $self->_warnings_is_enabled ); |
429
|
0
|
|
|
|
|
0
|
warn( "Property \"$_\" is in our stack, but not in our repository of properties, skipping.\n" ); |
430
|
0
|
|
|
|
|
0
|
next; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
# If the property exists in our repo, but has no value it is a boolean |
433
|
98
|
100
|
|
|
|
1996
|
push( @res, defined( $props->{ $_ } ) ? sprintf( "$_${eq}%s", ( $quotes->{ $_ } ? '"' : '' ) . $props->{ $_ } . ( $quotes->{ $_ } ? '"' : '' ) ) : $_ ); |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
434
|
|
|
|
|
|
|
} |
435
|
28
|
|
|
|
|
1491
|
return( join( "${sep} ", @res ) ); |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# Used by Cache-Control |
439
|
|
|
|
|
|
|
sub _set_get_property_boolean |
440
|
|
|
|
|
|
|
{ |
441
|
32
|
|
|
32
|
|
84
|
my $self = shift( @_ ); |
442
|
32
|
|
50
|
|
|
134
|
my $prop = shift( @_ ) || return( $self->error( "No parameter name was provided." ) ); |
443
|
32
|
|
|
|
|
89
|
my $params = $self->params; |
444
|
32
|
|
|
|
|
24143
|
my $props = $self->properties; |
445
|
32
|
|
|
|
|
26073
|
my $pos = $params->pos( $prop ); |
446
|
32
|
100
|
|
|
|
826
|
if( @_ ) |
447
|
|
|
|
|
|
|
{ |
448
|
9
|
|
|
|
|
24
|
my $bool = shift( @_ ); |
449
|
9
|
100
|
|
|
|
25
|
if( defined( $pos ) ) |
450
|
|
|
|
|
|
|
{ |
451
|
4
|
100
|
100
|
|
|
28
|
if( defined( $bool ) && $bool ) |
452
|
|
|
|
|
|
|
{ |
453
|
|
|
|
|
|
|
# Nothing to do, it is already there |
454
|
|
|
|
|
|
|
# Making sure we have it in our properties hash as well |
455
|
1
|
|
|
|
|
7
|
$props->{ $prop } = undef; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
# Undefined or false properties get removed |
458
|
|
|
|
|
|
|
else |
459
|
|
|
|
|
|
|
{ |
460
|
3
|
|
|
|
|
23
|
$params->splice( $pos, 1 ); |
461
|
3
|
|
|
|
|
253
|
$props->delete( $prop ); |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
# Not there yet |
465
|
|
|
|
|
|
|
else |
466
|
|
|
|
|
|
|
{ |
467
|
5
|
50
|
33
|
|
|
39
|
if( defined( $bool ) && $bool ) |
468
|
|
|
|
|
|
|
{ |
469
|
5
|
|
|
|
|
30
|
$params->push( $prop ); |
470
|
5
|
|
|
|
|
51
|
$props->{ $prop } = undef; |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
# Nothing to do, it is not there yet |
473
|
|
|
|
|
|
|
# Still make sure it is removed from the properties hash as well |
474
|
|
|
|
|
|
|
else |
475
|
|
|
|
|
|
|
{ |
476
|
0
|
|
|
|
|
0
|
$props->delete( $prop ); |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
} |
479
|
9
|
|
|
|
|
271
|
return( $bool ); |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
else |
482
|
|
|
|
|
|
|
{ |
483
|
23
|
100
|
|
|
|
214
|
return( defined( $pos ) ? 1 : 0 ); |
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
# Used by Cache-Control, Expect-CT |
488
|
|
|
|
|
|
|
sub _set_get_property_number |
489
|
|
|
|
|
|
|
{ |
490
|
18
|
|
|
18
|
|
51
|
my $self = shift( @_ ); |
491
|
18
|
|
50
|
|
|
79
|
my $prop = shift( @_ ) || return( $self->error( "No parameter name was provided." ) ); |
492
|
18
|
100
|
|
|
|
65
|
if( @_ ) |
493
|
|
|
|
|
|
|
{ |
494
|
2
|
|
|
|
|
6
|
my $v = shift( @_ ); |
495
|
2
|
50
|
66
|
|
|
16
|
return( $self->error( "The value provided for property \"${prop}\" is not a number." ) ) if( defined( $v ) && !$self->_is_integer( $v ) ); |
496
|
2
|
|
|
|
|
27
|
return( $self->_set_get_property_value( $prop => $v ) ); |
497
|
|
|
|
|
|
|
} |
498
|
16
|
|
|
|
|
78
|
return( $self->_set_get_property_value( $prop ) ); |
499
|
|
|
|
|
|
|
} |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
# Used by Expect-CT |
502
|
|
|
|
|
|
|
sub _set_get_property_value |
503
|
|
|
|
|
|
|
{ |
504
|
76
|
|
|
76
|
|
151
|
my $self = shift( @_ ); |
505
|
76
|
|
50
|
|
|
220
|
my $prop = shift( @_ ) || return( $self->error( "No parameter name was provided." ) ); |
506
|
76
|
|
|
|
|
135
|
my $opts = {}; |
507
|
76
|
100
|
|
|
|
215
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
508
|
76
|
|
100
|
|
|
362
|
$opts->{needs_quotes} //= 0; |
509
|
76
|
|
100
|
|
|
302
|
$opts->{maybe_boolean} //= 0; |
510
|
76
|
|
|
|
|
178
|
my $params = $self->params; |
511
|
76
|
|
|
|
|
58684
|
my $props = $self->properties; |
512
|
76
|
|
|
|
|
56332
|
my $pos = $params->pos( $prop ); |
513
|
76
|
100
|
|
|
|
2276
|
if( @_ ) |
514
|
|
|
|
|
|
|
{ |
515
|
4
|
|
|
|
|
21
|
my $v = shift( @_ ); |
516
|
4
|
100
|
|
|
|
15
|
if( !defined( $v ) ) |
517
|
|
|
|
|
|
|
{ |
518
|
2
|
50
|
|
|
|
9
|
$self->params->splice( $pos, 1 ) if( defined( $pos ) ); |
519
|
2
|
|
|
|
|
1155
|
return( $self->properties->delete( $prop ) ); |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# Not there yet, add the value |
523
|
2
|
50
|
|
|
|
20
|
if( !defined( $pos ) ) |
524
|
|
|
|
|
|
|
{ |
525
|
2
|
50
|
0
|
|
|
19
|
$params->push( $prop ) if( !$opts->{maybe_boolean} || ( $opts->{maybe_boolean} && $v ) ); |
|
|
|
33
|
|
|
|
|
526
|
2
|
50
|
33
|
|
|
26
|
if( exists( $opts->{maybe_boolean} ) && $opts->{maybe_boolean} ) |
527
|
|
|
|
|
|
|
{ |
528
|
0
|
0
|
|
|
|
0
|
if( $v == 1 ) |
|
|
0
|
|
|
|
|
|
529
|
|
|
|
|
|
|
{ |
530
|
0
|
|
|
|
|
0
|
$props->{ $prop } = undef; |
531
|
|
|
|
|
|
|
} |
532
|
|
|
|
|
|
|
elsif( !$v ) |
533
|
|
|
|
|
|
|
{ |
534
|
0
|
|
|
|
|
0
|
$props->delete( $prop ); |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
else |
537
|
|
|
|
|
|
|
{ |
538
|
0
|
|
|
|
|
0
|
$props->{ $prop } = $v; |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
else |
542
|
|
|
|
|
|
|
{ |
543
|
2
|
|
|
|
|
13
|
$props->{ $prop } = $v; |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
} |
546
|
|
|
|
|
|
|
else |
547
|
|
|
|
|
|
|
{ |
548
|
0
|
0
|
0
|
|
|
0
|
if( exists( $opts->{maybe_boolean} ) && $opts->{maybe_boolean} ) |
549
|
|
|
|
|
|
|
{ |
550
|
0
|
0
|
|
|
|
0
|
if( !$v ) |
|
|
0
|
|
|
|
|
|
551
|
|
|
|
|
|
|
{ |
552
|
0
|
|
|
|
|
0
|
$params->splice( $pos, 1 ); |
553
|
0
|
|
|
|
|
0
|
$props->delete( $prop ); |
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
elsif( $v == 1 ) |
556
|
|
|
|
|
|
|
{ |
557
|
0
|
|
|
|
|
0
|
$props->{ $prop } = undef; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
else |
560
|
|
|
|
|
|
|
{ |
561
|
0
|
|
|
|
|
0
|
$props->{ $prop } = $v; |
562
|
|
|
|
|
|
|
} |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
else |
565
|
|
|
|
|
|
|
{ |
566
|
0
|
|
|
|
|
0
|
$props->{ $prop } = $v; |
567
|
|
|
|
|
|
|
} |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
# Used for non-standard properties during stringification |
570
|
2
|
100
|
66
|
|
|
86
|
if( $opts->{needs_quotes} && $self->can( '_needs_quotes' ) ) |
571
|
|
|
|
|
|
|
{ |
572
|
1
|
|
|
|
|
8
|
$self->_needs_quotes->set( $prop => 1 ); |
573
|
|
|
|
|
|
|
} |
574
|
2
|
|
|
|
|
566
|
return( $v ); |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
else |
577
|
|
|
|
|
|
|
{ |
578
|
72
|
50
|
|
|
|
172
|
if( defined( $pos ) ) |
579
|
|
|
|
|
|
|
{ |
580
|
|
|
|
|
|
|
return( |
581
|
|
|
|
|
|
|
$opts->{maybe_boolean} |
582
|
|
|
|
|
|
|
? defined( $pos ) ? 1 : 0 |
583
|
72
|
50
|
|
|
|
450
|
: $props->{ $prop } |
|
|
100
|
|
|
|
|
|
584
|
|
|
|
|
|
|
); |
585
|
|
|
|
|
|
|
} |
586
|
0
|
|
|
|
|
0
|
return( '' ); |
587
|
|
|
|
|
|
|
} |
588
|
|
|
|
|
|
|
} |
589
|
|
|
|
|
|
|
|
590
|
|
|
|
|
|
|
# Same as _set_get_param but with surrounding double quotes |
591
|
|
|
|
|
|
|
sub _set_get_qparam |
592
|
|
|
|
|
|
|
{ |
593
|
14
|
|
|
14
|
|
44
|
my $self = shift( @_ ); |
594
|
14
|
|
50
|
|
|
55
|
my $name = shift( @_ ) || return( $self->error( "No parameter name was provided." ) ); |
595
|
14
|
|
50
|
|
|
40
|
my $hv = $self->_hv || return( $self->error( "Header value object could not be found!" ) ); |
596
|
14
|
|
|
|
|
431
|
my $v; |
597
|
14
|
50
|
|
|
|
41
|
if( @_ ) |
598
|
|
|
|
|
|
|
{ |
599
|
0
|
|
|
|
|
0
|
$v = shift( @_ ); |
600
|
0
|
|
|
|
|
0
|
$v =~ s/^\"//; |
601
|
0
|
|
|
|
|
0
|
$v =~ s/(?<!\\)\"$//; |
602
|
0
|
|
|
|
|
0
|
$hv->param( $name => qq{"${v}"} ); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
else |
605
|
|
|
|
|
|
|
{ |
606
|
14
|
|
|
|
|
50
|
$v = $hv->param( $name ); |
607
|
14
|
100
|
100
|
|
|
8203
|
return( '' ) if( !defined( $v ) || !length( "$v" ) ); |
608
|
11
|
|
|
|
|
34
|
$v =~ s/^\"//; |
609
|
11
|
|
|
|
|
28
|
$v =~ s/(?<!\\)\"$//; |
610
|
|
|
|
|
|
|
} |
611
|
11
|
|
|
|
|
76
|
return( $v ); |
612
|
|
|
|
|
|
|
} |
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
sub _set_get_value |
615
|
|
|
|
|
|
|
{ |
616
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
617
|
0
|
|
|
|
|
0
|
my $hv = $self->_hv; |
618
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
619
|
|
|
|
|
|
|
{ |
620
|
0
|
|
|
|
|
0
|
$hv->value( shift( @_ ) ); |
621
|
|
|
|
|
|
|
} |
622
|
0
|
|
|
|
|
0
|
return( $hv->value_data ); |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
# NOTE: sub FREEZE is inherited |
626
|
|
|
|
|
|
|
|
627
|
21
|
|
|
21
|
0
|
1564
|
sub STORABLE_freeze { CORE::return( CORE::shift->FREEZE( @_ ) ); } |
628
|
|
|
|
|
|
|
|
629
|
21
|
|
|
21
|
0
|
13262
|
sub STORABLE_thaw { CORE::return( CORE::shift->THAW( @_ ) ); } |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
# NOTE: sub THAW is inherited |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
# NOTE: HTTP::Promise::Field::QualityValue class |
634
|
|
|
|
|
|
|
{ |
635
|
|
|
|
|
|
|
package |
636
|
|
|
|
|
|
|
HTTP::Promise::Field::QualityValue; |
637
|
|
|
|
|
|
|
BEGIN |
638
|
0
|
|
|
|
|
0
|
{ |
639
|
11
|
|
|
11
|
|
17219
|
use strict; |
|
11
|
|
|
|
|
40
|
|
|
11
|
|
|
|
|
435
|
|
640
|
11
|
|
|
11
|
|
113
|
use warnings; |
|
11
|
|
|
|
|
28
|
|
|
11
|
|
|
|
|
585
|
|
641
|
11
|
|
|
11
|
|
93
|
use parent qw( Module::Generic ); |
|
11
|
|
|
|
|
37
|
|
|
11
|
|
|
|
|
77
|
|
642
|
|
|
|
|
|
|
use overload ( |
643
|
|
|
|
|
|
|
'""' => 'as_string', |
644
|
70
|
|
|
70
|
|
2446
|
'bool' => sub{1}, |
645
|
11
|
|
|
11
|
|
1122
|
); |
|
11
|
|
|
0
|
|
37
|
|
|
11
|
|
|
|
|
136
|
|
646
|
|
|
|
|
|
|
}; |
647
|
|
|
|
|
|
|
|
648
|
|
|
|
|
|
|
sub as_string |
649
|
|
|
|
|
|
|
{ |
650
|
67
|
|
|
67
|
|
1197
|
my $self = shift( @_ ); |
651
|
67
|
|
|
|
|
145
|
my $elem = $self->element; |
652
|
67
|
|
|
|
|
54098
|
my $val = $self->value; |
653
|
67
|
100
|
66
|
|
|
50680
|
return( $elem ) if( !defined( $val ) || !length( "${val}" ) ); |
654
|
44
|
|
|
|
|
401
|
return( "${elem};q=${val}" ); |
655
|
|
|
|
|
|
|
} |
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
sub init |
658
|
|
|
|
|
|
|
{ |
659
|
35
|
|
|
35
|
|
2711
|
my $self = shift( @_ ); |
660
|
35
|
|
|
|
|
80
|
my $elem = shift( @_ ); |
661
|
35
|
50
|
33
|
|
|
210
|
return( $self->error( "No element was provided for this quality value." ) ) if( !defined( $elem ) || !length( "$elem" ) ); |
662
|
35
|
|
|
|
|
95
|
my $val = shift( @_ ); |
663
|
35
|
50
|
|
|
|
131
|
$self->SUPER::init( @_ ) || return( $self->pass_error ); |
664
|
35
|
|
|
|
|
123
|
$self->element( $elem ); |
665
|
35
|
|
|
|
|
66192
|
$self->value( $val ); |
666
|
35
|
|
|
|
|
1046452
|
return( $self ); |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
123
|
|
|
123
|
|
5437
|
sub element { return( shift->_set_get_scalar_as_object( 'element', @_ ) ); } |
670
|
|
|
|
|
|
|
|
671
|
124
|
|
|
124
|
|
10629
|
sub value { return( shift->_set_get_number( { field => 'value', undef_ok => 1 }, @_ ) ); } |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
# NOTE: sub FREEZE is inherited |
674
|
|
|
|
|
|
|
|
675
|
17
|
|
|
17
|
|
10467
|
sub STORABLE_freeze { CORE::return( CORE::shift->FREEZE( @_ ) ); } |
676
|
|
|
|
|
|
|
|
677
|
17
|
|
|
17
|
|
13934
|
sub STORABLE_thaw { CORE::return( CORE::shift->THAW( @_ ) ); } |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
# NOTE: sub THAW is inherited |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
1; |
684
|
|
|
|
|
|
|
# NOTE: POD |
685
|
|
|
|
|
|
|
__END__ |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
=encoding utf-8 |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
=head1 NAME |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
HTTP::Promise::Headers::Generic - Generic HTTP Header Class |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
=head1 SYNOPSIS |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
package HTTP::Promise::Headers::MyHeader; |
696
|
|
|
|
|
|
|
use strict; |
697
|
|
|
|
|
|
|
use warnings; |
698
|
|
|
|
|
|
|
use parent qw( HTTP::Promise::Headers::Generic ); |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
=head1 VERSION |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
v0.1.1 |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=head1 DESCRIPTION |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
This is a generic module to be inherited by HTTP header modules. See for example: L<HTTP::Promise::Headers::AcceptEncoding>, L<HTTP::Promise::Headers::AcceptLanguage>, L<HTTP::Promise::Headers::Accept>, L<HTTP::Promise::Headers::AltSvc>, L<HTTP::Promise::Headers::CacheControl>, L<HTTP::Promise::Headers::ClearSiteData>, L<HTTP::Promise::Headers::ContentDisposition>, L<HTTP::Promise::Headers::ContentRange>, L<HTTP::Promise::Headers::ContentSecurityPolicy>, L<HTTP::Promise::Headers::ContentSecurityPolicyReportOnly>, L<HTTP::Promise::Headers::ContentType>, L<HTTP::Promise::Headers::Cookie>, L<HTTP::Promise::Headers::ExpectCT>, L<HTTP::Promise::Headers::Forwarded>, L<HTTP::Promise::Headers::Generic>, L<HTTP::Promise::Headers::KeepAlive>, L<HTTP::Promise::Headers::Link>, L<HTTP::Promise::Headers::Range>, L<HTTP::Promise::Headers::ServerTiming>, L<HTTP::Promise::Headers::StrictTransportSecurity>, L<HTTP::Promise::Headers::TE> |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=head1 METHODS |
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=head2 as_string |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
Return a string representation of this header field object. |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=head2 field_name |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
Sets or gets the object headers field name |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=head2 uri_escape_utf8 |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
Provided with some string and this returns the URI-escaped version of this using L<URI::Escape::XS> |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
=head2 value |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
By default and superseded by inheriting classes such as Content-Type that has more elaborate value with parameters |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=head1 PRIVATE METHODS |
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
=head2 _filename_decode |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
Provided with a filename, and this will decode it, if necessary, by calling L<HTTP::Promise::Headers/decode_filename> |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
It returns in list context the decoded filename, the character-set and language used and in scalar context the decoded filename. |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
If the filename did not need to be decoded, it will return the filename untouched, so this is quite safe to use. |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
See L<rfc2231|https://tools.ietf.org/html/rfc2231> |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
=head2 _filename_encode |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
Provided with a filename, and an optional language, and this will encode it, if necessary, following the L<rfc2231|https://tools.ietf.org/html/rfc2231> |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
If the filename did not need to be encoded, it returns C<undef>, so be sure to check for the return value. |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
See L<rfc2231|https://tools.ietf.org/html/rfc2231> |
745
|
|
|
|
|
|
|
|
746
|
|
|
|
|
|
|
=head2 _hv |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
Sets or gets the L<header value object|Module::Generic::HeaderValue> |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
=head2 _hv_as_string |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
Returns the L<header value object|Module::Generic::HeaderValue> as a string, if a header value object is set, or an empty string otherwise. |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
=head2 _get_header_value_object |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
This instantiates a new L<header value object|Module::Generic::HeaderValue>, passing it whatever arguments were provided, and return the new object. |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=head2 _make_boundary |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
Returns a new boundary using L<Data::UUID> |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=head2 _new_hv |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
Does the same thing as L</_get_header_value_object> |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=head2 _new_qv_object |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
This instantiates a new quality value object using C<HTTP::Promise::Field::QualityValue>, passing it whatever arguments were provided, and return the new object. |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=head2 _parse_header_value |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
Provided with a string, and this instantiates a new L<header value object|Module::Generic::HeaderValue>, by calling L<Module::Generic::HeaderValue/new_from_header> passing it the string and any other arguments that were provided, and return the new object. |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
=head2 _parse_quality_value |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
Provided with a string representing a quality value, and this will parse it and return a new L<array object|Module::Generic::Array> |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
See L<rfc7231, section 5.3.1|https://tools.ietf.org/html/rfc7231#section-5.3.1> |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
=head2 _qstring_join |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
Provided with a list of strings and this will ensure any special characters are escaped before returning them as one string separated by comma. |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
See also L</_qstring_split> |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
=head2 _qstring_split |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
Provided with a string, and this will split it by comma, mindful of any special characters. |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
It returns an array of the parts split. |
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
=head2 _qv_add |
795
|
|
|
|
|
|
|
|
796
|
|
|
|
|
|
|
Provided with an element and its value, and this will instantiate a new C<HTTP::Promise::Field::QualityValue> object and add it to the list of objects contained with the method C<elements> (implemented in each specific header module) |
797
|
|
|
|
|
|
|
|
798
|
|
|
|
|
|
|
=head2 _qv_as_string |
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
This takes the list of all elements contained with the method C<elements> (implemented in each specific header module) and returns them as a string separated by comma. |
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
=head2 _qv_elements |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
Sets or gets the L<array object|Module::Generic::Array> containing the list of quality values. |
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
=head2 _qv_get |
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
Provided with a quality value element, and this returns its corresponding object if it exists, or an empty string otherwise. |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=head2 _qv_match |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
Provided with a string, and this returns an L<array object|Module::Generic::Array> of matching quality value objects in their order of preference. |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=head2 _qv_match_wildcard |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
This method is used to do the actual work of matching a requested value such as C<fr-FR> or <text/html> depending on the type of header, against the ones announced in the header. |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
For example: |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
Accept: image/* |
825
|
|
|
|
|
|
|
Accept: text/html |
826
|
|
|
|
|
|
|
Accept: */* |
827
|
|
|
|
|
|
|
Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8 |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
Accept-Encoding: gzip |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5 |
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
Accept-Language: fr-FR, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5 |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
This takes an "acceptable" L<scalar object|Module::Generic::Scalar>, an L<array object|Module::Generic::Array> of proposed quality-value objects, and an L<array object|Module::Generic::Array> of original proposed value, and possibly an hash reference of already seen object address. |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
It returns an L<array object|Module::Generic::Array> of matching quality-value objects. |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
=head2 _qv_remove |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
Provided with a quality-value string or object, and this will remove it from the list of elements. |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
It returns the element removed, or upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
=head2 _qv_sort |
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
This takes an optional hash or hash reference of options and returns an L<array object|Module::Generic::Array> of sorted element by their quality-value. |
849
|
|
|
|
|
|
|
|
850
|
|
|
|
|
|
|
Supported options are: |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
=over 4 |
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
=item * C<asc> |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
Boolean. If true, the elements will be sorted in their ascending order, otherwise in their descending order. |
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
=back |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
=head2 _set_get_param_boolean |
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
In retrieval mode, this takes a header value parameter, and this returns its value. |
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
In assignment mode, this takes a header value parameter, and a value, possibly C<undef> and assign it to the given parameter. |
865
|
|
|
|
|
|
|
|
866
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
=head2 _set_get_param |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
In retrieval mode, this takes a header value parameter, and it returns its corresponding value. |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
In assignment mode, this takes a header value parameter, and a value and assign it. |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
=head2 _set_get_params |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
This takes a list of header-value parameter and their corresponding value and set them. |
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
If no argument is provided, this returns the L<array object|Module::Generic::Array> containing all the header-value parameters. |
881
|
|
|
|
|
|
|
|
882
|
|
|
|
|
|
|
=head2 _set_get_properties_as_string |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
This takes an hash or hash reference of options and returns the header-value parameters as a regular string. |
885
|
|
|
|
|
|
|
|
886
|
|
|
|
|
|
|
Supported options are: |
887
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
=over 4 |
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=item * C<equal> |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=item * C<separator> or C<sep> |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
=back |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
=head2 _set_get_property_boolean |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
This sets or gets a boolean value for the given header-value property. |
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
It returns the boolean value for the given property. |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
=head2 _set_get_property_number |
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
This sets or gets a number for the given header-value property. |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
It returns the number value for the given property. |
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
=head2 _set_get_property_value |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
This sets or gets a value for the given header-value property. |
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
It returns the value for the given property. |
917
|
|
|
|
|
|
|
|
918
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
=head2 _set_get_qparam |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
Sets or gets a quality-value parameter. If a value is provided, any double quote found at the bginning or end are removed. |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
It returns the current value. |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
Upon error, this sets an L<error|Module::Generic/error> and returns C<undef> |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
=head2 _set_get_value |
929
|
|
|
|
|
|
|
|
930
|
|
|
|
|
|
|
This sets or gets a header main value. |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
For example C<text/html> in C<text/html; charset=utf-8> |
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
=head1 AUTHOR |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
=head1 SEE ALSO |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
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> |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
Copyright(c) 2022 DEGUEST Pte. Ltd. |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
All rights reserved. |
947
|
|
|
|
|
|
|
|
948
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
949
|
|
|
|
|
|
|
|
950
|
|
|
|
|
|
|
=cut |