FU: HTTP date handling + fu->send_file
This commit is contained in:
parent
18e642290d
commit
8595c4ba64
2 changed files with 144 additions and 8 deletions
52
FU/Util.pm
52
FU/Util.pm
|
|
@ -4,12 +4,14 @@ use v5.36;
|
|||
use FU::XS;
|
||||
use Carp 'confess';
|
||||
use Exporter 'import';
|
||||
use POSIX ();
|
||||
use experimental 'builtin';
|
||||
|
||||
our @EXPORT_OK = qw/
|
||||
json_format json_parse
|
||||
utf8_decode uri_escape uri_unescape
|
||||
query_decode query_encode
|
||||
httpdate_format httpdate_parse
|
||||
fdpass_send fdpass_recv
|
||||
/;
|
||||
|
||||
|
|
@ -60,6 +62,31 @@ sub query_encode :prototype($) ($o) {
|
|||
} sort keys %$o;
|
||||
}
|
||||
|
||||
|
||||
my @httpmonths = qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/;
|
||||
my %httpmonths = map +($httpmonths[$_], $_), 0..11;
|
||||
my @httpdays = qw/Sun Mon Tue Wed Thu Fri Sat/;
|
||||
my $httpdays = '(?:'.join('|', @httpdays).')';
|
||||
|
||||
sub httpdate_format :prototype($) ($time) {
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime $time;
|
||||
sprintf '%s, %02d %s %d %02d:%02d:%02d GMT',
|
||||
$httpdays[$wday], $mday, $httpmonths[$mon], $year+1900, $hour, $min, $sec;
|
||||
}
|
||||
|
||||
sub httpdate_parse :prototype($) ($str) {
|
||||
return if $str !~ /^$httpdays, ([0-9]{2}) ([A-Z][a-z]{2}) ([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2}) GMT$/;
|
||||
my ($mday, $mon, $year, $hour, $min, $sec) = ($1, $httpmonths{$2}, $3, $4, $5, $6);
|
||||
return if !defined $mon;
|
||||
# mktime() interprets the broken down time as our local timezone,
|
||||
# which is utter garbage. But we can work around that by subtracting the
|
||||
# time offset between localtime and gmtime around the given date. Might be
|
||||
# off for a few hours around DST changes, but ugh.
|
||||
my $mktime = POSIX::mktime($sec, $min, $hour, $mday, $mon, $year-1900);
|
||||
$mktime + (POSIX::mktime(localtime $mktime) - POSIX::mktime(gmtime $mktime));
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
|
|
@ -272,6 +299,31 @@ then encoded.
|
|||
=back
|
||||
|
||||
|
||||
=head2 HTTP Date Formatting
|
||||
|
||||
The HTTP date format is utter garbage, but with the right tools it doesn't
|
||||
require I<too> much code to work with.
|
||||
|
||||
=over
|
||||
|
||||
=item httpdate_format($time)
|
||||
|
||||
Convert the given seconds-since-Unix-epoch C<$time> into a HTTP date string.
|
||||
|
||||
=item httpdate_parse($str)
|
||||
|
||||
Converts the given HTTP date string into a seconds-since-Unix-epoch integer.
|
||||
This function is very strict about its input and only accepts "IMF-fixdate" as
|
||||
per L<RFC7231|https://www.rfc-editor.org/rfc/rfc7231#section-7.1.1.1>, which is
|
||||
what every sensible implementation written in the past decade uses.
|
||||
|
||||
This function plays fast and loose with timezone conversions, the parsed
|
||||
timestamp I<might> be off by an hour or so for a few hours around a DST change.
|
||||
This will not happen if your local timezone is UTC.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 File Descriptor Passing
|
||||
|
||||
UNIX sockets (see L<IO::Socket::UNIX>) have the fancy property of letting you
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue