|
|
|
@ -234,8 +234,10 @@ http_date_parse_IMF_fixdate (const char * const s, struct tm * const tm)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const char * |
|
|
|
|
http_date_str_to_tm (const char * const s, struct tm * const tm) |
|
|
|
|
http_date_str_to_tm (const char * const s, const uint32_t len, |
|
|
|
|
struct tm * const tm) |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
/* attempt strptime() using multiple date formats
|
|
|
|
|
* support RFC 822,1123,7231; RFC 850; and ANSI C asctime() date strings, |
|
|
|
|
* as required by [RFC7231] https://tools.ietf.org/html/rfc7231#section-7.1
|
|
|
|
@ -250,8 +252,9 @@ http_date_str_to_tm (const char * const s, struct tm * const tm)
|
|
|
|
|
* - HTTP expected date formats are known, so not needed as input param |
|
|
|
|
* - HTTP expected date string content is in C locale and is case-sensitive |
|
|
|
|
* - returns (const char *) instead of strptime() (char *) return type |
|
|
|
|
* - returns NULL if error (if date string could not be parsed) */ |
|
|
|
|
const size_t len = strlen(s); /*(require '\0'-terminated string)*/ |
|
|
|
|
* - returns NULL if error (if date string could not be parsed) |
|
|
|
|
* Note: internal implementation requires '\0'-terminated string, or at |
|
|
|
|
* least one valid char after partial match of RFC 850 or asctime formats */ |
|
|
|
|
if (len == 29) |
|
|
|
|
return http_date_parse_IMF_fixdate(s, tm); |
|
|
|
|
else if (len > 29) |
|
|
|
@ -261,13 +264,14 @@ http_date_str_to_tm (const char * const s, struct tm * const tm)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
size_t |
|
|
|
|
http_date_time_to_str (char * const s, const size_t max, const time_t t) |
|
|
|
|
uint32_t |
|
|
|
|
http_date_time_to_str (char * const s, const size_t sz, const time_t t) |
|
|
|
|
{ |
|
|
|
|
/*('max' is expected to be >= 30 (IMF-fixdate is 29 chars + '\0'))*/ |
|
|
|
|
struct tm tm; |
|
|
|
|
const char fmt[] = "%a, %d %b %Y %T GMT"; /*IMF-fixdate fmt*/ |
|
|
|
|
return (__builtin_expect( (NULL != gmtime_r(&t, &tm)), 1)) |
|
|
|
|
? strftime(s, max, "%a, %d %b %Y %T GMT", &tm) /* IMF-fixdate format */ |
|
|
|
|
? (uint32_t)strftime(s, sz, fmt, &tm) |
|
|
|
|
: 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -280,37 +284,28 @@ http_date_time_to_str (char * const s, const size_t max, const time_t t)
|
|
|
|
|
#else |
|
|
|
|
/* If OS missing timegm(), then for best portability it is recommended to set
|
|
|
|
|
* $ export LC_TIME=C TZ=UTC0 |
|
|
|
|
* or else time comparisons may be off by timezone offset (!!) |
|
|
|
|
* |
|
|
|
|
* tm->tm_isdst = 0 for mktime() to indicate daylight saving time not in effect |
|
|
|
|
* which is fine since two strings should be GMT dates, and both are converted |
|
|
|
|
* with mktime() and then the results compared */ |
|
|
|
|
* which is fine since HTTP date strings should be GMT dates |
|
|
|
|
* |
|
|
|
|
* If not TZ=UTC0, and timegm() is not present, then can we expect gmtime() to |
|
|
|
|
* be available so that we can mktime(gmtime_r(lmtime, >m)) ? That would be |
|
|
|
|
* an expensive way to obtain TZ offset. XXX: maybe calculate TZ offset once |
|
|
|
|
* at startup? Are there any (modern) systems missing timegm() or _mkgmtime()? |
|
|
|
|
*/ |
|
|
|
|
#define http_date_timegm(tm) ((tm)->tm_isdst = 0, mktime(tm)) |
|
|
|
|
#endif |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
http_date_if_modified_since (const char * const ifmod, |
|
|
|
|
const char * const lmod, time_t lmtime) |
|
|
|
|
http_date_if_modified_since (const char * const ifmod, const uint32_t ifmodlen, |
|
|
|
|
const time_t lmtime) |
|
|
|
|
{ |
|
|
|
|
/* if caller provides non-zero lmtime, it must match Last-Modified lmod,
|
|
|
|
|
* and will typically be same arg given to http_response_set_last_modified() |
|
|
|
|
* (small opt to elide one strptime(),timegm() call) |
|
|
|
|
* (In absense of timegm(), substitute mktime(), which works reasonably well |
|
|
|
|
* since mktime() strings are used for comparison of If-Modified-Since) |
|
|
|
|
* (use mktime() to convert both strings for compare) */ |
|
|
|
|
struct tm ifmodtm; |
|
|
|
|
if (NULL == http_date_str_to_tm(ifmod, &ifmodtm)) |
|
|
|
|
if (NULL == http_date_str_to_tm(ifmod, ifmodlen, &ifmodtm)) |
|
|
|
|
return 1; /* date parse error */ |
|
|
|
|
#if defined(HAVE_TIMEGM) || defined(_WIN32) |
|
|
|
|
if (0 == lmtime) |
|
|
|
|
#endif |
|
|
|
|
{ |
|
|
|
|
struct tm lmodtm; |
|
|
|
|
if (NULL == http_date_str_to_tm(lmod, &lmodtm)) |
|
|
|
|
return 1; /* date parse error */ |
|
|
|
|
lmtime = http_date_timegm(&lmodtm); |
|
|
|
|
} |
|
|
|
|
const time_t ifmtime = http_date_timegm(&ifmodtm); |
|
|
|
|
return (lmtime > ifmtime); |
|
|
|
|
/* returns 0 if not modified since,
|
|
|
|
|