File Coverage

lib/HTTP/Promise/Headers.pm
Criterion Covered Total %
statement 535 944 56.6
branch 196 496 39.5
condition 96 379 25.3
subroutine 98 190 51.5
pod 127 142 89.4
total 1052 2151 48.9


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## Asynchronous HTTP Request and Promise - ~/lib/HTTP/Promise/Headers.pm
3             ## Version v0.2.0
4             ## Copyright(c) 2022 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <jack@deguest.jp>
6             ## Created 2022/03/21
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;
15             BEGIN
16             {
17 14     14   367416 use strict;
  14         45  
  14         445  
18 14     14   83 use warnings;
  14         30  
  14         444  
19 14     14   76 use warnings::register;
  14         28  
  14         1661  
20 14     14   628 use parent qw( HTTP::XSHeaders );
  14         332  
  14         100  
21 14     14   123431 use vars qw( $VERSION $EXCEPTION_CLASS $MOD_PERL $SUPPORTED $MOD_PATH );
  14         28  
  14         976  
22 14     14   118 use Config;
  14         31  
  14         566  
23 14     14   74 use Cwd ();
  14         27  
  14         228  
24 14     14   626 use Encode;
  14         14591  
  14         1131  
25 14     14   2463 use HTTP::Promise::Exception;
  14         39  
  14         186  
26 14     14   4468 use HTTP::XSHeaders 0.400004;
  14         271  
  14         365  
27 14     14   95 use IO::File;
  14         29  
  14         1987  
28             # use Nice::Try;
29 14     14   94 use Scalar::Util;
  14         28  
  14         529  
30 14     14   5787 use URI::Escape::XS ();
  14         1114910  
  14         507  
31 14     14   116 use Want;
  14         27  
  14         2993  
32 14 50 33 14   138 if( exists( $ENV{MOD_PERL} )
33             &&
34             ( $MOD_PERL = $ENV{MOD_PERL} =~ /^mod_perl\/(\d+\.[\d\.]+)/ ) )
35             {
36 0         0 select( ( select( STDOUT ), $| = 1 )[ 0 ] );
37 0         0 require Apache2::Log;
38             # For _is_class_loaded method
39 0         0 require Apache2::Module;
40 0         0 require Apache2::ServerUtil;
41 0         0 require Apache2::RequestUtil;
42 0         0 require Apache2::ServerRec;
43 0         0 require ModPerl::Util;
44 0         0 require Apache2::Const;
45 0         0 Apache2::Const->import( compile => qw( :log OK ) );
46             }
47 14     14   121 use constant CRLF => "\015\012";
  14         31  
  14         1456  
48 14   33 14   102 use constant HAS_THREADS => ( $Config{useithreads} && $INC{'threads.pm'} );
  14         41  
  14         1345  
49 14         56 our $EXCEPTION_CLASS = 'HTTP::Promise::Exception';
50 14         26 our $SUPPORTED = {};
51 14         316 our $VERSION = 'v0.2.0';
52             };
53              
54 14     14   78 use strict;
  14         40  
  14         387  
55 14     14   71 use warnings;
  14         29  
  14         44039  
56              
57             my $stderr = IO::File->new;
58             $stderr->fdopen( fileno( STDERR ), 'w' );
59             $stderr->binmode( ':utf8' );
60             $stderr->autoflush( 1 );
61             my $stderr_raw = IO::File->new;
62             $stderr_raw->fdopen( fileno( STDERR ), 'w' );
63             $stderr_raw->binmode( ':raw' );
64             $stderr_raw->autoflush( 1 );
65              
66             our $MOD_PATH = Cwd::abs_path( $INC{ ( __PACKAGE__ =~ s{::}{/}gr ) . '.pm' } );
67              
68             # for mod in `ls -1 ./lib/HTTP/Promise/Headers`; do printf "%-32s => 'HTTP::Promise::Headers::%s',\n" $(echo $(basename $mod ".pm")|tr "[:upper:]" "[:lower:]") $(basename $mod ".pm"); done
69             # or
70             # perl -MModule::Generic::File=file -lE 'my $d=file("./lib/HTTP/Promise/Headers"); my $files=$d->content; $files->for(sub{ my$f=file($_); printf("%-32s => ''HTTP::Promise::Headers::%s'',\n", $f->basename(".pm")->lc, $f->basename(".pm")) })'
71             our $SUPPORTED =
72             {
73             accept => 'HTTP::Promise::Headers::Accept',
74             acceptencoding => 'HTTP::Promise::Headers::AcceptEncoding',
75             acceptlanguage => 'HTTP::Promise::Headers::AcceptLanguage',
76             altsvc => 'HTTP::Promise::Headers::AltSvc',
77             cachecontrol => 'HTTP::Promise::Headers::CacheControl',
78             clearsitedata => 'HTTP::Promise::Headers::ClearSiteData',
79             contentdisposition => 'HTTP::Promise::Headers::ContentDisposition',
80             contentrange => 'HTTP::Promise::Headers::ContentRange',
81             contentsecuritypolicy => 'HTTP::Promise::Headers::ContentSecurityPolicy',
82             contentsecuritypolicyreportonly => 'HTTP::Promise::Headers::ContentSecurityPolicyReportOnly',
83             contenttype => 'HTTP::Promise::Headers::ContentType',
84             cookie => 'HTTP::Promise::Headers::Cookie',
85             expectct => 'HTTP::Promise::Headers::ExpectCT',
86             forwarded => 'HTTP::Promise::Headers::Forwarded',
87             generic => 'HTTP::Promise::Headers::Generic',
88             keepalive => 'HTTP::Promise::Headers::KeepAlive',
89             link => 'HTTP::Promise::Headers::Link',
90             range => 'HTTP::Promise::Headers::Range',
91             servertiming => 'HTTP::Promise::Headers::ServerTiming',
92             stricttransportsecurity => 'HTTP::Promise::Headers::StrictTransportSecurity',
93             te => 'HTTP::Promise::Headers::TE',
94             wantdigest => 'HTTP::Promise::Headers::WantDigest',
95             };
96              
97             sub new
98             {
99 188     188 1 21759 my $this = shift( @_ );
100 188         600 my $opts = {};
101 188 100       996 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
102 188         494 my $self;
103             # try-catch
104 188         507 local $@;
105             eval
106 188         601 {
107 188         2421 $self = $this->SUPER::new( @_ );
108             };
109 188 50       799 if( $@ )
110             {
111 0         0 return( $this->error( "Error instantiating an HTTP::Promise::Headers object: $@" ) );
112             }
113 188         1103 $self->{default_type} = undef;
114 188         658 $self->{_init_strict_use_sub} = 1;
115 188         1061 $self->{_exception_class} = $EXCEPTION_CLASS;
116 188 100       1316 $self->debug( $opts->{debug} ) if( CORE::exists( $opts->{debug} ) );
117 188         958 $self->{_ctype_cached} = '';
118 188         1211 return( $self );
119             }
120              
121             # e.g. text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
122             sub accept
123             {
124 0     0 1 0 my $self = shift( @_ );
125 0 0       0 if( @_ )
126             {
127 0         0 my $types = $self->_get_args_as_array( @_ );
128 0         0 $self->header( accept => $types );
129 0         0 CORE::delete( $self->{acceptables} );
130             }
131 0         0 return( $self->_set_get_one( 'Accept' ) );
132             }
133              
134             # Obsolete header that should not be used
135 0     0 1 0 sub accept_charset { return( shift->_set_get_one( 'Accept-Charset', @_ ) ); }
136              
137             # e.g. gzip, deflate, br
138 0     0 1 0 sub accept_encoding { return( shift->_set_get_multi( 'Accept-Encoding', @_ ) ); }
139              
140             # e.g.: en-GB,fr-FR;q=0.8,fr;q=0.6,ja;q=0.4,en;q=0.2
141 0     0 1 0 sub accept_language { return( shift->_set_get_multi( 'Accept-Language', @_ ) ); }
142              
143             # NOTE: Accept-Patch is a response header
144             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Patch>
145 0     0 1 0 sub accept_patch { return( shift->_set_get_one( 'Accept-Patch', @_ ) ); }
146              
147             # NOTE: Accept-Post is a response header
148             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Post>
149 0     0 1 0 sub accept_post { return( shift->_set_get_multi( 'Accept-Post', @_ ) ); }
150              
151             # NOTE: Accept-Tanges is a response header
152             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Ranges>
153 0     0 1 0 sub accept_ranges { return( shift->_set_get_multi( 'Accept-Ranges', @_ ) ); }
154              
155             sub acceptables
156             {
157 0     0 1 0 my $self = shift( @_ );
158 0 0       0 return( $self->{acceptables} ) if( $self->{acceptables} );
159 0         0 my $accept_raw = $self->accept;
160 0 0       0 if( $accept_raw )
161             {
162 0   0     0 my $f = $self->new_field( accept => $accept_raw ) ||
163             return( $self->pass_error );
164 0         0 $self->{acceptables} = $f;
165             }
166 0         0 return( $self->{acceptables} );
167             }
168              
169 1     1 1 120 sub add { return( shift->push_header( @_ ) ); }
170              
171             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Age>
172 0     0 1 0 sub age { return( shift->_set_get_one( 'Age', @_ ) ); }
173              
174             # NOTE: Allow is a response header
175             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Allow>
176 0     0 1 0 sub allow { return( shift->_set_get_multi( 'Allow', @_ ) ); }
177              
178             # Response header: <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials>
179 0     0 1 0 sub allow_credentials { return( shift->_set_get_one( 'Access-Control-Allow-Credentials', @_ ) ); }
180              
181             # Response header <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers>
182 0     0 1 0 sub allow_headers { return( shift->_set_get_multi( 'Access-Control-Allow-Headers', @_ ) ); }
183              
184             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods>
185 0     0 1 0 sub allow_methods { return( shift->_set_get_one( 'Access-Control-Allow-Methods', @_ ) ); }
186              
187             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin>
188 0     0 1 0 sub allow_origin { return( shift->_set_get_one( 'Access-Control-Allow-Origin', @_ ) ); }
189              
190             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc>
191 0     0 1 0 sub alt_svc { return( shift->_set_get_multi( 'Alt-Svc', @_ ) ); }
192              
193             sub alternate_server
194             {
195 0     0 1 0 my $self = shift( @_ );
196 0 0       0 if( @_ )
197             {
198             # { name => 'h2', value => 'alt.example.com:443', ma => 2592000, persist => 1
199 0         0 my $def = $self->_get_args_as_hash( @_ );
200 0         0 my $name = CORE::delete( $def->{name} );
201 0         0 my $value = CORE::delete( $def->{value} );
202 0   0     0 my $f = $self->new_field( alt_svc => [$name => $value], $def ) ||
203             return( $self->pass_error );
204 0         0 $self->push_header( 'Alt-Svc' => "$f" );
205             }
206             else
207             {
208 0         0 my $all = $self->alt_svc;
209 0 0       0 return( $all ) if( !$all->length );
210 0         0 my $a = $self->new_array;
211             $all->foreach(sub
212             {
213 0   0 0   0 my $f = $self->new_field( alt_svc => $_ ) ||
214             return( $self->pass_error );
215 0         0 $a->push( $f );
216 0         0 });
217 0         0 return( $a );
218             }
219             }
220              
221             # NOTE: as_string() is inherited
222             # NOTE: unfortunately, HTTP::XSHeaders is not dealing with as_string properly
223             # It takes the given eol and replace simply any instance in-between line of \n with it,
224             # thus if you have something like: foo\r\nbar\r\n, it will end up with
225             # foo\r\r\nbar\r\n instead of foot\r\nbar\r\n
226             # Bug report #10 <https://github.com/p5pclub/http-xsheaders/issues/10>
227             # sub as_string { return( shift->SUPER::as_string( @_ ? @_ : ( CRLF ) ) ); }
228             sub as_string
229             {
230 100     100 1 58368 my $self = shift( @_ );
231 100         430 my $type = $self->type;
232             # If the type is multipart, ensure we have a boundary set.
233             # This is a convenience for the user, who only needs to set the mime-type
234             # without having to worry about generating a boundary.
235 100 100 100     439 if( defined( $type ) && lc( [split( '/', $type, 2 )]->[0] ) eq 'multipart' )
236             {
237 8         325 my $boundary = $self->multipart_boundary;
238 8 100       226 unless( $boundary )
239             {
240 2         22 $boundary = $self->make_boundary;
241 2         25 my $ct = $self->new_field( 'Content-Type' => $type );
242 2         10 $ct->boundary( $boundary );
243 2         1070 $self->content_type( "$ct" );
244             }
245             }
246 100 100       2225 my $str = $self->SUPER::as_string( @_ ? @_ : ( CRLF ) );
247 100 100       39098 if( index( $str, "\r\r\n" ) != -1 )
248             {
249 1         8 $str =~ s/\r\r\n/\r\n/g;
250             }
251 100         626 return( $str );
252             }
253              
254             # NOTE: authorization() is inherited
255 1     1 1 450 sub authorization { return( shift->_set_get_one( 'Authorization', @_ ) ); }
256              
257             # NOTE: authorization_basic() is inherited
258 7     7 1 2638 sub authorization_basic { return( shift->_basic_auth( 'Authorization', @_ ) ); }
259              
260             sub boundary
261             {
262 7     7 1 58 my $self = shift( @_ );
263 7 50       33 if( @_ )
264             {
265 0         0 my $boundary = shift( @_ );
266 0         0 my $ct = $self->content_type;
267 0         0 $self->{boundary} = $boundary;
268             # If there is a content type set, add the charset to it; otherwise, just return
269             # User should set the content type before setting the charset
270 0 0       0 return( '' ) if( !length( $ct ) );
271 0   0     0 my $f = $self->new_field( content_type => $ct ) ||
272             return( $self->pass_error );
273 0         0 $f->param( boundary => $boundary );
274 0         0 $self->{type} = $f->type;
275 0         0 $self->content_type( $f );
276 0         0 $self->{_ctype_cached} = "$f";
277             }
278 7 100 100     82 unless( length( $self->{boundary} ) && $self->{_ctype_cached} eq $self->content_type )
279             {
280 4         89 my $ct = $self->content_type;
281 4 50       85 my $f = $self->new_field( content_type => ( defined( $ct ) ? "$ct" : () ) );
282 4         24 $self->{boundary} = $f->boundary;
283 4         2172 $self->{type} = $f->type;
284 4         147526 $self->{_ctype_cached} = $ct;
285             }
286 7         200 return( $self->{boundary} );
287             }
288              
289             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control>
290 1     1 1 18 sub cache_control { return( shift->_set_get_one( 'Cache-Control', @_ ) ); }
291              
292             sub charset
293             {
294 0     0 1 0 my $self = shift( @_ );
295 0 0       0 if( @_ )
296             {
297 0         0 my $charset = shift( @_ );
298 0         0 my $ct = $self->content_type;
299 0         0 $self->{charset} = $charset;
300             # If there is a content type set, add the charset to it; otherwise, just return
301             # User should set the content type before setting the charset
302 0 0       0 return( '' ) if( !length( $ct ) );
303 0   0     0 my $f = $self->new_field( content_type => $ct ) || return( $self->pass_error );
304 0         0 $f->param( charset => $charset );
305 0         0 $self->content_type( $f );
306             }
307 0 0       0 unless( length( $self->{charset} ) )
308             {
309 0         0 my $ct = $self->content_type;
310 0         0 my $f = $self->new_field( content_type => $ct );
311 0         0 $self->{charset} = $f->charset;
312             }
313 0         0 return( $self->{charset} );
314             }
315              
316             # NOTE: clear() is inherited
317              
318             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data>
319 0     0 1 0 sub clear_site_data { return( shift->_set_get_multi( 'Clear-Site-Data', @_ ) ); }
320              
321 36     36 0 91 sub client_date { return( shift->_date_header( 'Client-Date', @_ ) ); }
322              
323             # NOTE: clone() is inherited
324              
325             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection>
326 0     0 1 0 sub connection { return( shift->_set_get_one( 'Connection', @_ ) ); }
327              
328             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition>
329 51     51 1 1118417 sub content_disposition { return( shift->_set_get_one( 'Content-Disposition', @_ ) ); }
330              
331             # NOTE: content_encoding() is implemented in our parent class, but our implementation differs
332 136     136 1 3056 sub content_encoding { return( shift->_set_get_one( 'Content-Encoding', @_ ) ); }
333              
334             # NOTE: content_is_html() is already implemented by our parent class, but our implementation of content_type() differs
335             sub content_is_html
336             {
337 2     2 1 1513 my $self = shift( @_ );
338 2         10 my $type = $self->type;
339 2 50 33     22 return(0) if( !defined( $type ) || !length( "$type" ) );
340 2         10 $type = lc( $type );
341 2   66     19 return( $type eq 'text/html' || $self->content_is_xhtml );
342             }
343              
344             sub content_is_json
345             {
346 0     0 1 0 my $self = shift( @_ );
347 0         0 my $type = $self->type;
348 0 0 0     0 return(0) if( !defined( $type ) || !length( "$type" ) );
349 0         0 $type = lc( $type );
350 0         0 return( $type eq 'application/json' );
351             }
352              
353             sub content_is_text
354             {
355 16     16 1 53 my $self = shift( @_ );
356 16         100 my $type = $self->content_type;
357 16 100 66     382 return(0) if( !defined( $type ) || !length( "$type" ) );
358 14         239 return( $$type =~ m,^text/,i );
359             }
360              
361             # NOTE: content_is_xhtml() is already implemented by our parent class, but our implementation of content_type() differs
362             sub content_is_xhtml
363             {
364 3     3 1 6 my $self = shift( @_ );
365 3         52 my $type = $self->type;
366 3 50 33     7 return(0) if( !defined( $type ) || !length( "$type" ) );
367 3         58 $type = lc( $type );
368 3   66     28 return( $type eq 'application/xhtml+xml' || $type eq 'application/vnd.wap.xhtml+xml' );
369             }
370              
371             # NOTE: content_is_xml() is already implemented by our parent class, but our implementation of content_type() differs
372             sub content_is_xml
373             {
374 28     28 1 131 my $self = shift( @_ );
375 28         311 my $type = $self->type;
376 28 100 66     222 return(0) if( !defined( $type ) || !length( "$type" ) );
377 24         544 $type = lc( $type );
378 24 50       176 return(1) if( $type eq 'text/xml' );
379 24 100       117 return(1) if( $type eq 'application/xml' );
380 21 100       179 return(1) if( $type =~ /\+xml$/ );
381 20         203 return(0);
382             }
383              
384             # NOTE: content_language() is implemented in our parent class, but our implementation differs
385 3     3 1 930 sub content_language { return( shift->_set_get_multi( 'Content-Language', @_ ) ); }
386              
387             # NOTE: content_length() is implemented in our parent class, but our implementation differs
388 24     24 1 245 sub content_length { return( shift->_set_get_one_number( 'Content-Length', @_ ) ); }
389              
390             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Location>
391 0     0 1 0 sub content_location { return( shift->_set_get_one( 'Content-Location', @_ ) ); }
392              
393             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range>
394 0     0 1 0 sub content_range { return( shift->_set_get_one( 'Content-Range', @_ ) ); }
395              
396             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy>
397 0     0 1 0 sub content_security_policy { return( shift->_set_get_one( 'Content-Security-Policy', @_ ) ); }
398              
399 0     0 1 0 sub content_security_policy_report_only { return( shift->_set_get_one( 'Content-Security-Policy-Report-Only', @_ ) ); }
400              
401             # NOTE: content_type() is already implemented by our parent class, but we our implementation is more straightforward in line with the idea of setting and getting exactly the header field value.
402             # Arguably, it is wrong to expect the return value of content_type to be only the mime_type, thus there is the type() method for that
403             sub content_type
404             {
405 403     403 1 516836 my $self = shift( @_ );
406 403         598 my $v;
407 403 100       940 if( @_ )
408             {
409 16         82 $v = shift( @_ );
410 16         194 $self->header( content_type => $v );
411             # Simple value, set the type() cache
412 16 100       109 if( index( $v, ';' ) == -1 )
413             {
414 8         30 $self->{type} = $v;
415             }
416             # Force type() to find the mime-type
417             else
418             {
419 8         514433 $self->{type} = '';
420             }
421            
422 16 100       173 return( $self->new_scalar( ref( $v ) ? "$v" : \$v ) );
423             }
424             else
425             {
426 387         1856 $v = $self->header( 'Content-Type' );
427             }
428            
429 387 100       1343 if( defined( $v ) )
    50          
430             {
431 241 100       1486 return( $self->new_scalar( ref( $v ) ? "$v" : \$v ) );
432             }
433             elsif( want( 'OBJECT' ) )
434             {
435 0         0 return( Module::Generic::Null->new );
436             }
437             else
438             {
439 146         8339 return;
440             }
441             }
442              
443             # NOTE: content_type_charset() is inherited
444              
445             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy>
446 0     0 1 0 sub cross_origin_embedder_policy { return( shift->_set_get_one( 'Cross-Origin-Embedder-Policy', @_ ) ); }
447              
448             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy>
449 0     0 1 0 sub cross_origin_opener_policy { return( shift->_set_get_one( 'Cross-Origin-Opener-Policy', @_ ) ); }
450              
451             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy>
452 0     0 1 0 sub cross_origin_resource_policy { return( shift->_set_get_one( 'Cross-Origin-Resource-Policy', @_ ) ); }
453              
454 0     0 1 0 sub cspro { return( shift->content_security_policy_report_only( @_ ) ); }
455              
456             # NOTE: date() is already implemented by our parent class, but our implementation is more versatile and better
457 51     51 1 4454 sub date { return( shift->_date_header( 'Date', @_ ) ); }
458              
459             # rfc2231 <https://datatracker.ietf.org/doc/html/rfc2231>
460             sub decode_filename
461             {
462 11     11 1 38 my $self = shift( @_ );
463 11         24 my $fname = shift( @_ );
464 11 50 33     73 return( $fname ) if( !defined( $fname ) || !length( $fname ) );
465 11         26 my( $charset, $lang );
466 11 100       103 if( $fname =~ /^(.*?)\'([^\']*)\'(.*?)$/ )
    100          
467             {
468 1         7 ( $charset, $lang, my $encoded_fname ) = ( $1, $2, $3 );
469 1 50 33     8 unless( lc( $charset ) eq 'utf8' || lc( $charset ) eq 'utf-8' )
470             {
471 0         0 return( $self->error( "Character set '$charset' is not supported for file name '$encoded_fname'" ) );
472             }
473             # The language parameter, if any, is discarded
474 1         19 $fname = Encode::decode_utf8( URI::Escape::XS::uri_unescape( $encoded_fname ) );
475             }
476             # rfc2047 encoded?
477             elsif( $fname =~ /^=\?(.+?)\?(.+?)\?(.+)\?=$/ )
478             {
479 4         12 $charset = $1;
480 4         9 my $encoding = uc( $2 );
481 4         10 my $encfile = $3;
482              
483 4 100 100     34 if( $encoding eq 'Q' || $encoding eq 'B' )
484             {
485             eval
486 3         9 {
487 3 100       12 if( $encoding eq 'Q' )
488             {
489 1         3 $encfile =~ s/_/ /g;
490 1 50       5 $self->_load_class( 'HTTP::Promise::Stream' ) || return( $self->pass_error );
491 1   50     39 my $s = HTTP::Promise::Stream->new( \$encfile, { decoding => 'quoted-printable' } ) ||
492             return( $self->pass_error( HTTP::Promise::Stream->error ) );
493 1         18 my $decoded = $s->decode;
494 1 50       37 return( $self->pass_error( $s->error ) ) if( !defined( $decoded ) );
495 1         16 $encfile = $decoded;
496             }
497             # $encoding eq 'B'
498             else
499             {
500 2 50       8 $self->_load_class( 'Crypt::Misc' ) || return( $self->pass_error );
501 2         37 $encfile = Crypt::Misc::decode_b64( $encfile );
502             }
503             };
504            
505 3 50       31 if( $@ )
506             {
507             # return( $self->error( "Error decoding content disposition file name: $e" ) );
508 0         0 warnings::warnif( "Error decoding content disposition file name: $@" );
509             }
510            
511             eval
512 3         5 {
513 3 50       12 $self->_load_class( 'Encode' ) || return( $self->pass_error );
514 3 50       12 $self->_load_class( 'Encode::Locale' ) || return( $self->pass_error );
515 3         23 Encode::from_to( $encfile, $charset, 'locale_fs' );
516 2         756 $fname = $encfile;
517             };
518            
519 3 100       1728 if( $@ )
520             {
521             # return( $self->error( "Error encoding content disposition file name: $e" ) );
522 1         313 warnings::warnif( "Error encoding content disposition file name from '$charset' to 'locale_fs': $@" );
523             }
524             }
525             }
526 11 100       127 return( wantarray() ? ( $fname, $charset, $lang ) : $fname );
527             }
528              
529             sub debug
530             {
531 114     114 1 2204 my $self = shift( @_ );
532 114   33     451 my $class = ( ref( $self ) || $self );
533 14     14   128 no strict 'refs';
  14         38  
  14         6081  
534 114 50       330 if( @_ )
535             {
536 114         249 my $flag = shift( @_ );
537 114         330 $self->{debug} = $flag;
538 114 50 33     479 if( $self->{debug} &&
539             !$self->{debug_level} )
540             {
541 0         0 $self->{debug_level} = $self->{debug};
542             }
543             }
544 114   33     372 return( $self->{debug} || ${"$class\:\:DEBUG"} );
545             }
546              
547 104     104 1 734 sub default_type { return( shift->_set_get( 'default_type', @_ ) ); }
548              
549 0     0 1 0 sub delete { return( shift->remove_header( @_ ) ); }
550              
551             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Device-Memory>
552 0     0 1 0 sub device_memory { return( shift->_set_get_one( 'Device-Memory', @_ ) ); }
553              
554             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest>
555 0     0 1 0 sub digest { return( shift->_set_get_multi( 'Digest', @_ ) ); }
556              
557             # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/DNT
558 0     0 1 0 sub dnt { return( shift->_set_get_one( dnt => @_ ) ); }
559              
560             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Early-Data>
561 0     0 1 0 sub early_data { return( shift->_set_get_one( 'Early-Data', @_ ) ); }
562              
563             # rfc2231 <https://datatracker.ietf.org/doc/html/rfc2231>
564             sub encode_filename
565             {
566 3     3 1 110 my $self = shift( @_ );
567 3         19 my $fname = shift( @_ );
568 3         23 my $lang = shift( @_ );
569 3 50       51 if( $fname =~ /[^\w\.]+/ )
570             {
571 3 50       22 $lang = '' if( !defined( $lang ) );
572 3         62 return( sprintf( "UTF-8'${lang}'%s", $self->uri_escape_utf8( $fname ) ) );
573             }
574             # Nothing to be done. We return undef on purpose to indicate nothing was done
575 0         0 return;
576             }
577              
578             # Copied here from Module::Generic
579             sub error
580             {
581 2     2 1 418 my $self = shift( @_ );
582 2   33     8 my $class = ref( $self ) || $self;
583 14     14   113 no warnings;
  14         28  
  14         817  
584 2         3 our $MOD_PERL;
585 2         5 my $o;
586 14     14   88 no strict 'refs';
  14         43  
  14         19418  
587 2 100       7 if( @_ )
588             {
589 1         2 my $args = {};
590             # We got an object as first argument. It could be a child from our exception package or from another package
591             # Either way, we use it as it is
592 1 50 33     13 if( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) ) ||
    50 33        
593             Scalar::Util::blessed( $_[0] ) )
594             {
595 0         0 $o = shift( @_ );
596             }
597             elsif( ref( $_[0] ) eq 'HASH' )
598             {
599 0         0 $args = shift( @_ );
600             }
601             else
602             {
603 1 50 33     11 $args->{message} = join( '', map( ( ref( $_ ) eq 'CODE' && !$self->{_msg_no_exec_sub} ) ? $_->() : $_, @_ ) );
604             }
605 1   50     6 $args->{class} //= '';
606             my $max_len = ( CORE::exists( $self->{error_max_length} ) && $self->{error_max_length} =~ /^[-+]?\d+$/ )
607             ? $self->{error_max_length}
608 1 50 33     5 : 0;
609 1 50 33     8 $args->{message} = substr( $args->{message}, 0, $self->{error_max_length} ) if( $max_len > 0 && length( $args->{message} ) > $max_len );
610             # Reset it
611 1         2 $self->{_msg_no_exec_sub} = 0;
612             # Note Taken from Carp to find the right point in the stack to start from
613 1         2 my $caller_func;
614 1 50       1 $caller_func = \&{"CORE::GLOBAL::caller"} if( defined( &{"CORE::GLOBAL::caller"} ) );
  0         0  
  1         9  
615 1 50       4 if( defined( $o ) )
616             {
617 0         0 $self->{error} = ${ $class . '::ERROR' } = $o;
  0         0  
618             }
619             else
620             {
621             my $ex_class = CORE::length( $args->{class} )
622             ? $args->{class}
623             : ( CORE::exists( $self->{_exception_class} ) && CORE::length( $self->{_exception_class} ) )
624             ? $self->{_exception_class}
625 1 50 33     15 : 'Module::Generic::Exception';
    50          
626 1 0 50     5 unless( $self->_is_class_loaded( $ex_class ) || scalar( keys( %{"${ex_class}\::"} ) ) )
  0         0  
627             {
628 0         0 my $pl = "use $ex_class;";
629 0     0   0 local $SIG{__DIE__} = sub{};
630 0         0 eval( $pl );
631             # We have to die, because we have an error within another error
632 0 0       0 die( __PACKAGE__ . "::error() is unable to load exception class \"$ex_class\": $@" ) if( $@ );
633             }
634 1         16 $o = $self->{error} = ${ $class . '::ERROR' } = $ex_class->new( $args );
  1         1005  
635             }
636            
637 1         2 my $r;
638 1 50       6 if( $MOD_PERL )
639             {
640             # try-catch
641 0         0 local $@;
642             eval
643 0         0 {
644 0         0 $r = Apache2::RequestUtil->request;
645 0 0       0 $r->warn( $o->as_string ) if( $r );
646             };
647 0 0       0 if( $@ )
648             {
649 0         0 print( STDERR "Error trying to get the global Apache2::ApacheRec: $@\n" );
650             }
651             }
652            
653 1 50 33     10 if( $r )
    50 33        
    50          
654             {
655 0 0       0 if( my $log_handler = $r->get_handlers( 'PerlPrivateErrorHandler' ) )
656             {
657 0         0 $log_handler->( $o );
658             }
659             else
660             {
661 0 0       0 $r->warn( $o->as_string ) if( warnings::enabled() );
662             }
663             }
664 1         125 elsif( $self->{fatal} || ( defined( ${"${class}\::FATAL_ERROR"} ) && ${"${class}\::FATAL_ERROR"} ) )
  0         0  
665             {
666             # my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
667             # die( $@ ? $o : $enc_str );
668 0         0 die( $o );
669             }
670             elsif( warnings::enabled() )
671             {
672 1 50       4 if( $r )
673             {
674 0         0 $r->warn( $o->as_string );
675             }
676             else
677             {
678 1         2 my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
  1         6  
679             # Display warnings if warnings for this class is registered and enabled or if not registered
680 1 50       2994 warn( $@ ? $o : $enc_str );
681             }
682             }
683            
684             # https://metacpan.org/pod/Perl::Critic::Policy::Subroutines::ProhibitExplicitReturnUndef
685             # https://perlmonks.org/index.pl?node_id=741847
686             # Because in list context this would create a lit with one element undef()
687             # A bare return will return an empty list or an undef scalar
688             # return( undef() );
689             # return;
690             # As of 2019-10-13, Module::Generic version 0.6, we use this special package Module::Generic::Null to be returned in chain without perl causing the error that a method was called on an undefined value
691             # 2020-05-12: Added the no_return_null_object to instruct not to return a null object
692             # This is especially needed when an error is called from TIEHASH that returns a special object.
693             # A Null object would trigger a fatal perl segmentation fault
694 1 50 33     12 if( !$args->{no_return_null_object} && want( 'OBJECT' ) )
695             {
696 0         0 require Module::Generic::Null;
697 0         0 my $null = Module::Generic::Null->new( $o, { debug => $self->{debug}, has_error => 1 });
698 0         0 rreturn( $null );
699             }
700 1         77 return;
701             }
702             # To avoid the perl error of 'called on undefined value' and so the user can do
703             # $o->error->message for example without concerning himself/herself whether an exception object is actually set
704 1 50 33     54 if( !$self->{error} && want( 'OBJECT' ) )
705             {
706 0         0 require Module::Generic::Null;
707 0         0 my $null = Module::Generic::Null->new( $o, { debug => $self->{debug}, wants => 'object' });
708 0         0 rreturn( $null );
709             }
710 1 50       15 return( ref( $self ) ? $self->{error} : ${ $class . '::ERROR' } );
  0         0  
