Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import Optional
from .dates_is_leap_year import is_leap_year ← from dates.is-leap-year ^1.0.0 · built alongside by fune
from .time_iso_to_unix import iso_to_unix ← from time.iso-to-unix ^1.0.0 · built alongside by fune
DAY_NAMES = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
MONTHS = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
MONTH_DAYS = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
# Nine digits is 31 years; anything longer is a broken header, not a wait.
MAX_DIGITS = 9
def _all_digits(text: str) -> bool:
# A character range, not str.isdigit(), which accepts other scripts' digits.
return len(text) > 0 and all("0" <= ch <= "9" for ch in text)
def _imf_fixdate(t: str) -> Optional[int]:
"""An IMF-fixdate, "Sun, 06 Nov 1994 08:49:37 GMT", to Unix seconds; None if it is not one."""
if len(t) != 29:
return None
if t[0:3] not in DAY_NAMES or t[3:5] != ", " or t[7] != " " or t[11] != " " or t[16] != " ":
return None
if t[19] != ":" or t[22] != ":" or t[25:] != " GMT":
return None
if t[8:11] not in MONTHS:
return None
month = MONTHS.index(t[8:11])
dd, yyyy, hh, mi, ss = t[5:7], t[12:16], t[17:19], t[20:22], t[23:25]
if not all(_all_digits(part) for part in (dd, yyyy, hh, mi, ss)):
return None
year, day = int(yyyy), int(dd)
if year < 1 or int(hh) > 23 or int(mi) > 59 or int(ss) > 59:
return None
month_days = 29 if month == 1 and is_leap_year(year) else MONTH_DAYS[month]
if day < 1 or day > month_days:
return None
return iso_to_unix("%s-%02d-%sT%s:%s:%sZ" % (yyyy, month + 1, dd, hh, mi, ss))
def retry_after_seconds(header: Optional[str], now: int) -> Optional[int]:
"""How long a client should wait before retrying, from a Retry-After
header (RFC 9110 10.2.3): delay-seconds, or an HTTP date turned into
seconds from `now`. A date in the past is 0. Anything else is None."""
if not isinstance(now, int) or isinstance(now, bool):
raise ValueError("now must be a whole number of seconds")
if not isinstance(header, str):
return None
# HTTP's optional whitespace is space and tab only (RFC 9110 5.6.3).
t = header.strip(" \t")
if _all_digits(t):
return int(t) if len(t) <= MAX_DIGITS else None
at = _imf_fixdate(t)
if at is None:
return None
return at - now if at > now else 0