FU: HTTP date handling + fu->send_file

This commit is contained in:
Yorhel 2025-02-24 11:12:01 +01:00
parent 18e642290d
commit 8595c4ba64
2 changed files with 144 additions and 8 deletions

View file

@ -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