711             }
712              
713 0     0 1 0 sub etag { return( shift->_set_get_one( 'Etag', @_ ) ); }
714              
715             sub exists
716             {
717 66     66 1 197 my $self = shift( @_ );
718 66   50     445 my $field = shift( @_ ) || return(0);
719 66         358 my $rv = $self->header( $field );
720 66 50       503 return( defined( $rv ) ? 1 : 0 );
721             }
722              
723             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect>
724 0     0 1 0 sub expect { return( shift->_set_get_one( 'Expect', @_ ) ); }
725              
726             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT>
727 0     0 1 0 sub expect_ct { return( shift->_set_get_multi( 'Expect-CT', @_ ) ); }
728              
729             # NOTE: expires() is inherited
730 25     25 1 10093 sub expires { return( shift->_date_header( 'Expires', @_ ) ); }
731              
732             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers>
733             # e.g.: Access-Control-Expose-Headers: Content-Encoding, X-Kuma-Revision
734 0     0 1 0 sub expose_headers { return( shift->_set_get_multi( 'Access-Control-Expose-Headers', @_ ) ); }
735              
736             # NOTE: flatten() is inherited
737              
738             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded>
739 0     0 1 0 sub forwarded { return( shift->_set_get_one( 'Forwarded', @_ ) ); }
740              
741             # NOTE: from() is inherited
742             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/From>
743 1     1 1 463 sub from { return( shift->_set_get_one( 'From', @_ ) ); }
744              
745 0     0 1 0 sub get { return( shift->header( shift( @_ ) ) ); }
746              
747             # NOTE: header() is inherited
748              
749             # NOTE: header_field_names() is inherited
750              
751 0     0 1 0 sub host { return( shift->_set_get_one( 'Host', @_ ) ); }
752              
753             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match>
754 0     0 1 0 sub if_match { return( shift->_set_get_one( 'If-Match', @_ ) ); }
755              
756             # NOTE: if_modified_since() is inherited
757             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since>
758 4     4 1 3497 sub if_modified_since { return( shift->_date_header( 'If-Modified-Since', @_ ) ); }
759              
760             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match>
761 0     0 1 0 sub if_none_match { return( shift->_set_get_one( 'If-None-Match', @_ ) ); }
762              
763             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Range>
764 0     0 1 0 sub if_range { return( shift->_set_get_one( 'If-Range', @_ ) ); }
765              
766             # NOTE: if_unmodified_since() is inherited
767             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Unmodified-Since>
768 3     3 1 3454 sub if_unmodified_since { return( shift->_date_header( 'If-Unmodified-Since', @_ ) ); }
769              
770             # NOTE: init_header() is inherited
771              
772             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive>
773 0     0 1 0 sub keep_alive { return( shift->_set_get_one( 'Keep-Alive', @_ ) ); }
774              
775             # NOTE: last_modified() is inherited
776             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified>
777 22     22 1 3517 sub last_modified { return( shift->_date_header( 'Last-Modified', @_ ) ); }
778              
779             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link>
780 0     0 1 0 sub link { return( shift->_set_get_multi( 'Link', @_ ) ); }
781              
782             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location>
783 0     0 1 0 sub location { return( shift->_set_get_one( 'Location', @_ ) ); }
784              
785             sub make_boundary
786             {
787 2     2 1 7 my $self = shift( @_ );
788 2 50       9 $self->_load_class( 'Data::UUID' ) || return( $self->pass_error );
789 2         3103 return( Data::UUID->new->create_str );
790             }
791              
792             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age>
793 0     0 1 0 sub max_age { return( shift->_set_get_number( 'Access-Control-Max-Age', @_ ) ); }
794              
795             sub message
796             {
797 0     0 0 0 my $self = shift( @_ );
798 0   0     0 my $class = ref( $self ) || $self;
799 14     14   149 no strict 'refs';
  14         41  
  14         6754  
800 0 0 0     0 if( $self->{verbose} || $self->{debug} || ${ $class . '::DEBUG' } )
  0   0     0  
801             {
802 0         0 my $r;
803 0 0       0 if( $MOD_PERL )
804             {
805             # try-catch
806 0         0 local $@;
807             eval
808 0         0 {
809 0         0 $r = Apache2::RequestUtil->request;
810             };
811 0 0       0 if( $@ )
812             {
813 0         0 $stderr_raw->print( "Error trying to get the global Apache2::ApacheRec: $@\n" );
814             }
815             }
816            
817 0         0 my $ref;
818 0         0 $ref = $self->message_check( @_ );
819 0 0       0 return(1) if( !$ref );
820            
821 0         0 my $opts = {};
822 0 0       0 $opts = pop( @$ref ) if( ref( $ref->[-1] ) eq 'HASH' );
823              
824 0   0     0 my $stackFrame = $self->message_frame( (caller(1))[3] ) || 1;
825 0 0       0 $stackFrame = 1 unless( $stackFrame =~ /^\d+$/ );
826 0 0       0 $stackFrame-- if( $stackFrame );
827 0 0 0     0 $stackFrame++ if( ( (caller(1))[3] // '' ) eq 'HTTP::Promise::Headers::messagef' );
828 0         0 my( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
829 0   0     0 my $sub = ( caller( $stackFrame + 1 ) )[3] // '';
830 0         0 my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
831 0 0       0 if( ref( $self->{_message_frame} ) eq 'HASH' )
832             {
833 0 0       0 if( exists( $self->{_message_frame}->{ $sub2 } ) )
834             {
835 0         0 my $frameNo = int( $self->{_message_frame}->{ $sub2 } );
836 0 0       0 if( $frameNo > 0 )
837             {
838 0         0 ( $pkg, $file, $line, $sub ) = caller( $frameNo );
839 0         0 $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
840             }
841             }
842             }
843 0 0       0 if( $sub2 eq 'message' )
844             {
845 0         0 $stackFrame++;
846 0         0 ( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
847 0   0     0 my $sub = ( caller( $stackFrame + 1 ) )[3] // '';
848 0         0 $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
849             }
850 0         0 my $txt;
851 0 0       0 if( $opts->{message} )
852             {
853 0 0       0 if( ref( $opts->{message} ) eq 'ARRAY' )
854             {
855 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$self->{_msg_no_exec_sub} ) ? $_->() : ( $_ // '' ), @{$opts->{message}} ) );
  0   0     0  
856             }
857             else
858             {
859 0         0 $txt = $opts->{message};
860             }
861             }
862             else
863             {
864 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$self->{_msg_no_exec_sub} ) ? $_->() : ( $_ // '' ), @$ref ) );
      0        
865             }
866             # Reset it
867 0         0 $self->{_msg_no_exec_sub} = 0;
868 0 0       0 my $prefix = CORE::length( $opts->{prefix} ) ? $opts->{prefix} : '##';
869 14     14   113 no overloading;
  14         27  
  14         9472  
870 0 0 0     0 $opts->{caller_info} = 1 if( !CORE::exists( $opts->{caller_info} ) || !CORE::length( $opts->{caller_info} ) );
871 0         0 my $proc_info = " [PID: $$]";
872 0         0 if( HAS_THREADS )
873             {
874             my $tid = threads->tid;
875             $proc_info .= ' -> [thread id ' . $tid . ']' if( $tid );
876             }
877 0 0       0 my $mesg_raw = $opts->{caller_info} ? ( "${pkg}::${sub2}( $self ) [$line]${proc_info}: " . $txt ) : $txt;
878 0         0 $mesg_raw =~ s/\n$//gs;
879 0         0 my $mesg = "${prefix} " . join( "\n${prefix} ", split( /\n/, $mesg_raw ) );
880            
881             my $info =
882             {
883             'formatted' => $mesg,
884             'message' => $txt,
885             'file' => $file,
886             'line' => $line,
887             'package' => $class,
888             'sub' => $sub2,
889 0 0       0 'level' => ( $_[0] =~ /^\d+$/ ? $_[0] : CORE::exists( $opts->{level} ) ? $opts->{level} : 0 ),
    0          
890             };
891 0 0       0 $info->{type} = $opts->{type} if( $opts->{type} );
892            
893             ## If Mod perl is activated AND we are not using a private log
894 0 0 0     0 if( $r && !${ "${class}::LOG_DEBUG" } )
  0 0 0     0  
    0 0        
    0 0        
      0        
      0        
895             {
896 0 0 0     0 if( my $log_handler = $r->get_handlers( 'PerlPrivateLogHandler' ) )
    0          
897             {
898 0         0 $log_handler->( $mesg_raw );
899             }
900             elsif( $self->{_log_handler} && ref( $self->{_log_handler} ) eq 'CODE' )
901             {
902 0         0 $self->{_log_handler}->( $info );
903             }
904             else
905             {
906 0         0 $r->log->debug( $mesg_raw );
907             }
908             }
909             # Using ModPerl Server to log
910 0         0 elsif( $MOD_PERL && !${ "${class}::LOG_DEBUG" } )
911             {
912 0         0 require Apache2::ServerUtil;
913 0         0 my $s = Apache2::ServerUtil->server;
914 0         0 $s->log->debug( $mesg );
915             }
916             # e.g. in our package, we could set the handler using the curry module like $self->{_log_handler} = $self->curry::log
917             elsif( !-t( STDIN ) && $self->{_log_handler} && ref( $self->{_log_handler} ) eq 'CODE' )
918             {
919 0         0 $self->{_log_handler}->( $info );
920             }
921 0         0 elsif( !-t( STDIN ) && ${ $class . '::MESSAGE_HANDLER' } && ref( ${ $class . '::MESSAGE_HANDLER' } ) eq 'CODE' )
  0         0  
922             {
923 0         0 my $h = ${ $class . '::MESSAGE_HANDLER' };
  0         0  
924 0         0 $h->( $info );
925             }
926             # Otherwise just on the stderr
927             else
928             {
929 0 0       0 if( $opts->{no_encoding} )
930             {
931 0         0 $stderr_raw->print( $mesg, "\n" );
932             }
933             else
934             {
935 0         0 $stderr->print( $mesg, "\n" );
936             }
937             }
938             }
939 0         0 return(1);
940             }
941              
942             sub message_check
943             {
944 0     0 0 0 my $self = shift( @_ );
945 0   0     0 my $class = ref( $self ) || $self;
946 14     14   115 no warnings 'uninitialized';
  14         34  
  14         600  
947 14     14   84 no strict 'refs';
  14         24  
  14         26359  
948 0 0       0 if( @_ )
949             {
950 0 0       0 if( $_[0] !~ /^\d/ )
951             {
952             # The last parameter is an options parameter which has the level property set
953 0 0 0     0 if( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
    0 0        
954             {
955             # Then let's use this
956             }
957             elsif( $self->{_message_default_level} =~ /^\d+$/ &&
958             $self->{_message_default_level} > 0 )
959             {
960 0         0 unshift( @_, $self->{_message_default_level} );
961             }
962             else
963             {
964 0         0 unshift( @_, 1 );
965             }
966             }
967             # If the first argument looks line a number, and there is more than 1 argument
968             # and it is greater than 1, and greater than our current debug level
969             # well, we do not output anything then...
970 0 0 0     0 if( ( $_[0] =~ /^\d+$/ ||
      0        
971             ( ref( $_[-1] ) eq 'HASH' &&
972             CORE::exists( $_[-1]->{level} ) &&
973             $_[-1]->{level} =~ /^\d+$/
974             )
975             ) && @_ > 1 )
976             {
977 0         0 my $message_level = 0;
978 0 0 0     0 if( $_[0] =~ /^\d+$/ )
    0          
979             {
980 0         0 $message_level = shift( @_ );
981             }
982             elsif( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
983             {
984 0         0 $message_level = $_[-1]->{level};
985             }
986 0         0 my $target_re = '';
987 0 0       0 if( ref( ${ "${class}::DEBUG_TARGET" } ) eq 'ARRAY' )
  0         0  
988             {
989 0 0       0 $target_re = scalar( @${ "${class}::DEBUG_TARGET" } ) ? join( '|', @${ "${class}::DEBUG_TARGET" } ) : '';
  0         0  
  0         0  
990             }
991 0 0 0     0 if( int( $self->{debug} ) >= $message_level ||
      0        
      0        
      0        
      0        
      0        
      0        
      0        
992             int( $self->{verbose} ) >= $message_level ||
993 0         0 ( defined( ${ $class . '::DEBUG' } ) && ${ $class . '::DEBUG' } >= $message_level ) ||
  0         0  
994             int( $self->{debug_level} ) >= $message_level ||
995             int( $self->{debug} ) >= 100 ||
996 0         0 ( length( $target_re ) && $class =~ /^$target_re$/ && ${ $class . '::GLOBAL_DEBUG' } >= $message_level ) )
997             {
998 0         0 return( [ @_ ] );
999             }
1000             else
1001             {
1002 0         0 return(0);
1003             }
1004             }
1005             }
1006 0         0 return(0);
1007             }
1008              
1009             sub message_frame
1010             {
1011 0     0 0 0 my $self = shift( @_ );
1012 0 0       0 $self->{_message_frame } = {} if( !exists( $self->{_message_frame} ) );
1013 0         0 my $mf = $self->{_message_frame};
1014 0 0       0 if( @_ )
1015             {
1016 0         0 my $args = {};
1017 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
    0          
1018             {
1019 0         0 $args = shift( @_ );
1020 0         0 my @k = keys( %$args );
1021 0         0 @$mf{ @k } = @$args{ @k };
1022             }
1023             elsif( !( @_ % 2 ) )
1024             {
1025 0         0 $args = { @_ };
1026 0         0 my @k = keys( %$args );
1027 0         0 @$mf{ @k } = @$args{ @k };
1028             }
1029             elsif( scalar( @_ ) == 1 )
1030             {
1031 0         0 my $sub = shift( @_ );
1032 0 0       0 $sub = substr( $sub, rindex( $sub, '::' ) + 2 ) if( index( $sub, '::' ) != -1 );
1033 0         0 return( $mf->{ $sub } );
1034             }
1035             else
1036             {
1037 0         0 return( $self->error( "I was expecting a key => value pair such as routine => stack frame (integer)" ) );
1038             }
1039             }
1040 0         0 return( $mf );
1041             }
1042              
1043             # For compatibility for MIME::Decoder->head, itself used by HTTP::Promise::Entity
1044             # "some decoders need to know a little about the file they are encoding/decoding; e.g., x-uu likes to have the filename. The HEAD is any object which responds to messages like:
1045             # $head->mime_attr( 'content-disposition.filename' );
1046             sub mime_attr
1047             {
1048 10     10 1 464 my $self = shift( @_ );
1049 10         65 my( $attr, $value ) = @_;
1050 10 50 33     120 return if( !defined( $attr ) || !length( $attr ) );
1051             # Break attribute name up
1052 10         75 my( $tag, $subtag ) = split( /\./, $attr, 2 );
1053 10         62 my $v = $self->header( $tag );
1054 10         96 require Module::Generic::HeaderValue;
1055 10         27 my $hv;
1056 10 50 33     68 if( defined( $v ) && length( $v ) )
1057             {
1058 10         63 $hv = Module::Generic::HeaderValue->new_from_header( $v );
1059 10 50       61748 return( $self->pass_error( Module::Generic::HeaderValue->error ) ) if( !defined( $hv ) );
1060             }
1061 10 50       56 if( scalar( @_ ) > 1 )
1062             {
1063 0 0       0 if( defined( $subtag ) )
1064             {
1065 0 0       0 return( $self->error( "There is no header field '$tag' currently set, so you cannot assign a value for '$subtag'." ) ) if( !defined( $hv ) );
1066 0         0 $hv->param( $subtag => $value );
1067             }
1068             else
1069             {
1070 0 0       0 if( defined( $hv ) )
1071             {
1072 0         0 $hv->value( $value );
1073             }
1074             else
1075             {
1076 0   0     0 $hv = Module::Generic::HeaderValue->new( $value ) ||
1077             return( $self->pass_error( Module::Generic::HeaderValue->error ) );
1078             }
1079             }
1080 0         0 $self->replace( $tag => "$hv" );
1081 0         0 return( $value );
1082             }
1083             else
1084             {
1085 10 50       39 return( '' ) if( !defined( $hv ) );
1086 10 100       55 return( defined( $subtag ) ? $hv->param( $subtag ) : $hv->value_data );
1087             }
1088             }
1089              
1090             # In HTTP parlance, the request may contain a Content-Encoding in multipart/form-data,
1091             # and the server response may contain Transfer-Encoding to indicate in which encoding the
1092             # response is provided.
1093             sub mime_encoding
1094             {
1095 2     2 1 60 my $self = shift( @_ );
1096 2   33     29 my $te = $self->header( 'Content-Encoding' ) || $self->header( 'Transfer-Encoding' );
1097 2 50 33     16 return( '' ) if( !defined( $te ) || !length( $te ) );
1098 0         0 my $enc = lc( $te );
1099             # 7-bit, 7_bit -> 7bit. Same for 8-bit, 8_bit
1100 0         0 $enc =~ s{^([78])[ _-]bit\Z}{$1bit};
1101 0         0 return( $enc );
1102             }
1103              
1104             sub mime_type
1105             {
1106 115     115 1 480 my $self = shift( @_ );
1107 115   66     1048 my $default = shift( @_ ) || $self->default_type;
1108 115         577 my $ct = $self->type;
1109 115 100 66     640 if( !defined( $ct ) || !length( $ct ) )
1110             {
1111 52 100       165 return( $default ) if( defined( $default ) );
1112 49         275 return( '' );
1113             }
1114 63         1511 return( $ct );
1115             }
1116              
1117             sub multipart_boundary
1118             {
1119 17     17 1 256 my $self = shift( @_ );
1120 17         94 my $ct = $self->content_type;
1121 17 50 33     395 return( '' ) unless( defined( $ct ) && length( "$ct" ) );
1122             # There is no attributes to this Content-Type, so no need to go further.
1123 17 100 66     189 return( '' ) if( index( $ct, ';' ) == -1 || index( $ct, 'boundary' ) == -1 );
1124 15         304 require Module::Generic::HeaderValue;
1125 15   50     189 my $hv = Module::Generic::HeaderValue->new_from_header( $ct ) ||
1126             return( $self->pass_error( Module::Generic::HeaderValue->error ) );
1127 15         93783 my $boundary = $hv->param( 'boundary' );
1128 15         8625 return( $boundary );
1129             }
1130              
1131             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/NEL>
1132 0     0 1 0 sub nel { return( shift->_set_get_one( 'NEL', @_ ) ); }
1133              
1134             sub new_array
1135             {
1136 59     59 0 126 my $self = shift( @_ );
1137 59         468 require Module::Generic::Array;
1138 59         214 return( Module::Generic::Array->new( @_ ) );
1139             }
1140              
1141             sub new_field
1142             {
1143 94     94 0 10804 my $self = shift( @_ );
1144 94         348 my $field = shift( @_ );
1145 94 50 33     972 return( $self->error( "No header field name was provided." ) ) if( !defined( $field ) || !length( "$field" ) );
1146 94 50       594 unless( scalar( keys( %$SUPPORTED ) ) )
1147             {
1148 0 0       0 $self->_load_class( 'Module::Generic::File' ) || return( $self->pass_error );
1149 0   0     0 my $dir = Module::Generic::File->new( ( $MOD_PATH || __FILE__ ) )->extension( undef );
1150 0 0       0 $dir->open || return( $self->error( "Unable to open directory \"$dir\": ", $dir->error ) );
1151 0         0 my $f;
1152 0         0 while( defined( $f = $dir->read( exclude_invisible => 1, as_object => 1 ) ) )
1153             {
1154 0 0       0 next if( $f->extension ne 'pm' );
1155 0         0 my $base = $f->basename( '.pm' );
1156 0         0 $SUPPORTED->{ lc( $base ) } = "HTTP\::Promise\::Headers\::${base}";
1157             }
1158             }
1159 94         846 ( my $name = $field ) =~ s/[\-_]+//g;
1160 94         325 $name = lc( $name );
1161 94 50       367 return( $self->error( "Unsupported field \"$field\"." ) ) if( !exists( $SUPPORTED->{ $name } ) );
1162 94         413 my $class = $SUPPORTED->{ $name };
1163 94 50       500 $self->_load_class( $class ) || return( $self->pass_error );
1164 94   50     696 my $o = $class->new( @_ ) ||
1165             return( $self->pass_error( $class->error ) );
1166 94         352 return( $o );
1167             }
1168              
1169             sub new_number
1170             {
1171 1     1 0 3 my $self = shift( @_ );
1172 1         8 require Module::Generic::Number;
1173 1         5 return( Module::Generic::Number->new( @_ ) );
1174             }
1175              
1176             sub new_scalar
1177             {
1178 346     346 0 411318 my $self = shift( @_ );
1179 346         3110 require Module::Generic::Scalar;
1180 346         52271 return( Module::Generic::Scalar->new( @_ ) );
1181             }
1182              
1183             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin>
1184 0     0 1 0 sub origin { return( shift->_set_get_one_uri( 'Origin', @_ ) ); }
1185              
1186             # Copied from Module::Generic to avoid loading it
1187             sub pass_error
1188             {
1189 0     0 0 0 my $self = shift( @_ );
1190 0   0     0 my $pack = ref( $self ) || $self;
1191 0         0 my $opts = {};
1192 0         0 my $err;
1193             my $class;
1194 14     14   176 no strict 'refs';
  14         29  
  14         41916  
1195 0 0       0 if( scalar( @_ ) )
1196             {
1197             # Either an hash defining a new error and this will be passed along to error(); or
1198             # an hash with a single property: { class => 'Some::ExceptionClass' }
1199 0 0 0     0 if( scalar( @_ ) == 1 && ref( $_[0] ) eq 'HASH' )
1200             {
1201 0         0 $opts = $_[0];
1202             }
1203             else
1204             {
1205             # $self->pass_error( $error_object, { class => 'Some::ExceptionClass' } );
1206 0 0 0     0 if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' )
1207             {
1208 0         0 $opts = pop( @_ );
1209             }
1210 0         0 $err = $_[0];
1211             }
1212             }
1213             # We set $class only if the hash provided is a one-element hash and not an error-defining hash
1214 0 0 0     0 $class = CORE::delete( $opts->{class} ) if( scalar( keys( %$opts ) ) == 1 && [keys( %$opts )]->[0] eq 'class' );
1215            
1216             # called with no argument, most likely from the same class to pass on an error
1217             # set up earlier by another method; or
1218             # with an hash containing just one argument class => 'Some::ExceptionClass'
1219 0 0 0     0 if( !defined( $err ) && ( !scalar( @_ ) || defined( $class ) ) )
    0 0        
      0        
      0        
      0        
1220             {
1221 0 0       0 if( !defined( $self->{error} ) )
1222             {
1223 0         0 warn( "No error object provided and no previous error set either! It seems the previous method call returned a simple undef\n" );
1224             }
1225             else
1226             {
1227 0 0       0 $err = ( defined( $class ) ? bless( $self->{error} => $class ) : $self->{error} );
1228             }
1229             }
1230             elsif( defined( $err ) &&
1231             Scalar::Util::blessed( $err ) &&
1232             ( scalar( @_ ) == 1 ||
1233             ( scalar( @_ ) == 2 && defined( $class ) )
1234             ) )
1235             {
1236 0 0       0 $self->{error} = ${ $pack . '::ERROR' } = ( defined( $class ) ? bless( $err => $class ) : $err );
  0         0  
1237             }
1238             # If the error provided is not an object, we call error to create one
1239             else
1240             {
1241 0         0 return( $self->error( @_ ) );
1242             }
1243            
1244 0 0       0 if( want( 'OBJECT' ) )
1245             {
1246 0         0 require Module::Generic::Null;
1247 0         0 my $null = Module::Generic::Null->new( $err, { debug => $self->{debug}, has_error => 1 });
1248 0         0 rreturn( $null );
1249             }
1250 0         0 my $wantarray = wantarray();
1251 0 0       0 if( $self->debug )
1252             {
1253 0         0 my $caller = [caller(1)];
1254             }
1255 0         0 return;
1256             }
1257              
1258             sub print
1259             {
1260 59     59 1 1830 my $self = shift( @_ );
1261 59         144 my $fh = shift( @_ );
1262 59         406 my $opts = $self->_get_args_as_hash( @_ );
1263 59   50     1217 my $eol = $opts->{eol} || CRLF;
1264 59   33     164 $fh ||= select;
1265 59 50 33     294 return( $self->error( "Filehandle provided ($fh) is not a proper filehandle and its not a HTTP::Promise::IO object." ) ) if( !$self->_is_glob( $fh ) && !$self->_is_a( $fh => 'HTTP::Promise::IO' ) );
1266 59         452 return( $fh->print( $self->as_string( $eol ) ) );
1267             }
1268              
1269 0     0 1 0 sub proxy { return( shift->_set_get_uri( 'proxy', @_ ) ); }
1270              
1271             # NOTE: proxy_authenticate() is inherited
1272             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authenticate>
1273 3     3 1 528 sub proxy_authenticate { return( shift->_set_get_one( 'Proxy-Authenticate', @_ ) ); }
1274              
1275             # NOTE: proxy_authorization() is inherited
1276             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization>
1277 1     1 1 401 sub proxy_authorization { return( shift->_set_get_one( 'Proxy-Authorization', @_ ) ); }
1278              
1279             # NOTE: proxy_authorization_basic() is inherited
1280              
1281             # NOTE: push_header() is inherited
1282              
1283             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range>
1284 0     0 1 0 sub range { return( shift->_set_get_multi( 'Range', @_ ) ); }
1285              
1286             sub recommended_filename
1287             {
1288 1     1 1 30 my $self = shift( @_ );
1289 1         26 foreach my $attr_name ( qw( content-disposition.filename* content-disposition.filename content-type.name ) )
1290             {
1291 2         10 my $value = $self->mime_attr( $attr_name );
1292 2 50 66     1104 if( defined( $value ) &&
      66        
1293             $value ne '' &&
1294             $value =~ /\S/ )
1295             {
1296 1         20 return( $self->decode_filename( $value ) );
1297             }
1298             }
1299 0         0 return;
1300             }
1301              
1302             # NOTE: referer() and referrer() are inherited
1303             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer>
1304 9     9 1 547 sub referer { return( shift->_set_get_one_uri( 'Referer', @_ ) ); }
1305              
1306 3     3 1 446 sub referrer { return( shift->referer( @_ ) ); }
1307              
1308             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy>
1309 0     0 1 0 sub referrer_policy { return( shift->_set_get_one( 'Referrer-Policy', @_ ) ); }
1310              
1311 18     18 1 616 sub remove { return( shift->remove_header( @_ ) ); }
1312              
1313             # NOTE: remove_header() is inherited
1314              
1315             # NOTE: remove_content_headers() is inherited
1316              
1317             sub replace
1318             {
1319 30     30 1 7023338 my $self = shift( @_ );
1320 30         284 my( $field, $value ) = @_;
1321 30         614 $self->header( $field => $value );
1322 30         236 return( $self );
1323             }
1324              
1325             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers>
1326 0     0 1 0 sub request_headers { return( shift->_set_get_one( 'Access-Control-Request-Headers', @_ ) ); }
1327              
1328             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Method>
1329 0     0 1 0 sub request_method { return( shift->_set_get_one( 'Access-Control-Request-Method', @_ ) ); }
1330              
1331 0     0 1 0 sub request_timeout { return( shift->_set_get_number( 'request_timeout', @_ ) ); }
1332              
1333             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After>
1334 0     0 1 0 sub retry_after { return( shift->_set_get_one( 'Retry-After', @_ ) ); }
1335              
1336             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Save-Data>
1337 0     0 1 0 sub save_data { return( shift->_set_get_one( 'Save-Data', @_ ) ); }
1338              
1339             # NOTE: scan() is inherited
1340              
1341             # NOTE: server() is inherited
1342             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server>
1343 3     3 1 482 sub server { return( shift->_set_get_one( 'Server', @_ ) ); }
1344              
1345             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>
1346 0     0 1 0 sub server_timing { return( shift->_set_get_one( 'Server-Timing', @_ ) ); }
1347              
1348             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie>
1349 0     0 1 0 sub set_cookie { return( shift->_set_get_one( 'Set-Cookie', @_ ) ); }
1350              
1351             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/SourceMap>
1352 0     0 1 0 sub sourcemap { return( shift->_set_get_one( 'SourceMap', @_ ) ); }
1353              
1354             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security>
1355 0     0 1 0 sub strict_transport_security { return( shift->_set_get_one( 'Strict-Transport-Security', @_ ) ); }
1356              
1357             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE>
1358 0     0 1 0 sub te { return( shift->_set_get_one( 'TE', @_ ) ); }
1359              
1360             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin>
1361 0     0 1 0 sub timing_allow_origin { return( shift->_set_get_multi( 'Timing-Allow-Origin', @_ ) ); }
1362              
1363             # NOTE: title() is inherited and sucks really
1364 3     3 1 502 sub title { return( shift->_set_get_one( 'Title', @_ ) ); }
1365              
1366             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Tk>
1367 0     0 1 0 sub tk { return( shift->_set_get_one( 'Tk', @_ ) ); }
1368              
1369             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer>
1370 0     0 1 0 sub trailer { return( shift->_set_get_one( 'Trailer', @_ ) ); }
1371              
1372             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding>
1373 0     0 1 0 sub transfer_encoding { return( shift->_set_get_one( 'Transfer-Encoding', @_ ) ); }
1374              
1375             sub type
1376             {
1377 280     280 1 933 my $self = shift( @_ );
1378 280 50 100     1804 if( @_ )
    100          
1379             {
1380             # mime-type like text/html, text/plain or application/json, etc...
1381 0         0 my $type = shift( @_ );
1382 0         0 $self->{type} = $type;
1383             # We are being provided with content type parameters, such as charset=utf8, or version=1
1384 0         0 my $ct = $self->new_field( 'Content-Type' => $type, @_ );
1385 0         0 $self->header( 'Content-Type' => "$ct" );
1386 0         0 $self->{_ctype_cached} = "$ct";
1387 0 0       0 $self->{boundary} = $ct->boundary if( $ct->boundary );
1388             }
1389             # Cached
1390             elsif( CORE::length( $self->{type} ) && $self->{_ctype_cached} eq $self->content_type )
1391             {
1392 97         3720 return( $self->{type} );
1393             }
1394             else
1395             {
1396 183         948 my $ctype_raw = $self->content_type;
1397 183 100 66     2030 return if( !defined( $ctype_raw ) || !length( "$ctype_raw" ) );
1398 51         818 $self->{_ctype_cached} = $ctype_raw;
1399             # There is nothing, but the mime-type itself, so no need to bother
1400 51 100       178 if( index( $ctype_raw, ';' ) == -1 )
1401             {
1402 30         424 $self->{type} = $ctype_raw;
1403 30         267 $self->{boundary} = '';
1404             }
1405             else
1406             {
1407             # Content-Type: application/json; encoding=utf-8
1408 21         365 my $ct = $self->new_field( 'Content-Type' => $ctype_raw );
1409 21 50       106 return( $self->pass_error ) if( !defined( $ct ) );
1410             # Accept: application/json; version=1.0; charset=utf-8
1411 21         84 $self->{type} = lc( $ct->type );
1412 21         781772 my $charset = $ct->charset;
1413 21 100       11981 $charset = lc( $charset ) if( defined( $charset ) );
1414 21         141 $self->{charset} = $charset;
1415 21 100       136 $self->{boundary} = $ct->boundary if( $ct->boundary );
1416             }
1417             }
1418 51         12109 return( $self->{type} );
1419             }
1420              
1421             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade>
1422 0     0 1 0 sub upgrade { return( shift->_set_get_multi( 'Upgrade', @_ ) ); }
1423              
1424             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade-Insecure-Requests>
1425 0     0 1 0 sub upgrade_insecure_requests { return( shift->_set_get_one( 'Upgrade-Insecure-Requests', @_ ) ); }
1426              
1427 3     3 1 106 sub uri_escape_utf8 { return( URI::Escape::XS::uri_escape( Encode::encode( 'UTF-8', $_[1] ) ) ); }
1428              
1429             # NOTE: user_agent() is inherited
1430             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent>
1431 4     4 1 497 sub user_agent { return( shift->_set_get_one( 'user_agent', @_ ) ); }
1432              
1433             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary>
1434 0     0 1 0 sub vary { return( shift->_set_get_multi( 'Vary', @_ ) ); }
1435              
1436             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Via>
1437 0     0 1 0 sub via { return( shift->_set_get_multi( 'Via', @_ ) ); }
1438              
1439             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Want-Digest>
1440 0     0 1 0 sub want_digest { return( shift->_set_get_multi( 'Want-Digest', @_ ) ); }
1441              
1442             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Warning>
1443 0     0 1 0 sub warning { return( shift->_set_get_one( 'Warning', @_ ) ); }
1444              
1445             # NOTE: www_authenticate() is superseded
1446             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate>
1447 3     3 1 12 sub www_authenticate { return( shift->_set_get_one( 'WWW-Authenticate', @_ ) ); }
1448              
1449 0     0 1 0 sub x { return( shift->_set_get_one( 'X-' . $_[0], @_ ) ); }
1450              
1451             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options>
1452 0     0 1 0 sub x_content_type_options { return( shift->_set_get_one( 'X-Content-Type-Options', @_ ) ); }
1453              
1454             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control>
1455 0     0 1 0 sub x_dns_prefetch_control { return( shift->_set_get_one( 'X-DNS-Prefetch-Control', @_ ) ); }
1456              
1457             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For>
1458 0     0 1 0 sub x_forwarded_for { return( shift->_set_get_one( 'X-Forwarded-For', @_ ) ); }
1459              
1460             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host>
1461 0     0 1 0 sub x_forwarded_host { return( shift->_set_get_one( 'X-Forwarded-Host', @_ ) ); }
1462              
1463             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto>
1464 0     0 1 0 sub x_forwarded_proto { return( shift->_set_get_one( 'X-Forwarded-Proto', @_ ) ); }
1465              
1466             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options>
1467 0     0 1 0 sub x_frame_options { return( shift->_set_get_one( 'X-Frame-Options', @_ ) ); }
1468              
1469             # <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection>
1470 0     0 1 0 sub x_xss_protection { return( shift->_set_get_one( 'X-XSS-Protection', @_ ) ); }
1471              
1472             sub _basic_auth
1473             {
1474 9     9   438 my $self = shift( @_ );
1475 9         15 my $field = shift( @_ );
1476 9 50 33     43 return( $self->error( "No field provided to get its basic authentication value." ) ) if( !defined( $field ) || !length( $field ) );
1477 9 50       25 $self->_load_class( 'Crypt::Misc' ) || return( $self->pass_error );
1478 9 100       31 if( @_ )
1479             {
1480 4         14 my( $user, $pwd ) = @_;
1481 4 100       21 return( $self->error( "Basic authorisation user name cannot contain ':'." ) ) if( index( $user, ':' ) != -1 );
1482 3 100       9 $pwd = '' if( !defined( $pwd ) );
1483 3         53 $self->header( $field => sprintf( 'Basic %s', Crypt::Misc::encode_b64( "${user}:${pwd}" ) ) );
1484 3         22 return( "${user}:${pwd}" );
1485             }
1486             else
1487             {
1488 5         24 my $v = $self->header( $field );
1489 5 50 66     19 return( $v ) if( !defined( $v ) && !want( 'OBJECT' ) );
1490 4 50 33     36 if( defined( $v ) && $v =~ /^[[:blank:]\h]*Basic[[:blank:]\h]+(.+?)$/ )
1491             {
1492 4         34 $v = Crypt::Misc::decode_b64( $1 );
1493             }
1494 4 100       39 return( wantarray() ? split( /:/, "$v" ) : $self->new_scalar( $v ) );
1495             }
1496             }
1497              
1498             sub _date_header
1499             {
1500 141     141   203 my $self = shift( @_ );
1501 141         201 my $f = shift( @_ );
1502 141 50 33     582 return( $self->error( "No field was provided to get or set its value." ) ) if( !defined( $f ) || !length( "$f" ) );
1503 141 100       275 if( @_ )
1504             {
1505 15         31 my $this = shift( @_ );
1506 15 50       50 return( $self->remove_header( "$f" ) ) if( !defined( $this ) );
1507 15         47 my $opts = $self->_get_args_as_hash( @_ );
1508 15 50 33     74 $opts->{time_zone} = 'GMT' if( !defined( $opts->{time_zone} ) || !length( $opts->{time_zone} ) );
1509 15         743 require Module::Generic::DateTime;
1510 15         932929 require DateTime::Format::Strptime;
1511 15 50 0     94 if( $this =~ /^\d+$/ )
    0 0        
    0          
1512             {
1513             # try-catch
1514 15         33 local $@;
1515             eval
1516 15         26 {
1517 15         80 $this = Module::Generic::DateTime->from_epoch( epoch => $this, time_zone => $opts->{time_zone} );
1518             };
1519 15 50       11473 if( $@ )
1520             {
1521 0         0 return( $self->error( "An error occurred while trying to get the DateTime object for epoch value '$this': $@" ) );
1522             }
1523             }
1524             elsif( Scalar::Util::blessed( $this ) && $this->isa( 'DateTime' ) )
1525             {
1526 0         0 $this = Module::Generic::DateTime->new( $this );
1527             }
1528             elsif( Scalar::Util::blessed( $this ) && $this->isa( 'Module::Generic::DateTime' ) )
1529             {
1530             # Ok, pass through
1531             }
1532             else
1533             {
1534 0         0 return( $self->error( "I was expecting an integer representing a unix time or a DateTime object, but instead got '$this'." ) );
1535             }
1536            
1537             # try-catch
1538 15         31 local $@;
1539             eval
1540 15         30 {
1541 15         112 $this->set_time_zone( 'GMT' );
1542 15         3512 my $fmt = DateTime::Format::Strptime->new(
1543             pattern => '%a, %d %b %Y %H:%M:%S GMT',
1544             locale => 'en_GB',
1545             time_zone => 'GMT',
1546             );
1547 15         30697 $this->set_formatter( $fmt );
1548 15         1417 $self->header( $f => $this );
1549             };
1550 15 50       57 if( $@ )
1551             {
1552 0         0 return( $self->error( "An error occurred while trying to format the datetime '$this': $@" ) );
1553             }
1554 15         68 return( $this );
1555             }
1556             else
1557             {
1558 126         442 my $v = $self->header( "$f" );
1559 126 100 66     1436 return( $v ) if( !defined( $v ) || !length( "${v}" ) );
1560 64 50 66     17397 if( !length( "$v" ) || ( ref( $v ) && !overload::Method( $v, '""' ) ) )
      33        
1561             {
1562 0 0       0 warnings::warn( "I do not know what to do with this supposedly datetime header value '$v'\n" ) if( length( "$v" ) );
1563             # if( want( 'OBJECT' ) )
1564             # {
1565             # require Module::Generic::Null;
1566             # rreturn( Module::Generic::Null->new );
1567             # }
1568 0         0 return( '' );
1569             }
1570            
1571             # try-catch
1572 64         18500 local $@;
1573             eval
1574 64         109 {
1575 64 100 66     438 unless( Scalar::Util::blessed( $v ) && $v->isa( 'Module::Generic::DateTime' ) )
1576             {
1577             # IE6 appends "; length = NNNN" on If-Modified-Since (can we handle it)
1578             # e.g.: Sat, 29 Oct 1994 19:43:31 GMT; length=34343
1579 1 50       6 if( index( $v, ';' ) != -1 )
1580             {
1581 1         13 $v = [split( /[[:blank:]\h]*;[[:blank:]\h]*/, "${v}", 2 )]->[0];
1582             }
1583 1         8 require Module::Generic;
1584 1         10 my $dt = Module::Generic->_parse_timestamp( "$v" );
1585 1 50       1886595 return( $self->pass_error( Module::Generic->error ) ) if( !defined( $dt ) );
1586 1         6 my $fmt = DateTime::Format::Strptime->new( pattern => '%s' );
1587 1         1141 $dt->set_formatter( $fmt );
1588 1         99 $v = Module::Generic::DateTime->new( $dt );
1589             }
1590             };
1591 64 50       572 if( $@ )
1592             {
1593 0         0 return( $self->error( "An error occurred while parsing datetime '$v': $@" ) );
1594             }
1595 64         1159 return( $v );
1596             }
1597             }
1598              
1599             sub _get_args_as_array
1600             {
1601 0     0   0 my $self = shift( @_ );
1602 0 0       0 return( [] ) if( !scalar( @_ ) );
1603 0         0 my $ref = [];
1604 0 0 0     0 if( scalar( @_ ) == 1 &&
      0        
      0        
1605             defined( $_[0] ) &&
1606             # Scalar::Util::reftype returns undef if the value is not a reference, which
1607             # causes a warning to pop up since we then compare an undefined value.
1608             ref( $_[0] ) &&
1609             Scalar::Util::reftype( $_[0] ) eq 'ARRAY' )
1610             {
1611 0         0 $ref = shift( @_ );
1612             }
1613             else
1614             {
1615 0         0 $ref = [ @_ ];
1616             }
1617 0         0 return( $ref );
1618             }
1619              
1620             sub _get_args_as_hash
1621             {
1622 74     74   166 my $self = shift( @_ );
1623 74 100       216 return( {} ) if( !scalar( @_ ) );
1624 14     14   120 no warnings 'uninitialized';
  14         37  
  14         7907  
1625 59         124 my $ref = {};
1626 59         306 my $order = $self->new_array;
1627 59 50       612 my $need_list = Want::want( 'LIST' ) ? 1 : 0;
1628 59 50 33     4070 if( scalar( @_ ) == 1 && Scalar::Util::reftype( $_[0] ) eq 'HASH' )
    0          
1629             {
1630 59         182 $ref = shift( @_ );
1631 59 50       156 $order = $self->new_array( [sort( keys( %$ref ) )] ) if( $need_list );
1632             }
1633             elsif( !( scalar( @_ ) % 2 ) )
1634             {
1635 0         0 $ref = { @_ };
1636 0 0       0 if( $need_list )
1637             {
1638 0         0 for( my $i = 0; $i < scalar( @_ ); $i += 2 )
1639             {
1640 0         0 $order->push( $_[$i] );
1641             }
1642             }
1643             }
1644 59 50       276 return( $need_list ? ( $ref, $order ) : $ref );
1645             }
1646              
1647             sub _header_get
1648             {
1649 0     0   0 my $self = shift( @_ );
1650 0         0 my $f = shift( @_ );
1651 0 0 0     0 return( $self->error( "No header field was provided." ) ) if( !defined( $f ) || !length( "$f" ) );
1652 0         0 my @values = ();
1653 0 0       0 if( wantarray() )
1654             {
1655 0         0 @values = $self->header( "$f" );
1656 0 0       0 return if( !@values );
1657 0         0 return( @values );
1658             }
1659             else
1660             {
1661 0         0 return( $self->header( "$f" ) );
1662             }
1663             }
1664              
1665             sub _header_set
1666             {
1667 0     0   0 my $self = shift( @_ );
1668 0 0       0 return( $self->SUPER::error( "Uneven number of parameters provided. I was expecting field-value pairs." ) ) if( @_ % 2 );
1669 0         0 my @args = ();
1670 0         0 for( my $i = 0; $i < scalar( @_ ); $i += 2 )
1671             {
1672 0         0 my( $f, $v ) = @_[$i..$i+1];
1673 0 0       0 next if( !defined( $v ) );
1674 0 0       0 if( $self->_is_array( $v ) )
1675             {
1676 0 0       0 my $ref = $self->_is_object( $v ) ? [@$v] : $v;
1677 0         0 push( @args, "$f" => $ref );
1678             }
1679             else
1680             {
1681 0         0 push( @args, "$f" => $v );
1682             }
1683             }
1684            
1685             # try-catch
1686 0         0 local $@;
1687             eval
1688 0         0 {
1689 0         0 $self->header( @args );
1690             };
1691 0 0       0 if( $@ )
1692             {
1693 0         0 return( $self->error( "Error trying to set headers with values: $@" ) );
1694             }
1695 0         0 return( $self );
1696             }
1697              
1698             sub _is_a
1699             {
1700 59     59   181 my $self = shift( @_ );
1701 59         110 my $obj = shift( @_ );
1702 59         138 my $pkg = shift( @_ );
1703 14     14   130 no overloading;
  14         37  
  14         30520  
1704 59 50 33     382 return if( !$obj || !$pkg );
1705 59 50       264 return if( !Scalar::Util::blessed( $obj ) );
1706 59         349 return( $obj->isa( $pkg ) );
1707             }
1708              
1709             sub _is_class_loaded
1710             {
1711 1     1   2 my $self = shift( @_ );
1712 1         3 my $class = shift( @_ );
1713 1         6 ( my $pm = $class ) =~ s{::}{/}gs;
1714 1         2 $pm .= '.pm';
1715 1         5 return( CORE::exists( $INC{ $pm } ) );
1716             }
1717              
1718             sub _is_glob
1719             {
1720 59 50   59   208 return(0) if( scalar( @_ < 2 ) );
1721 59 50       143 return(0) if( !defined( $_[1] ) );
1722 59         218 my $type = Scalar::Util::reftype( $_[1] );
1723 59 50       157 return(0) if( !defined( $type ) );
1724 59         509 return( $type eq 'GLOB' );
1725             }
1726              
1727             sub _load_class
1728             {
1729 114     114   253 my $self = shift( @_ );
1730 114   50     343 my $class = shift( @_ ) || return( $self->error( "No class to load was provided." ) );
1731 114         7844 eval( "require $class;" );
1732 114 50       17264 return( $self->error( "Unable to load class \"$class\": $@" ) ) if( $@ );
1733 114         457 return( $class );
1734             }
1735              
1736             sub _set_get
1737             {
1738 104     104   234 my $self = shift( @_ );
1739 104         362 my $prop = shift( @_ );
1740 104 50       353 $self->{ $prop } = shift( @_ ) if( @_ );
1741 104         432 return( $self->{ $prop } );
1742             }
1743              
1744             # If there can be multiple instance of the given header
1745             sub _set_get_multi
1746             {
1747 3     3   5 my $self = shift( @_ );
1748 3         6 my $f = shift( @_ );
1749 3 50 33     15 return( $self->error( "No field was provided to get or set its value." ) ) if( !defined( $f ) || !length( "$f" ) );
1750 3 100       11 if( @_ )
1751             {
1752 1         2 my $v = shift( @_ );
1753 1 50       4 return( $self->remove_header( "$f" ) ) if( !defined( $v ) );
1754             # Too dangerous and unnecessary. The value type the user provides us defines how it will be set in the HTTP headers
1755             # An array reference means there will be possibly multiple instance of the header
1756             # A string, means there will be only one instance.
1757             # my $ref = Scalar::Util::reftype( $v ) eq 'ARRAY' ? $v : [split( /\,[[:blank:]\h]*/, $v)];
1758             # $self->header( "$f" => $ref );
1759 1         11 $self->header( "$f" => $v );
1760 1         4 return( $v );
1761             }
1762             else
1763             {
1764 2         10 my @vals = $self->header( "$f" );
1765 2         3 my $ref;
1766 2 50       14 if( @vals > 1 )
    100          
1767             {
1768 0         0 $ref = \@vals;
1769             }
1770             elsif( !defined( $vals[0] ) )
1771             {
1772 1 50       5 if( want( 'OBJECT' ) )
1773             {
1774 0         0 return( Module::Generic::Null->new );
1775             }
1776             else
1777             {
1778 1         91 return;
1779             }
1780             }
1781             else
1782             {
1783 1         6 $vals[0] =~ s/^[[:blank:]\h]+|[[:blank:]\h]+$//g;
1784 1         9 $ref = [split( /\,[[:blank:]\h]*/, $vals[0] )];
1785             }
1786             # Thi is not such a good idea after all. It is better to return a list in list
1787             # context or a scalar object otherwise
1788             # return( $self->new_array( $ref ) );
1789 1 50       6 return( wantarray() ? @$ref : $self->new_scalar( join( ', ', @$ref ) ) );
1790             }
1791             }
1792              
1793             # If there can be only one instance of the given header
1794             sub _set_get_one
1795             {
1796 207     207   624 my $self = shift( @_ );
1797 207         518 my $f = shift( @_ );
1798 207 50 33     1776 return( $self->error( "No field was provided to get or set its value." ) ) if( !defined( $f ) || !length( "$f" ) );
1799 207 100       675 if( @_ )
1800             {
1801 21         82 my $v = shift( @_ );
1802 21 50       131 return( $self->remove_header( "$f" ) ) if( !defined( $v ) );
1803 21         280 $self->header( "$f" => $v );
1804 21         120 return( $v );
1805             }
1806             else
1807             {
1808 186         1484 my @vals = $self->header( "$f" );
1809 186 50       888 if( @vals > 1 )
    100          
1810             {
1811             # return( $self->new_array( \@vals ) );
1812 0         0 return( $self->new_scalar( join( ', ', @vals ) ) );
1813             }
1814             elsif( !defined( $vals[0] ) )
1815             {
1816 99 100       392 if( want( 'OBJECT' ) )
1817             {
1818 30         2217 return( Module::Generic::Null->new );
1819             }
1820             else
1821             {
1822 69         4264 return;
1823             }
1824             }
1825             else
1826             {
1827 87         917 $vals[0] =~ s/^[[:blank:]\h]+|[[:blank:]\h]+$//g;
1828 87         614 return( $self->new_scalar( $vals[0] ) );
1829             }
1830             }
1831             }
1832              
1833             sub _set_get_one_number
1834             {
1835 24     24   110 my $self = shift( @_ );
1836 24         110 my $f = shift( @_ );
1837 24 50 33     346 return( $self->error( "No field was provided to get or set its value." ) ) if( !defined( $f ) || !length( "$f" ) );
1838 24 100       139 if( @_ )
1839             {
1840 1         4 my $v = shift( @_ );
1841 1 50       11 return( $self->remove_header( "$f" ) ) if( !defined( $v ) );
1842 1         30 $self->header( "$f" => $v );
1843 1         5 return( $v );
1844             }
1845             else
1846             {
1847 23         180 my $v = $self->header( "$f" );
1848 23 100 66     229 if( !defined( $v ) || !length( $v ) )
1849             {
1850 22 50       94 if( want( 'OBJECT' ) )
1851             {
1852 0         0 require Module::Generic::Null;
1853 0         0 my $null = Module::Generic::Null->new( '', { debug => $self->debug });
1854 0         0 rreturn( $null );
1855             }
1856             else
1857             {
1858 22         1506 return( $v );
1859             }
1860             }
1861             # Ignore overflow values
1862             # 16 digits corresponding to 2^53-1 or 9007199254740991
1863 1 50       21 if( $v =~ /^[[:blank:]\h]*(\d{1,16})[[:blank:]\h]*$/ )
1864             {
1865 1         5 $v = $1;
1866             }
1867             else
1868             {
1869 0         0 return( '' );
1870             }
1871 1 50 33     5 return( $v ) if( ref( $v ) && !overload::Method( $v, '""' ) );
1872 1         6 return( $self->new_number( "$v" ) );
1873             }
1874             }
1875              
1876             sub _set_get_one_uri
1877             {
1878 9     9   16 my $self = shift( @_ );
1879 9         14 my $f = shift( @_ );
1880 9 50 33     50 return( $self->error( "No field was provided to get or set its value." ) ) if( !defined( $f ) || !length( "$f" ) );
1881 9 100       23 if( @_ )
1882             {
1883 3         6 my $v = shift( @_ );
1884 3 50       8 return( $self->remove_header( "$f" ) ) if( !defined( $v ) );
1885 3         20 $self->header( "$f" => $v );
1886 3         15 return( $v );
1887             }
1888             else
1889             {
1890 6         35 my $v = $self->header( "$f" );
1891 6         17 my $uri;
1892             # try-catch
1893 6         12 local $@;
1894             eval
1895 6         11 {
1896 6         750 require URI;
1897 6         3536 $uri = URI->new( $v );
1898             };
1899 6 50       13397 if( $@ )
1900             {
1901 0         0 return( $self->error( "Unable to create an URI object from the header value for \"$f\": $@" ) );
1902             }
1903 6         43 return( $uri );
1904             }
1905             }
1906              
1907             # NOTE: For CBOR and Sereal
1908             sub FREEZE
1909             {
1910 5     5 0 39 my $self = CORE::shift( @_ );
1911 5   50     31 my $serialiser = CORE::shift( @_ ) // '';
1912 5         23 my $class = CORE::ref( $self );
1913 5         23 my $h = {};
1914 5         26 my $headers = [];
1915 5         23 my $order = [];
1916             $self->scan(sub
1917             {
1918 10     10   42 my( $f, $val ) = @_;
1919 10 50       45 if( CORE::exists( $h->{ $f } ) )
1920             {
1921 0 0       0 $h->{ $f } = [ $h->{ $f } ] unless( CORE::ref( $h->{ $f } ) eq 'ARRAY' );
1922 0         0 CORE::push( @{$h->{ $f }}, $val );
  0         0  
1923             }
1924             else
1925             {
1926 10         88 $h->{ $f } = $val;
1927 10         71 CORE::push( @$order, $f );
1928             }
1929 5         158 });
1930 5         76 foreach my $f ( @$order )
1931             {
1932 10         48 CORE::push( @$headers, $f, $h->{ $f } );
1933             }
1934 5         56 my %hash = %$self;
1935 5         36 $hash{_headers_to_restore} = $headers;
1936             # Return an array reference rather than a list so this works with Sereal and CBOR
1937 5 50 33     62 CORE::return( [$class, \%hash] ) if( $serialiser eq 'Sereal' && Sereal::Encoder->VERSION <= version->parse( '4.023' ) );
1938             # But Storable want a list with the first element being the serialised element
1939 5         330 CORE::return( $class, \%hash );
1940             }
1941              
1942 5     5 0 533 sub STORABLE_freeze { CORE::return( CORE::shift->FREEZE( @_ ) ); }
1943              
1944             # NOTE: Storable creates an instance of HTTP:::Promise::Headers. The only problem is that it does not work with XS module and that Storable discard whatever value is returned by STORABLE_thaw. See issue #19984 <https://github.com/Perl/perl5/issues/19984>
1945             # So instead, we use this hook to store some data into the object created by Storable, and we call STORABLE_thaw_post_processing() with it and take what it returns.
1946             sub STORABLE_thaw
1947             {
1948 5     5 0 4031 my( $self, undef, $class, $hash ) = @_;
1949 5   0     21 $class //= CORE::ref( $self ) || $self;
      33        
1950 5   50     37 $hash //= {};
1951 5         48 $hash->{_class} = $class;
1952 5         39 $self->{_deserialisation_params} = $hash;
1953             # Useles to do more in STORABLE_thaw, because Storable anyway ignores the value returned
1954             # so we just store our hash of parameters for STORABLE_thaw_post_processing to do its actual job
1955 5         111 CORE::return( $self );
1956             }
1957              
1958             sub STORABLE_thaw_post_processing
1959             {
1960 4     4 0 55 my $obj = CORE::shift( @_ );
1961             my $hash = ( CORE::exists( $obj->{_deserialisation_params} ) && CORE::ref( $obj->{_deserialisation_params} ) eq 'HASH' )
1962             ? CORE::delete( $obj->{_deserialisation_params} )
1963 4 50 33     53 : {};
1964 4   33     40 my $class = CORE::delete( $hash->{_class} ) || CORE::ref( $obj ) || $obj;
1965             my $headers = CORE::ref( $hash->{_headers_to_restore} ) eq 'ARRAY'
1966             ? CORE::delete( $hash->{_headers_to_restore} )
1967 4 50       35 : [];
1968 4         23 my $new = $class->new( @$headers );
1969 4         54 foreach( CORE::keys( %$hash ) )
1970             {
1971 19         60 $new->{ $_ } = CORE::delete( $hash->{ $_ } );
1972             }
1973 4         31 CORE::return( $new );
1974             }
1975              
1976             # NOTE: CBOR will call the THAW method with the stored classname as first argument, the constant string CBOR as second argument, and all values returned by FREEZE as remaining arguments.
1977             # NOTE: Storable calls STORABLE_thaw with a blessed object it created followed with $cloning and any other arguments initially provided by STORABLE_freeze. Then, after receiving $self from STORABLE_thaw, we call THAW which return a useable object. The one generated by Storable triggers the exception: "hl is not an instance of HTTP::XSHeader"
1978             sub THAW
1979             {
1980             # STORABLE_thaw would issue $cloning as the 2nd argument, while CBOR would issue
1981             # 'CBOR' as the second value.
1982 0     0 0   my( $self, undef, @args ) = @_;
1983 0 0 0       my $ref = ( CORE::scalar( @args ) == 1 && CORE::ref( $args[0] ) eq 'ARRAY' ) ? CORE::shift( @args ) : \@args;
1984 0 0 0       my $class = ( CORE::defined( $ref ) && CORE::ref( $ref ) eq 'ARRAY' && CORE::scalar( @$ref ) > 1 ) ? CORE::shift( @$ref ) : ( CORE::ref( $self ) || $self );
      0        
1985 0 0         my $hash = CORE::ref( $ref ) eq 'ARRAY' ? CORE::shift( @$ref ) : {};
1986             my $headers = ( CORE::exists( $hash->{_headers_to_restore} ) && CORE::ref( $hash->{_headers_to_restore} ) eq 'ARRAY' )
1987             ? CORE::delete( $hash->{_headers_to_restore} )
1988 0 0 0       : [];
1989            
1990 0           my $new = $class->new( @$headers );
1991 0           foreach( CORE::keys( %$hash ) )
1992             {
1993 0 0         next if( CORE::scalar( CORE::grep( $_, @$headers ) ) );
1994 0           $new->{ $_ } = CORE::delete( $hash->{ $_ } );
1995             }
1996 0           CORE::return( $new );
1997             }
1998              
1999             sub TO_JSON
2000             {
2001 0     0 0   my $self = shift( @_ );
2002 0           my $ref = [];
2003             $self->scan(sub
2004             {
2005 0     0     my( $header, $val ) = @_;
2006 0           CORE::push( @$ref, [ $header, $val ] );
2007 0           });
2008 0           return( $ref );
2009             }
2010              
2011             1;
2012             # NOTE: POD
2013             __END__
2014              
2015             =encoding utf-8
2016              
2017             =head1 NAME
2018              
2019             HTTP::Promise::Headers - HTTP Headers Class
2020              
2021             =head1 SYNOPSIS
2022              
2023             use HTTP::Promise::Headers;
2024             my $h = HTTP::Promise::Headers->new ||
2025             die( HTTP::Promise::Headers->error, "\n" );
2026              
2027             =head1 VERSION
2028              
2029             v0.2.0
2030              
2031             =head1 DESCRIPTION
2032              
2033             This class uses for the most part an XS module (L<HTTP::XSHeaders>) to be very fast, and yet provides a convenient and versatile interface to retrieve and manipulate HTTP headers.
2034              
2035             A number of classes has been created to have a more granular control on the creation of some header values. See L</SEE ALSO>
2036              
2037             All HTTP headers known today have their corresponding method that can be used to easily get or set their corresponding header value.
2038              
2039             =head1 CONSTRUCTOR
2040              
2041             =head2 new
2042              
2043             This instantiates a new L<HTTP::Promise::Headers> object. You might pass some initial
2044             attribute-value pairs as parameters to the constructor.
2045              
2046             For example:
2047              
2048             $h = HTTP::Headers->new(
2049             Date => 'Mon, 09 May 2022 09:00:00 GMT',
2050             Content_Type => 'text/html; charset=utf-8; version=5.0',
2051             Content_Base => 'http://www.example.org/'
2052             );
2053              
2054             The constructor arguments are passed to the L</header> method described below.
2055              
2056             =head1 METHODS
2057              
2058             =head2 add
2059              
2060             This is an alias for L</push_header>
2061              
2062             =head2 as_string
2063              
2064             Provided with an optional C<EOL> to be used as End-Of-Line character, and this will return a string representation of the headers. C<EOL> defaults to C<\015\012>. Embedded "\n" characters in header field values will be substituted with this line ending sequence.
2065              
2066             This uses L</scan> internally and use header field case as suggested by HTTP specifications. It will also follow recommended "Good Practice" of ordering the header fields. Long header values are not folded.
2067              
2068             =head2 authorization_basic
2069              
2070             This is a convenience method around the L</authorization> method for the C<Authorization> header using the "Basic Authentication Scheme".
2071              
2072             To set the related header value, you provide a login and an optional password, and this will set the C<Authorization> header value and return the current headers object for chaining.
2073              
2074             $h->authorization_basic( $user, $password );
2075              
2076             If no value is provided, this will get the curent value of the C<Authorization> header field, base64 decode it, and return the decoded string as a L<scalar object|Module::Generic::Scalar>, i.e. something like C<usernaem:password>
2077              
2078             my $str = $h->authorization_basic;
2079              
2080             =head2 boundary
2081              
2082             This is a convenience method to set or get the boundary, if any, used for multipart C<Content-Type>
2083              
2084             If provided, this will add the C<boundary> parameter with the given value to the C<Content-Type> header field.
2085              
2086             If no value is provided, this returns the current boundary, if any, or an empty string.
2087              
2088             =head2 charset
2089              
2090             This is a convenience method to set or get the charset associated with the C<Content-Type> header field.
2091              
2092             If provided, this will add the C<charset> parameter with the given value to the C<Content-Type> header field.
2093              
2094             If no value is provided, this returns the current charset, if any, or an empty string.
2095              
2096             =head2 clear
2097              
2098             This will remove all header fields.
2099              
2100             =for Pod::Coverage:: client_date
2101              
2102             =head2 clone
2103              
2104             Returns a copy of this L<HTTP::Promise::Headers> object.
2105              
2106             =head2 content_is_text
2107              
2108             Returns true if the C<Content-Type> mime-type is textual in nature, i.e. its first half is C<text>, false otherwise. For example: C<text/plain> or C<text/html>
2109              
2110             =head2 content_is_html
2111              
2112             Returns true if the C<Content-Type> mime-type is html, such as C<text/html>, false otherwise.
2113              
2114             =head2 content_is_json
2115              
2116             Returns true if the C<Content-Type> mime-type is C<application/json>, false otherwise.
2117              
2118             =head2 content_is_xhtml
2119              
2120             Returns true if the C<Content-Type> mime-type is C<application/xhtml+xml> or C<application/vnd.wap.xhtml+xml>, false otherwise.
2121              
2122             =head2 content_is_xml
2123              
2124             Returns true if the C<Content-Type> mime-type is C<text/xml> or C<application/xml>, or contains the keyword C<xml>, false otherwise.
2125              
2126             =head2 content_type_charset
2127              
2128             This is a legacy method and it returns the upper-cased charset specified in the Content-Type header.
2129             In list context return the lower-cased bare content type followed by the upper-cased charset.
2130             Both values will be C<undef> if not specified in the header.
2131              
2132             =head2 decode_filename
2133              
2134             This takes a file name from the C<Content-Disposition> header value typically and returns it decoded if it was encoded as per the L<rfc2231|https://tools.ietf.org/html/rfc2231>
2135              
2136             For example:
2137              
2138             Content-Disposition: form-data; name="fileField"; filename*=UTF-8''%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt
2139            
2140             my $fname = $h->decode_filename( "UTF-8''%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt" );
2141            
2142             or
2143            
2144             Content-Disposition: form-data; name="fileField"; filename*=UTF-8'ja-JP'%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt
2145              
2146             my $fname = $h->decode_filename( "UTF-8'ja-JP'%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt" );
2147              
2148             or encoded with quoted-printable
2149              
2150             Content-Disposition: attachment; filename="=?UTF-8?Q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB.txt?="
2151              
2152             my $fname = $h->decode_filename( "=?UTF-8?Q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB.txt?=" );
2153              
2154             or encoded with base64
2155              
2156             Content-Disposition: attachment; filename="=?UTF-8?B?44OV44Kh44Kk44OrLnR4dAo?="
2157              
2158             my $fname = $h->decode_filename( "=?UTF-8?B?44OV44Kh44Kk44OrLnR4dAo?=" );
2159              
2160             In the above example, the result for C<$fname> would yield C<ファイル.txt> (i.e. file.txt in Japanese)
2161              
2162             =head2 debug
2163              
2164             Sets or gets the debug value. If positive, this will trigger an output of debugging messages on the STDERR or in the web server log files. Be mindful that this slows down the script, so make sure to switch it off once you are done.
2165              
2166             =head2 default_type
2167              
2168             Sets or gets the default mime-type to be used.
2169              
2170             =head2 delete
2171              
2172             This is an alias for L</remove_header>
2173              
2174             =head2 encode_filename
2175              
2176             This takes a file name to be used in the C<Content-Disposition> header value, and an optional language iso 639 code (see L<rfc1766|https://tools.ietf.org/html/rfc1766>), and if it contains non ascii characters, it will utf-8 encode it and URI escape it according to L<rfc2231|https://tools.ietf.org/html/rfc2231> and return the newly encoded file name.
2177              
2178             If the file name did not require any encoding, it will return C<undef>, so you can write something like this:
2179              
2180             my $filename = q{マイファイル.txt};
2181             if( my $enc = $h->encode_filename( $filename ) )
2182             {
2183             $filename = $enc;
2184             # Now $filename is: UTF-8''%E3%83%9E%E3%82%A4%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt
2185             }
2186              
2187             You can optionally pass a language code argument:
2188              
2189             if( my $enc = $h->encode_filename( $filename, 'ja-JP' ) )
2190             {
2191             $filename = $enc;
2192             # Now $filename is: UTF-8'ja-JP'%E3%83%9E%E3%82%A4%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt
2193             }
2194              
2195             The C<Content-Disposition> header value would then contain a property C<filename*> (with the trailing wildcard).
2196              
2197             =head2 error
2198              
2199             Sets or gets an error and when set, this returns C<undef>. When no argument is provided, this returns the latest error set.
2200              
2201             The error returned is actually a L<HTTP::Promise::Exception> object.
2202              
2203             =head2 exists
2204              
2205             Provided with a header field name and this returns true if it exists, or false otherwise.
2206              
2207             =head2 flatten
2208              
2209             $h->flatten();
2210              
2211             Returns the list of pairs of keys and values.
2212              
2213             =head2 get
2214              
2215             This is an alias for L</header>, mainly used without argument.
2216              
2217             =head2 header
2218              
2219             $h->header( $field );
2220             $h->header( $field => $value );
2221             $h->header( $f1 => $v1, $f2 => $v2, ... );
2222              
2223             The following is an extract from the original L<HTTP::Headers> class.
2224              
2225             Sets or gets the value of one or more header fields.
2226             The header field name (C<$field>) is not case sensitive.
2227             To make the life easier for perl users who wants to avoid quoting before the => operator, you can use '_' as a replacement for '-' in header names.
2228              
2229             The L</header> method accepts multiple field-value (C<$field => $value>) pairs, which means that you can update several header field values with a single invocation.
2230              
2231             The C<$value> argument may be a plain string or an array reference of strings for a multi-valued field. If the C<$value> is provided as C<undef> then the field is removed.
2232              
2233             If the C<$value> is not given, then that header field will remain unchanged. In addition to being a string, C<$value> may be something that stringifies.
2234              
2235             The old value (or values) of the last of the header fields is returned. If no such field exists C<undef> will be returned.
2236              
2237             A multi-valued field will be returned as separate values in list context and will be concatenated with ", " as separator in scalar context.
2238             The HTTP spec (L<rfc7230|https://tools.ietf.org/html/rfc7230> which obsoleted L<rfc2616|https://tools.ietf.org/html/rfc2616>) promises that joining multiple values in this way will not change the semantic of a header field, but in practice there are cases like old-style Netscape cookies where "," is used as part of the syntax of a single field value.
2239              
2240             Examples:
2241              
2242             $h->header( MIME_Version => '1.0',
2243             User_Agent => 'My-Web-Client/0.01' );
2244             $h->header( Accept => "text/html, text/plain, image/*" );
2245             $h->header( Accept => [qw( text/html text/plain image/* )] );
2246             @accepts = $h->header( 'Accept' ); # get multiple values
2247             $accepts = $h->header( 'Accept' ); # get values as a single string
2248              
2249             =head2 header_field_names
2250              
2251             The following is an extract from the original L<HTTP::Headers> class.
2252              
2253             Returns the list of distinct names for the fields present in the header.
2254             The field names have case as suggested by HTTP spec, and the names are returned in the recommended "Good Practice" order.
2255              
2256             In scalar context return the number of distinct field names.
2257              
2258             =head2 init_header
2259              
2260             $h->init_header( $field => $value );
2261              
2262             Set the specified header to the given value, but only if no previous value for that field is set.
2263              
2264             The header field name (C<$field>) is not case sensitive and '_' can be used as a replacement for '-'.
2265              
2266             The $value argument may be a scalar or a reference to a list of scalars.
2267              
2268             =head2 make_boundary
2269              
2270             Returns a new boundary using L<Data::UUID>
2271              
2272             =for Pod::Coverage message
2273              
2274             =for Pod::Coverage message_check
2275              
2276             =for Pod::Coverage message_frame
2277              
2278             =head2 mime_attr
2279              
2280             Provided with a header field name and an attribute name separated by a dot, such as C<content-disposition.filename> and this will return the value for that attribute in this header.
2281              
2282             If a value is provided, it will be set, otherwise it will be returned.
2283              
2284             If no attribute is provided, it will set or get the header field main value.
2285              
2286             For example:
2287              
2288             Content-Disposition: attachment; filename="hello.txt"
2289             my $dispo = $h->mime_attr( 'content-disposition' );
2290              
2291             will return C<attachment>
2292              
2293             =head2 mime_encoding
2294              
2295             Returns the value of the C<Content-Encoding>, C<Transfer-Encoding> or C<Content-Transfer-Encoding> (the latter only exists in mail, not in HTTP)
2296              
2297             =head2 mime_type
2298              
2299             Returns the mime-type from the C<Content-Type> header value, or the one from L<default_type>, if it is set. If nothing is found, this returns an empty string (not C<undef>).
2300              
2301             =head2 multipart_boundary
2302              
2303             Returns the multipart boundary used, if any, or an empty string otherwise.
2304              
2305             my $boundary = $h->multipart_boundary;
2306             # or you can provide the Content-Type if you already have it; it will save a few cycle
2307             my $boundary = $h->multipart_boundary( $content_type );
2308              
2309             =head2 print
2310              
2311             Provided with a filehandle, or an L<HTTP::Promise::IO> object and this will print on it the string representation of the headers and return whatever value L<perlfunc/print> will return.
2312              
2313             =head2 proxy_authorization_basic
2314              
2315             =head2 push_header
2316              
2317             $h->push_header( $field => $value );
2318             $h->push_header( $f1 => $v1, $f2 => $v2, ... );
2319              
2320             Add a new value for the specified header. Previous values for the same header are retained.
2321              
2322             As for the L</header> method, the field name (C<$field>) is not case sensitive and '_' can be used as a replacement for '-'.
2323              
2324             The $value argument may be a scalar or a reference to a list of scalars.
2325              
2326             $header->push_header( Accept => 'image/jpeg' );
2327             $header->push_header( Accept => [ map( "image/$_", qw( gif png tiff ) )] );
2328              
2329             =head2 recommended_filename
2330              
2331             This returns the filename set in either C<Content-Disposition> with the C<filename> property or in C<Content-Type> with the C<name> property.
2332              
2333             If none exists, this returns C<undef>.
2334              
2335             =head2 remove
2336              
2337             This is an alias for L</remove_header>
2338              
2339             =head2 remove_content_headers
2340              
2341             This will remove all the headers used to describe the content of a message.
2342              
2343             All header field names prefixed with C<Content-> are included in this category, as well as C<Allow>, C<Expires> and
2344             C<Last-Modified>. L<rfc7230|https://tools.ietf.org/html/rfc7230> denotes these headers as I<Entity Header Fields>.
2345              
2346             The return value is a new L<HTTP::Promise::Headers> object that contains the removed headers only.
2347              
2348             =head2 remove_header
2349              
2350             my @values = $h->remove_header( $field, ... );
2351             my $total_values_removed = $h->remove_header( $field, ... );
2352              
2353             This function removes the header with the specified names.
2354              
2355             The header names (C<$field>) are not case sensitive and '_' can be used as a replacement for '-'.
2356              
2357             The return value is the values of the headers removed. In scalar context the number of headers removed is returned.
2358              
2359             Note that if you pass in multiple header names then it is generally not possible to tell which of the returned values belonged to which field.
2360              
2361             =head2 replace
2362              
2363             Provided with a header field name and a value and this replace whatever current value with the value provided.
2364              
2365             It returns the current object for chaining.
2366              
2367             =head2 request_timeout
2368              
2369             Sets or gets the request timeout. This takes an integer.
2370              
2371             =head2 scan
2372              
2373             $h->scan( \&process_header_field );
2374              
2375             Apply a subroutine to each header field in turn.
2376             The callback routine is called with two parameters; the name of the field and a single value (a string).
2377             If a header field is multi-valued, then the routine is called once for each value.
2378             The field name passed to the callback routine has case as suggested by HTTP spec, and the headers will be visited in the recommended "Good Practice" order.
2379              
2380             Any return values of the callback routine are ignored.
2381             The loop can be broken by raising an exception (C<die>), but the caller of scan() would have to trap the exception itself.
2382              
2383             =head2 type
2384              
2385             This sets or gets the C<Content-Type> header value when setting a value, and returns only the mime-type when retrieving the value.
2386              
2387             $h->type( 'text/plain' );
2388             # Assuming Content-Type: text/html; charset=utf-8
2389             my $type = $h->type; # text/html
2390              
2391             =head2 uri_escape_utf8
2392              
2393             Provided with a string and this returns an URI-escaped string using L<URI::Escape::XS>
2394              
2395             =head1 HTTP HEADERS METHODS
2396              
2397             =head2 accept
2398              
2399             $h->accept( q{text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8} );
2400             $h->accept( [qw( text/html application/xhtml+xml application/xml;q=0.9 */*;q=0.8 )] );
2401              
2402             Sets or gets the C<Accept> header field value. It takes either a string or an array or array reference of values.
2403              
2404             See L<rfc7231, section 5.3.2|https://tools.ietf.org/html/rfc7231#section-5.3.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept>
2405              
2406             See also L<HTTP::Promise::Headers::Accept>
2407              
2408             =head2 accept_charset
2409              
2410             $h->accept( 'utf-8' );
2411              
2412             Sets or gets the C<Accept-Charset> headers field value. It takes a single string value.
2413              
2414             You should know that the C<Accept-Charset> header is deprecated by HTTP standards and that no modern web browsers is sending nor any modern HTTP server recognising it.
2415              
2416             See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Charset>
2417              
2418             =head2 accept_encoding
2419              
2420             $h->accept_encoding( 'gzip, deflate, br' );
2421             $h->accept_encoding( [qw( gzip deflate br )] );
2422             $h->accept_encoding( 'br;q=1.0, gzip;q=0.8, *;q=0.1' );
2423              
2424             Sets or gets the C<Accept-Encoding> header field value. It takes either a string or an array or array reference of values.
2425              
2426             See also L<HTTP::Promise::Headers::AcceptEncoding> to have a more granular control.
2427              
2428             Encoding header fields and their nuances:
2429              
2430             =over 4
2431              
2432             =item C<Accept-Encoding>
2433              
2434             The encodings accepted by the client.
2435              
2436             =item C<Content-Encoding>
2437              
2438             Contains the encodings that have been applied to the content, before transport
2439              
2440             =item C<TE>
2441              
2442             The encodings the user agent accepts.
2443              
2444             =item C<Transfer-Encoding>
2445              
2446             The encoding applied during transfer, such as C<chunked>
2447              
2448             =back
2449              
2450             See L<rfc7231, section 5.3.4|https://tools.ietf.org/html/rfc7231#section-5.3.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding>
2451              
2452             =head2 accept_language
2453              
2454             $h->accept_language( 'fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5' );
2455             $h->accept_language( [qw(fr-CH fr;q=0.9 en;q=0.8 de;q=0.7 *;q=0.5 )] );
2456              
2457             Sets or gets the C<Accept-Language> header field value. It takes either a string or an array or array reference of values.
2458              
2459             See also L<HTTP::Promise::Headers::AcceptLanguage> to have a more granular control.
2460              
2461             See L<rfc7231, section 5.3.5|https://tools.ietf.org/html/rfc7231#section-5.3.5> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language>
2462              
2463             =head2 accept_patch
2464              
2465             $h->accept_patch( 'application/example, text/example' );
2466             $h->accept_patch( [qw( application/example text/example )] );
2467             $h->accept_patch( 'text/example;charset=utf-8' );
2468             $h->accept_patch( 'application/merge-patch+json' );
2469              
2470             Sets or gets the C<Accept-Patch> header field value. It takes either a string or an array or array reference of values.
2471              
2472             This is a server response header.
2473              
2474             See L<rfc5789, section 3.1|https://tools.ietf.org/html/rfc5789#section-3.1>, L<rfc7231, section 4.3.4|https://tools.ietf.org/html/rfc7231#section-4.3.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Patch>
2475              
2476             =head2 accept_post
2477              
2478             $h->accept_post( 'application/example, text/example' );
2479             $h->accept_post( [qw( application/example text/example )] );
2480             $h->accept_post( 'image/webp' );
2481             $h->accept_post( '*/*' );
2482              
2483             Sets or gets the C<Accept-Post> header field value. It takes either a string or an array or array reference of values.
2484              
2485             This is a server response header.
2486              
2487             See L<rfc7231, section 4.3.3|https://tools.ietf.org/html/rfc7231#section-4.3.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Post>
2488              
2489             =head2 accept_ranges
2490              
2491             $h->accept_ranges(1234);
2492              
2493             Sets or gets the C<Accept-Ranges> header field value. It takes either a string or an array or array reference of values.
2494              
2495             This is a server response header.
2496              
2497             See L<rfc7233, section 2.3|https://tools.ietf.org/html/rfc7233#section-2.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Ranges>
2498              
2499             =head2 acceptables
2500              
2501             This returns a new L<HTTP::Promise::Headers::Accept> object based on the content of the C<Accept> header value.
2502              
2503             =head2 age
2504              
2505             $h->age(1234);
2506              
2507             Sets or gets the C<Age> header field value. It takes a numeric value.
2508              
2509             This is a server response header.
2510              
2511             See L<rfc7234, section 5.1|https://tools.ietf.org/html/rfc7234#section-5.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Age>
2512              
2513             =head2 allow
2514              
2515             $h->allow( 'GET, POST, HEAD' );
2516             $h->allow( [qw( GET POST HEAD )] );
2517              
2518             Sets or gets the C<Allow> header field value. It takes either a string or an array or array reference of values.
2519              
2520             This is a server response header.
2521              
2522             See L<rfc7231, section 7.4.1|https://tools.ietf.org/html/rfc7231#section-7.4.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Age>
2523              
2524             =head2 allow_credentials
2525              
2526             # Access-Control-Allow-Credentials: true
2527             $h->allow_credentials( 'true' );
2528              
2529             Sets or gets the C<Access-Control-Allow-Credentials> header field value. It takes a string boolean value: C<true> or C<false>.
2530              
2531             See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials>
2532              
2533             =head2 allow_headers
2534              
2535             # Access-Control-Allow-Headers: X-Custom-Header, Upgrade-Insecure-Requests
2536             $h->allow_headers( 'X-Custom-Header, Upgrade-Insecure-Requests' );
2537             $h->allow_headers( [qw( X-Custom-Header Upgrade-Insecure-Requests )] );
2538              
2539             Sets or gets the C<Access-Control-Allow-Headers> header field value. It takes either a string or an array or array reference of values.
2540              
2541             This is a server response header.
2542              
2543             See L<rfc7231, section 7.4.1|https://tools.ietf.org/html/rfc7231#section-7.4.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Age>
2544              
2545             =head2 allow_methods
2546              
2547             # Access-Control-Allow-Methods: POST, GET, OPTIONS
2548             $h->allow_methods( 'POST, GET, OPTIONS' );
2549             $h->allow_methods( [qw( POST GET OPTIONS )] );
2550             # Access-Control-Allow-Methods: *
2551             $h->allow_methods( '*' );
2552              
2553             Sets or gets the C<Access-Control-Allow-Methods> header field value. It takes either a string or an array or array reference of values.
2554              
2555             This is a server response header.
2556              
2557             See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods>
2558              
2559             =head2 allow_origin
2560              
2561             # Access-Control-Allow-Origin: *
2562             $h->allow_origin( '*' );
2563             # Access-Control-Allow-Origin: https://food.example.org
2564             $h->allow_origin( 'https://food.example.org' );
2565             # Access-Control-Allow-Origin: null
2566             $h->allow_origin( 'null' );
2567              
2568             Sets or gets the C<Access-Control-Allow-Origin> header field value. It takes a string value.
2569              
2570             This is a server response header.
2571              
2572             See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods>
2573              
2574             =head2 alt_svc
2575              
2576             # Alt-Svc: h2=":443"; ma=2592000;
2577             $h->alt_svc( 'h2=":443"; ma=2592000' );
2578             # Alt-Svc: h2=":443"; ma=2592000; persist=1
2579             $h->alt_svc( 'h2=":443"; ma=2592000; persist=1' );
2580             # Alt-Svc: h2="alt.example.com:443", h2=":443"
2581             $h->alt_svc( 'h2="alt.example.com:443", h2=":443"' );
2582             # Alt-Svc: h3-25=":443"; ma=3600, h2=":443"; ma=3600
2583             $h->alt_svc( 'h3-25=":443"; ma=3600, h2=":443"; ma=3600' );
2584              
2585             Sets or gets the C<Alt-Svc> header field value. It takes either a string or an array or array reference of values.
2586              
2587             See also L<HTTP::Promise::Headers::AltSvc> to have a more granular control.
2588              
2589             See L<rfc7838, section 3|https://tools.ietf.org/html/rfc7838#section-3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Alt-Svc>
2590              
2591             =head2 alternate_server
2592              
2593             This is a convenience method for the header field C<Alt-Svc>.
2594              
2595             To et it value, you provide a hash or hash reference of properties, including C<name> and C<value> respectively for the protocol-id and the alternate authority.
2596              
2597             $h->alternate_server( name => 'h2', value => ':443', ma => 2592000, persist => 1 );
2598              
2599             would create the header value:
2600              
2601             Alt-Svc: h2=":443"; ma=2592000; persist=1
2602              
2603             Without any parameter, it creates a new L<HTTP::Promise::Headers::AltSvc> object for each C<Alt-Svc> header value and returns an L<array object|Module::Generic::Array> of all those L<HTTP::Promise::Headers::AltSvc> objects.
2604              
2605             =head2 authorization
2606              
2607             # Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
2608             $h->authorization( 'Basic YWxhZGRpbjpvcGVuc2VzYW1l' );
2609              
2610             Sets or gets the C<Authorization> header field value. It takes a string value.
2611              
2612             See also L</authorization_basic>
2613              
2614             See L<rfc7235, section 4.2|https://tools.ietf.org/html/rfc7235#section-4.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization>
2615              
2616             =head2 cache_control
2617              
2618             # Cache-Control: max-age=604800
2619             $h->cache_control( 'max-age=604800' );
2620             # Cache-Control: s-maxage=604800
2621             $h->cache_control( 's-maxage=604800' );
2622             # Cache-Control: no-cache
2623             $h->cache_control( 'no-cache' );
2624             # Cache-Control: max-age=604800, must-revalidate
2625             $h->cache_control( 'max-age=604800, must-revalidate' );
2626             # Cache-Control: public, max-age=604800, immutable
2627             $h->cache_control( 'public, max-age=604800, immutable' );
2628              
2629             Sets or gets the C<Cache-Control> header field value. It takes either a string or an array or array reference of values.
2630              
2631             See also L<HTTP::Promise::Headers::CacheControl> to have a more granular control.
2632              
2633             See L<rfc7234, section 5.2|https://tools.ietf.org/html/rfc7234#section-5.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control>
2634              
2635             =head2 clear_site_data
2636              
2637             # Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"
2638             $h->clear_site_data( q{"cache", "cookies", "storage", "executionContexts"} );
2639             $h->clear_site_data( [qw( cache cookies storage executionContexts )] );
2640              
2641             The Clear-Site-Data header accepts one or more directives. If all types of data should be cleared, the wildcard directive ("*") can be used.
2642              
2643             See also L<HTTP::Promise::Headers::ClearSiteData> to have a more granular control.
2644              
2645             See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data>
2646              
2647             =head2 connection
2648              
2649             # Connection: keep-alive
2650             # Connection: close
2651              
2652             Sets or gets the C<Connection> header field value. It takes a string value.
2653              
2654             See L<rfc7230, section 6.1|https://tools.ietf.org/html/rfc7230#section-6.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection>
2655              
2656             =head2 content_disposition
2657              
2658             # Content-Disposition: inline
2659             # Content-Disposition: attachment
2660             # Content-Disposition: attachment; filename="filename.jpg"
2661             # Content-Disposition: form-data; name="fieldName"
2662             # Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"
2663              
2664             Sets or gets the C<Content-Disposition> header field value. It takes a string value.
2665              
2666             See also L<HTTP::Promise::Headers::ContentDisposition> to have a more granular control.
2667              
2668             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>
2669              
2670             =head2 content_encoding
2671              
2672             # Content-Encoding: gzip
2673             # Content-Encoding: compress
2674             # Content-Encoding: deflate
2675             # Content-Encoding: br
2676              
2677             # Multiple, in the order in which they were applied
2678             # Content-Encoding: deflate, gzip
2679              
2680             Sets or gets the C<Cache-Encoding> header field value. It takes either a string or an array or array reference of values.
2681              
2682             Encoding header fields and their nuances:
2683              
2684             =over 4
2685              
2686             =item C<Accept-Encoding>
2687              
2688             The encodings accepted by the client.
2689              
2690             =item C<Content-Encoding>
2691              
2692             Contains the encodings that have been applied to the content, before transport
2693              
2694             =item C<TE>
2695              
2696             The encodings the user agent accepts.
2697              
2698             =item C<Transfer-Encoding>
2699              
2700             The encoding applied during transfer, such as C<chunked>
2701              
2702             =back
2703              
2704             See L<rfc7230, section 3.3.1|https://tools.ietf.org/html/rfc7230#section-3.3.1>:
2705             "Unlike Content-Encoding (L<Section 3.1.2.1 of [RFC7231]|https://tools.ietf.org/html/rfc7231#section-3.1.2.1>), Transfer-Encoding is a property of the message, not of the representation"
2706              
2707             See also L</accept_encoding>, L</transfer_encoding> and L</te> and this L<Stackoverflow discussion|https://stackoverflow.com/questions/11641923/transfer-encoding-gzip-vs-content-encoding-gzip>
2708              
2709             See L<rfc7231, section 3.1.2.2|https://tools.ietf.org/html/rfc7231#section-3.1.2.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding>
2710              
2711             =head2 content_language
2712              
2713             # Content-Language: de-DE
2714             # Content-Language: en-US
2715             $h->content_language( 'en-GB' );
2716             # Content-Language: de-DE, en-CA
2717             $h->content_language( 'de-DE, en-CA' );
2718             $h->content_language( [qw( de-DE en-CA )] );
2719              
2720             Sets or gets the C<Cache-Language> header field value. It takes either a string or an array or array reference of values.
2721              
2722             There is no enforcement on the value provided, so it is up to you to set the proper value or values.
2723              
2724             See L<rfc7231, section 3.1.3.2|https://tools.ietf.org/html/rfc7231#section-3.1.3.2>, L<rfc5646|https://tools.ietf.org/html/rfc5646> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language>
2725              
2726             =head2 content_length
2727              
2728             # Content-Length: 72
2729             $h->content_length(72);
2730              
2731             Sets or gets the C<Connection> header field value. It takes a numeric value.
2732              
2733             See L<rfc7230, section 3.3.2|https://tools.ietf.org/html/rfc7230#section-3.3.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length>
2734              
2735             =head2 content_location
2736              
2737             # Content-Location: /some/where/file.html
2738             $h->content_location( '/some/where/file.html' );
2739              
2740             Sets or gets the C<Connection> header field value. It takes a numeric value.
2741              
2742             See L<rfc7231, section 3.1.4.2|https://tools.ietf.org/html/rfc7231#section-3.1.4.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Location>
2743              
2744             =head2 content_range
2745              
2746             # Content-Range: bytes 200-1000/67589
2747             # Unsatisfiable range value
2748             # Content-Range: bytes */1234
2749              
2750             Sets or gets the C<Content-Range> header field value. It takes a string value.
2751              
2752             See also L<HTTP::Promise::Headers::ContentRange> to have a more granular control.
2753              
2754             See L<rfc7233, section 4.2|https://tools.ietf.org/html/rfc7233#section-4.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range>
2755              
2756             =head2 content_security_policy
2757              
2758             # Content-Security-Policy: default-src 'self' http://example.com;
2759             # connect-src 'none';
2760             # Content-Security-Policy: connect-src http://example.com/;
2761             # script-src http://example.com/
2762              
2763             Sets or gets the C<Content-Security-Policy> header field value. It takes a string value.
2764              
2765             See also L<HTTP::Promise::Headers::ContentSecurityPolicy> to have a more granular control.
2766              
2767             See L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy>
2768              
2769             =head2 content_security_policy_report_only
2770              
2771             # Content-Security-Policy-Report-Only: default-src https:; report-uri /csp-violation-report-endpoint/
2772              
2773             Sets or gets the C<Content-Security-Policy-Report-Only> header field value. It takes a string value of properly formatted header value.
2774              
2775             See also L<HTTP::Promise::Headers::ContentSecurityPolicyReportOnly> to have a more granular control.
2776              
2777             =head2 content_type
2778              
2779             This sets or gets the C<Content-Type> header value. It takes a string value.
2780              
2781             If a value is provided, this will set the header value. If no value is provided, this simply return the header field value.
2782              
2783             See also L<HTTP::Promise::Headers::ContentType> to have a more granular control.
2784              
2785             See also L<rfc7233, section 4.1|https://tools.ietf.org/html/rfc7233#section-4.1>, L<rfc7231, section 3.1.1.5|https://tools.ietf.org/html/rfc7231#section-3.1.1.5> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types>, and L<this Mozilla documentation too|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type>
2786              
2787             =head2 cross_origin_embedder_policy
2788              
2789             # Cross-Origin-Embedder-Policy: require-corp
2790             # Cross-Origin-Opener-Policy: same-origin
2791              
2792             This sets or gets the C<Cross-Origin-Embedder-Policy> header value. It takes a string value.
2793              
2794             It can have either of the following value: C<require-corp> or C<same-origin>
2795              
2796             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy>
2797              
2798             =head2 cross_origin_opener_policy
2799              
2800             # Cross-Origin-Opener-Policy: unsafe-none
2801             # Cross-Origin-Opener-Policy: same-origin-allow-popups
2802             # Cross-Origin-Opener-Policy: same-origin
2803              
2804             This sets or gets the C<Cross-Origin-Opener-Policy> header value. It takes a string value.
2805              
2806             It can have either of the following value: C<unsafe-none> or C<same-origin-allow-popups> or C<same-origin>
2807              
2808             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy>
2809              
2810             =head2 cross_origin_resource_policy
2811              
2812             This sets or gets the C<Cross-Origin-Resource-Policy> header value. It takes a string value.
2813              
2814             It can have either of the following value: C<same-site> or C<same-origin> or C<same-origin>
2815              
2816             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy>
2817              
2818             For more example: L<https://resourcepolicy.fyi/>
2819              
2820             =head2 cspro
2821              
2822             This is an alias for L</content_security_policy_report_only>
2823              
2824             =head2 date
2825              
2826             This sets or gets the C<Date> header value. It takes a date string value, a unix timestamp or a L<DateTime> value.
2827              
2828             If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime> object.
2829              
2830             =head2 device_memory
2831              
2832             # Device-Memory: 1
2833              
2834             This sets or gets the C<Device-Memory> header value. It takes a number.
2835              
2836             L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Device-Memory>
2837              
2838             =head2 digest
2839              
2840             # Digest: sha-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=
2841             # Digest: sha-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=,unixsum=30637
2842              
2843             This sets or gets the C<Digest> header value. It takes either a string or an array or array reference of properly formatted values.
2844              
2845             See L<draft rfc|https://tools.ietf.org/html/draft-ietf-httpbis-digest-headers-05#section-3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Digest>
2846              
2847             =head2 dnt
2848              
2849             # DNT: 0
2850             # DNT: 1
2851             # DNT: null
2852              
2853             This sets or gets the C<DNT> header value. It takes a string value.
2854              
2855             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/DNT>
2856              
2857             =head2 early_data
2858              
2859             # Early-Data: 1
2860              
2861             This sets or gets the C<Early-Data> header value. It takes a string value.
2862              
2863             See also L<rfc8470, section 5.1|https://tools.ietf.org/html/rfc8470#section-5.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Early-Data>
2864              
2865             =head2 etag
2866              
2867             # ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
2868             # ETag: W/"0815"
2869              
2870             This sets or gets the C<Etag> header value. It takes a string of properly formatted value.
2871              
2872             See also L<rfc7232, section 2.3|https://tools.ietf.org/html/rfc7232#section-2.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag>
2873              
2874             =head2 expect
2875              
2876             This sets or gets the C<Expect> header value. It takes a string of properly formatted value, typically C<100-continue>
2877              
2878             For example, before sending a very large file:
2879              
2880             PUT /some/where HTTP/1.1
2881             Host: origin.example.com
2882             Content-Type: video/h264
2883             Content-Length: 1234567890987
2884             Expect: 100-continue
2885              
2886             If the server is ok, it would return a C<100 Continue>
2887              
2888             See also L<rfc7231, section 5.1.1|https://tools.ietf.org/html/rfc7231#section-5.1.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect>, L<interesting article|https://www.bram.us/2020/04/14/about-the-http-expect-100-continue-header/>
2889              
2890             =head2 expect_ct
2891              
2892             # Expect-CT: max-age=86400, enforce, report-uri="https://foo.example.com/report"
2893             $h->expect_ct( q{max-age=86400, enforce, report-uri="https://foo.example.com/report"} );
2894             $h->expect_ct( [qw( max-age=86400 enforce report-uri="https://foo.example.com/report" )] );
2895              
2896             This sets or gets the C<Expect-CT> header value. It takes a string of properly formatted value.
2897              
2898             See also L<HTTP::Promise::Headers::ExpectCT> to have a more granular control.
2899              
2900             See also L<rfc draft|https://tools.ietf.org/html/draft-ietf-httpbis-expect-ct-08> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expect-CT>
2901              
2902             =head2 expires
2903              
2904             This sets or gets the C<Expires> header value. It takes a date string value, a unix timestamp or a L<DateTime> value.
2905              
2906             If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime> object.
2907              
2908             For example:
2909              
2910             Expires: Wed, 21 Oct 2015 07:28:00 GMT
2911              
2912             See also L<rfc7234, section 5.3|https://tools.ietf.org/html/rfc7234#section-5.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Expires>
2913              
2914             =head2 expose_headers
2915              
2916             This sets or gets the C<Expose-Headers> header value. It takes either a string or an array or array reference of properly formatted values.
2917              
2918             For example:
2919              
2920             Access-Control-Expose-Headers: *, Authorization
2921              
2922             See also L<rfc7234, section 5.3|https://tools.ietf.org/html/rfc7234#section-5.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers>
2923              
2924             =head2 forwarded
2925              
2926             This sets or gets the C<Forwarded> header value. It takes either a string or an array or array reference of properly formatted values.
2927              
2928             See also L<HTTP::Promise::Headers::Forwarded> to have a more granular control.
2929              
2930             For example:
2931              
2932             Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43
2933             # Values from multiple proxy servers can be appended using a comma
2934             Forwarded: for=192.0.2.43, for=198.51.100.17
2935              
2936             See also L<rfc7239, section 4|https://tools.ietf.org/html/rfc7239#section-4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded>
2937              
2938             =head2 from
2939              
2940             This sets or gets the C<From> header value. It takes a string value.
2941              
2942             For example:
2943              
2944             From: webmaster@example.org
2945              
2946             See also L<rfc7231, section 5.5.1|https://tools.ietf.org/html/rfc7231#section-5.5.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/From>
2947              
2948             =head2 host
2949              
2950             This sets or gets the C<Host> header value. It takes a string value.
2951              
2952             For example:
2953              
2954             Host: dev.example.org
2955              
2956             See also L<rfc7230, section 5.4|https://tools.ietf.org/html/rfc7230#section-5.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host>
2957              
2958             =head2 if_match
2959              
2960             This sets or gets the C<If-Match> header value. It takes a string value.
2961              
2962             For example:
2963              
2964             If-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d"
2965             If-Match: "67ab43", "54ed21", "7892dd"
2966             If-Match: *
2967              
2968             See also L<rfc7232, section 3.1|https://tools.ietf.org/html/rfc7232#section-3.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Match>
2969              
2970             =head2 if_modified_since
2971              
2972             This sets or gets the C<If-Modified-Since> header value. It takes a date string value, a unix timestamp or a L<DateTime> value.
2973              
2974             If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime> object.
2975              
2976             For example:
2977              
2978             If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
2979              
2980             See also L<rfc7232, section 3.3|https://tools.ietf.org/html/rfc7232#section-3.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since>
2981              
2982             =head2 if_none_match
2983              
2984             This sets or gets the C<If-None-Match> header value. It takes a string value.
2985              
2986             For example:
2987              
2988             If-None-Match: "bfc13a64729c4290ef5b2c2730249c88ca92d82d"
2989             If-None-Match: W/"67ab43", "54ed21", "7892dd"
2990             If-None-Match: *
2991              
2992             See also L<rfc7232, section 3.2|https://tools.ietf.org/html/rfc7232#section-3.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Modified-Since>
2993              
2994             =head2 if_range
2995              
2996             This sets or gets the C<If-Range> header value. It takes a string value.
2997              
2998             For example:
2999              
3000             If-Range: Wed, 21 Oct 2015 07:28:00 GMT
3001              
3002             See also L<rfc7233, section 3.2|https://tools.ietf.org/html/rfc7233#section-3.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Range>
3003              
3004             =head2 if_unmodified_since
3005              
3006             This sets or gets the C<If-Unmodified-Since> header value. It takes a date string value, a unix timestamp or a L<DateTime> value.
3007              
3008             If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime> object.
3009              
3010             For example:
3011              
3012             If-Unmodified-Since: Wed, 21 Oct 2015 07:28:00 GMT
3013              
3014             See also L<rfc7232, section 3.4|https://tools.ietf.org/html/rfc7232#section-3.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-Unmodified-Since>
3015              
3016             =head2 keep_alive
3017              
3018             This sets or gets the C<Keep-Alive> header value. It takes either a string or an array or array reference of properly formatted values.
3019              
3020             See also L<HTTP::Promise::Headers::KeepAlive> to have a more granular control.
3021              
3022             Example response containing a Keep-Alive header:
3023              
3024             HTTP/1.1 200 OK
3025             Connection: Keep-Alive
3026             Content-Encoding: gzip
3027             Content-Type: text/html; charset=utf-8
3028             Date: Thu, 11 Aug 2016 15:23:13 GMT
3029             Keep-Alive: timeout=5, max=1000
3030             Last-Modified: Mon, 25 Jul 2016 04:32:39 GMT
3031             Server: Apache
3032              
3033             See also L<rfc7230, section A.1.2|https://tools.ietf.org/html/rfc7230#section-A.1.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive>
3034              
3035             =head2 last_modified
3036              
3037             This sets or gets the C<Last-Modified> header value. It takes a date string value, a unix timestamp or a L<DateTime> value.
3038              
3039             If no value is provided, it returns the current value of the C<Date> header field as a L<DateTime> object.
3040              
3041             For example:
3042              
3043             Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
3044              
3045             See also L<rfc7232, section 2.2|https://tools.ietf.org/html/rfc7232#section-2.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified>
3046              
3047             =head2 link
3048              
3049             This sets or gets the C<Link> header value. It takes a string value.
3050              
3051             See also L<HTTP::Promise::Headers::Link> to have a more granular control.
3052              
3053             Example:
3054              
3055             Link: <https://example.com>; rel="preconnect"
3056              
3057             See also L<rfc8288, section 3|https://tools.ietf.org/html/rfc8288#section-3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link>
3058              
3059             =head2 location
3060              
3061             This sets or gets the C<Location> header value. It takes a string value.
3062              
3063             Example:
3064              
3065             Location: /index.html
3066              
3067             See also L<rfc7231, section 7.1.2|https://tools.ietf.org/html/rfc7231#section-7.1.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location>
3068              
3069             =head2 max_age
3070              
3071             This sets or gets the C<Location> header value. It takes a numeric value.
3072              
3073             Example:
3074              
3075             Access-Control-Max-Age: 600
3076              
3077             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age>
3078              
3079             =head2 nel
3080              
3081             This sets or gets the C<NEL> header value. It takes a string of properly formatted json value.
3082              
3083             Example:
3084              
3085             NEL: { "report_to": "name_of_reporting_group", "max_age": 12345, "include_subdomains": false, "success_fraction": 0.0, "failure_fraction": 1.0 }
3086              
3087             See also L<rfc8288, section 3|https://tools.ietf.org/html/rfc8288#section-3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/NEL>
3088              
3089             =for Pod::Coverage new_array
3090              
3091             =for Pod::Coverage new_field
3092              
3093             =for Pod::Coverage new_number
3094              
3095             =for Pod::Coverage new_scalar
3096              
3097             =head2 origin
3098              
3099             This sets or gets the C<Origin> header value. It takes a string of properly formatted json value.
3100              
3101             Example:
3102              
3103             Origin: http://dev.example.org:80
3104              
3105             See also L<rfc6454, section 7|https://tools.ietf.org/html/rfc6454#section-7> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin>
3106              
3107             =for Pod::Coverage pass_error
3108              
3109             =head2 proxy
3110              
3111             Sets or gets the URI used for the proxy. It returns a L<URI> object.
3112              
3113             =head2 proxy_authenticate
3114              
3115             This sets or gets the C<Proxy-Authenticate> header value. It takes a string value.
3116              
3117             Example:
3118              
3119             Proxy-Authenticate: Basic realm="Access to the internal site"
3120              
3121             See also L<rfc6454, section 7|https://tools.ietf.org/html/rfc6454#section-7> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authenticate>
3122              
3123             =head2 proxy_authorization
3124              
3125             This sets or gets the C<Proxy-Authorization> header value. It takes a string value.
3126              
3127             Example:
3128              
3129             Proxy-Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
3130              
3131             See also L<rfc7235, section 4.4|https://tools.ietf.org/html/rfc7235#section-4.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization>
3132              
3133             =head2 range
3134              
3135             This sets or gets the C<Range> header value. It takes a string value.
3136              
3137             See also L<HTTP::Promise::Headers::Range> to have a more granular control.
3138              
3139             Example:
3140              
3141             Range: bytes=200-1000, 2000-6576, 19000-
3142              
3143             See also L<rfc7233, section 3.1|https://tools.ietf.org/html/rfc7233#section-3.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range>
3144              
3145             =head2 referer
3146              
3147             This sets or gets the C<Referer> header value. It takes a string value.
3148              
3149             Example:
3150              
3151             Referer: https://dev.example.org/some/where
3152             Referer: https://example.org/page?q=123
3153             Referer: https://example.org/
3154              
3155             See also L<rfc7231, section 5.5.2|https://tools.ietf.org/html/rfc7231#section-5.5.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer>
3156              
3157             =head2 referrer
3158              
3159             This is an alias for L</referer>
3160              
3161             =head2 referrer_policy
3162              
3163             This sets or gets the C<Referrer-Policy> header value. It takes a string value.
3164              
3165             The allowed values can be: C<no-referrer>, C<no-referrer-when-downgrade>, C<origin>, C<origin-when-cross-origin>, C<same-origin>, C<strict-origin>, C<strict-origin-when-cross-origin>, C<unsafe-url>
3166              
3167             Example:
3168              
3169             Referrer-Policy: no-referrer
3170             # With fallback
3171             Referrer-Policy: no-referrer, strict-origin-when-cross-origin
3172              
3173             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy>
3174              
3175             =head2 request_headers
3176              
3177             This sets or gets the C<Access-Control-Request-Headers> header value. It takes a string value.
3178              
3179             Example:
3180              
3181             Access-Control-Request-Headers: X-PINGOTHER, Content-Type
3182              
3183             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers>
3184              
3185             =head2 request_method
3186              
3187             This sets or gets the C<Access-Control-Request-Method> header value. It takes a string value.
3188              
3189             Example:
3190              
3191             Access-Control-Request-Method: POST
3192              
3193             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Method>
3194              
3195             =head2 retry_after
3196              
3197             This sets or gets the C<Retry-After> header value. It takes a string value.
3198              
3199             Example:
3200              
3201             Retry-After: Wed, 21 Oct 2015 07:28:00 GMT
3202             Retry-After: 120
3203              
3204             See also L<rfc7231, section 7.1.3|https://tools.ietf.org/html/rfc7231#section-7.1.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After>
3205              
3206             =head2 save_data
3207              
3208             This sets or gets the C<Save-Data> header value. It takes a string value.
3209              
3210             The value can be either C<on> or C<off>
3211              
3212             Example:
3213              
3214             Save-Data: on
3215              
3216             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Save-Data>
3217              
3218             =head2 server
3219              
3220             This sets or gets the C<Server> header value. It takes a string value.
3221              
3222             Example:
3223              
3224             Server: Apache/2.4.1 (Unix)
3225              
3226             See also L<rfc7231, section 7.4.2|https://tools.ietf.org/html/rfc7231#section-7.4.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server>
3227              
3228             =head2 server_timing
3229              
3230             This sets or gets the C<Server> header value. It takes a string value.
3231              
3232             See also L<HTTP::Promise::Headers::ServerTiming> to have a more granular control.
3233              
3234             Example:
3235              
3236             # Single metric without value
3237             Server-Timing: missedCache
3238              
3239             # Single metric with value
3240             Server-Timing: cpu;dur=2.4
3241              
3242             # Single metric with description and value
3243             Server-Timing: cache;desc="Cache Read";dur=23.2
3244              
3245             # Two metrics with value
3246             Server-Timing: db;dur=53, app;dur=47.2
3247              
3248             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>
3249              
3250             =head2 set_cookie
3251              
3252             This sets or gets the C<Set-Cookie> header value. It takes a string value.
3253              
3254             See also L<Cookie> to have a more granular control.
3255              
3256             Example:
3257              
3258             Set-Cookie: sessionId=38afes7a8
3259             Set-Cookie: __Secure-ID=123; Secure; Domain=example.com
3260             Set-Cookie: __Host-ID=123; Secure; Path=/
3261              
3262             See also L<rfc6265, section 4.1|https://tools.ietf.org/html/rfc6265#section-4.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie>
3263              
3264             =head2 sourcemap
3265              
3266             This sets or gets the C<SourceMap> header value. It takes a string value.
3267              
3268             Example:
3269              
3270             SourceMap: /path/to/file.js.map
3271              
3272             See also L<draft specifications|https://sourcemaps.info/spec.html> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/SourceMap>
3273              
3274             =head2 strict_transport_security
3275              
3276             This sets or gets the C<Strict-Transport-Security> header value. It takes a string value.
3277              
3278             See also L<HTTP::Promise::Headers::StrictTransportSecurity> to have a more granular control.
3279              
3280             Example:
3281              
3282             Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
3283              
3284             See also L<rfc6797, section 6.1|https://tools.ietf.org/html/rfc6797#section-6.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security>
3285              
3286             =head2 te
3287              
3288             This sets or gets the C<TE> header value. It takes a string value.
3289              
3290             See also L<HTTP::Promise::Headers::TE> to have a more granular control.
3291              
3292             Example:
3293              
3294             TE: deflate
3295             TE: gzip
3296             TE: trailers
3297              
3298             # Multiple directives, weighted with the quality value syntax:
3299             TE: trailers, deflate;q=0.5
3300              
3301             Notably, the value C<trailers> means the HTTP client support trailers, which are a set of headers sent after the body.
3302              
3303             Encoding header fields and their nuances:
3304              
3305             =over 4
3306              
3307             =item C<Accept-Encoding>
3308              
3309             The encodings accepted by the client.
3310              
3311             =item C<Content-Encoding>
3312              
3313             Contains the encodings that have been applied to the content, before transport
3314              
3315             =item C<TE>
3316              
3317             The encodings the user agent accepts.
3318              
3319             =item C<Transfer-Encoding>
3320              
3321             The encoding applied during transfer, such as C<chunked>
3322              
3323             =back
3324              
3325             See also L</transfer_encoding>, L<rfc7230, section 4.3|https://tools.ietf.org/html/rfc7230#section-4.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/TE>, L<article on trailers|https://httptoolkit.tech/blog/http-wtf/#http-trailers>
3326              
3327             =head2 timing_allow_origin
3328              
3329             This sets or gets the C<Timing-Allow-Origin> header value. It takes a string value.
3330              
3331             Example:
3332              
3333             Timing-Allow-Origin: *
3334             Timing-Allow-Origin: https://dev.example.org, https://example.com
3335              
3336             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Timing-Allow-Origin>
3337              
3338             =head2 title
3339              
3340             Sets or gets the C<Title> of the HTML document if that were the case. This is here for legacy.
3341              
3342             =head2 tk
3343              
3344             This sets or gets the deprecated C<Tk> header value. It takes a string value.
3345              
3346             Example:
3347              
3348             Tk: N
3349              
3350             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Tk>
3351              
3352             =head2 trailer
3353              
3354             This sets or gets the C<Trailer> header value. It takes a string value.
3355              
3356             Example:
3357              
3358             Trailer: Expires
3359              
3360             See also L<rfc7230, section 4.4|https://tools.ietf.org/html/rfc7230#section-4.4>, L<rfc7230, section 4.1.2|https://tools.ietf.org/html/rfc7230#section-4.1.2> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer>
3361              
3362             =head2 transfer_encoding
3363              
3364             This sets or gets the C<Transfer-Encoding> header value. It takes a string value.
3365              
3366             Example:
3367              
3368             Transfer-Encoding: chunked
3369             Transfer-Encoding: compress
3370             Transfer-Encoding: deflate
3371             Transfer-Encoding: gzip
3372              
3373             # Several values can be listed, separated by a comma
3374             Transfer-Encoding: gzip, chunked
3375              
3376             Encoding header fields and their nuances:
3377              
3378             =over 4
3379              
3380             =item C<Accept-Encoding>
3381              
3382             The encodings accepted by the client.
3383              
3384             =item C<Content-Encoding>
3385              
3386             Contains the encodings that have been applied to the content, before transport
3387              
3388             =item C<TE>
3389              
3390             The encodings the user agent accepts.
3391              
3392             =item C<Transfer-Encoding>
3393              
3394             The encoding applied during transfer, such as C<chunked>
3395              
3396             =back
3397              
3398             See L<rfc7230, section 3.3.1|https://tools.ietf.org/html/rfc7230#section-3.3.1>:
3399             "Unlike Content-Encoding (L<Section 3.1.2.1 of [RFC7231]|https://tools.ietf.org/html/rfc7231#section-3.1.2.1>), Transfer-Encoding is a property of the message, not of the representation"
3400              
3401             See also L</te>, L<rfc7230, section 3.3.1|https://tools.ietf.org/html/rfc7230#section-3.3.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding> and L<Wikipedia|https://en.wikipedia.org/wiki/Chunked_transfer_encoding>
3402              
3403             =head2 upgrade
3404              
3405             This sets or gets the C<Upgrade> header value. It takes a string value.
3406              
3407             Example:
3408              
3409             Connection: upgrade
3410             Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11
3411              
3412             Connection: Upgrade
3413             Upgrade: websocket
3414              
3415             See also L<rfc7230, section 6.7|https://tools.ietf.org/html/rfc7230#section-6.7>, L<rfc7231, section 6.6.15|https://tools.ietf.org/html/rfc7231#section-6.6.15>, L<rfc7240, section 8.1.1|https://tools.ietf.org/html/rfc7240#section-8.1.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade>
3416              
3417             =head2 upgrade_insecure_requests
3418              
3419             This sets or gets the C<Upgrade-Insecure-Requests> header value. It takes a string value.
3420              
3421             Example:
3422              
3423             Upgrade-Insecure-Requests: 1
3424              
3425             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade-Insecure-Requests>
3426              
3427             =head2 user_agent
3428              
3429             This sets or gets the C<User-Agent> header value. It takes a string value.
3430              
3431             Example:
3432              
3433             User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0
3434             User-Agent: curl/7.64.1
3435              
3436             See also L<rfc7231, section 5.5.3|https://tools.ietf.org/html/rfc7231#section-5.5.3> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent>
3437              
3438             =head2 vary
3439              
3440             This sets or gets the C<Vary> header value. It takes a string value.
3441              
3442             Example:
3443              
3444             Vary: *
3445             Vary: Accept-Encoding, User-Agent
3446              
3447             See also L<rfc7231, section 7.1.4|https://tools.ietf.org/html/rfc7231#section-7.1.4> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary>
3448              
3449             =head2 via
3450              
3451             This sets or gets the C<Via> header value. It takes a string value.
3452              
3453             Example:
3454              
3455             Via: 1.1 vegur
3456             Via: HTTP/1.1 GWA
3457             Via: 1.0 fred, 1.1 p.example.net
3458              
3459             See also L<rfc7230, section 5.7.1|https://tools.ietf.org/html/rfc7230#section-5.7.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Via>
3460              
3461             =head2 want_digest
3462              
3463             This sets or gets the C<Want-Digest> header value. It takes a string value.
3464              
3465             Example:
3466              
3467             Want-Digest: sha-256
3468             Want-Digest: SHA-512;q=0.3, sha-256;q=1, md5;q=0
3469              
3470             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Want-Digest>
3471              
3472             =head2 warning
3473              
3474             This sets or gets the C<Warning> header value. It takes a string value.
3475              
3476             Example:
3477              
3478             Warning: 110 anderson/1.3.37 "Response is stale"
3479              
3480             See also L<rfc7234, section 5.5|https://tools.ietf.org/html/rfc7234#section-5.5> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Warning>
3481              
3482             =head2 www_authenticate
3483              
3484             This sets or gets the C<WWW-Authenticate> header value. It takes a string value.
3485              
3486             Example:
3487              
3488             WWW-Authenticate: Basic realm="Access to the staging site", charset="UTF-8"
3489             WWW-Authenticate: Digest
3490             realm="http-auth@example.org",
3491             qop="auth, auth-int",
3492             algorithm=SHA-256,
3493             nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
3494             opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
3495             WWW-Authenticate: Digest
3496             realm="http-auth@example.org",
3497             qop="auth, auth-int",
3498             algorithm=MD5,
3499             nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
3500             opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
3501              
3502             See also L<rfc7235, section 4.1|https://tools.ietf.org/html/rfc7235#section-4.1> and L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate>
3503              
3504             =head2 x
3505              
3506             Sets or gets an arbitrary C<X-*> header. For example:
3507              
3508             $h->x( 'Spip-Cache' => 3600 );
3509              
3510             would set the C<X-Spip-Cache> header value to C<3600>
3511              
3512             my $value = $h->x( 'Spip-Cache' );
3513              
3514             =head2 x_content_type_options
3515              
3516             This sets or gets the C<X-Content-Type-Options> header value. It takes a string value.
3517              
3518             Example:
3519              
3520             X-Content-Type-Options: nosniff
3521              
3522             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options>
3523              
3524             =head2 x_dns_prefetch_control
3525              
3526             This sets or gets the C<X-DNS-Prefetch-Control> header value. It takes a string value.
3527              
3528             Example:
3529              
3530             X-DNS-Prefetch-Control: on
3531             X-DNS-Prefetch-Control: off
3532              
3533             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control>
3534              
3535             =head2 x_forwarded_for
3536              
3537             This sets or gets the C<X-Forwarded-For> header value. It takes a string value.
3538              
3539             Example:
3540              
3541             X-Forwarded-For: 2001:db8:85a3:8d3:1319:8a2e:370:7348
3542             X-Forwarded-For: 203.0.113.195
3543             X-Forwarded-For: 203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348
3544              
3545             See also L</host>, L</forwarded>, L</x_forwarded_host>, L</x_forwarded_proto>, L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For>
3546              
3547             =head2 x_forwarded_host
3548              
3549             This sets or gets the C<X-Forwarded-Host> header value. It takes a string value.
3550              
3551             Example:
3552              
3553             X-Forwarded-Host: id42.example-cdn.com
3554              
3555             See also L</host>, L</forwarded>, L</x_forwarded_for>, L</x_forwarded_proto>, L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host>
3556              
3557             =head2 x_forwarded_proto
3558              
3559             This sets or gets the C<X-Forwarded-Proto> header value. It takes a string value.
3560              
3561             Example:
3562              
3563             X-Forwarded-Proto: https
3564              
3565             See also L</host>, L</forwarded>, L</x_forwarded_for>, L</x_forwarded_host>, L<https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto>
3566              
3567             =head2 x_frame_options
3568              
3569             This sets or gets the C<X-Frame-Options> header value. It takes a string value.
3570              
3571             Example:
3572              
3573             X-Frame-Options: DENY
3574             X-Frame-Options: SAMEORIGIN
3575              
3576             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options>
3577              
3578             =head2 x_xss_protection
3579              
3580             This sets or gets the C<X-XSS-Protection> header value. It takes a string value.
3581              
3582             Example:
3583              
3584             X-XSS-Protection: 0
3585             X-XSS-Protection: 1
3586             X-XSS-Protection: 1; mode=block
3587             X-XSS-Protection: 1; report=https://example.org/some/where
3588              
3589             See also L<Mozilla documentation|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection>
3590              
3591             =for Pod::Coverage STORABLE_thaw_post_processing
3592              
3593             =head1 AUTHOR
3594              
3595             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
3596              
3597             =head1 SEE ALSO
3598              
3599             L<Mozilla documentation on HTTP headers|https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers>
3600              
3601             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>
3602              
3603             L<rfc7230, section 3.2 on headers field names|https://tools.ietf.org/html/rfc7230#section-3.2>,
3604             L<rfc6838 on mime types|https://tools.ietf.org/html/rfc6838>
3605              
3606             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>
3607              
3608             =head1 COPYRIGHT & LICENSE
3609              
3610             Copyright(c) 2022 DEGUEST Pte. Ltd.
3611              
3612             All rights reserved
3613             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
3614              
3615             =cut