mirror of
https://github.com/curl/curl.git
synced 2026-04-14 23:01:41 +03:00
parsedate: make Curl_getdate_capped able to return epoch
By returning error separately on parse errors and avoiding magic numbers, this function can now return 0 or -1 as proper dates when such a date string is provided. Closes #18445
This commit is contained in:
parent
4d040c71d7
commit
f8e6e11725
9 changed files with 50 additions and 68 deletions
|
|
@ -187,13 +187,13 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
|
||||||
else {
|
else {
|
||||||
struct altsvc *as;
|
struct altsvc *as;
|
||||||
char dbuf[MAX_ALTSVC_DATELEN + 1];
|
char dbuf[MAX_ALTSVC_DATELEN + 1];
|
||||||
time_t expires;
|
time_t expires = 0;
|
||||||
|
|
||||||
/* The date parser works on a null-terminated string. The maximum length
|
/* The date parser works on a null-terminated string. The maximum length
|
||||||
is upheld by curlx_str_quotedword(). */
|
is upheld by curlx_str_quotedword(). */
|
||||||
memcpy(dbuf, curlx_str(&date), curlx_strlen(&date));
|
memcpy(dbuf, curlx_str(&date), curlx_strlen(&date));
|
||||||
dbuf[curlx_strlen(&date)] = 0;
|
dbuf[curlx_strlen(&date)] = 0;
|
||||||
expires = Curl_getdate_capped(dbuf);
|
Curl_getdate_capped(dbuf, &expires);
|
||||||
as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn,
|
as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn,
|
||||||
(size_t)srcport, (size_t)dstport);
|
(size_t)srcport, (size_t)dstport);
|
||||||
if(as) {
|
if(as) {
|
||||||
|
|
|
||||||
31
lib/cookie.c
31
lib/cookie.c
|
|
@ -107,7 +107,7 @@ static void strstore(char **str, const char *newstr, size_t len);
|
||||||
*/
|
*/
|
||||||
static void cap_expires(time_t now, struct Cookie *co)
|
static void cap_expires(time_t now, struct Cookie *co)
|
||||||
{
|
{
|
||||||
if((TIME_T_MAX - COOKIES_MAXAGE - 30) > now) {
|
if(co->expires && (TIME_T_MAX - COOKIES_MAXAGE - 30) > now) {
|
||||||
timediff_t cap = now + COOKIES_MAXAGE;
|
timediff_t cap = now + COOKIES_MAXAGE;
|
||||||
if(co->expires > cap) {
|
if(co->expires > cap) {
|
||||||
cap += 30;
|
cap += 30;
|
||||||
|
|
@ -388,17 +388,17 @@ static void remove_expired(struct CookieInfo *ci)
|
||||||
for(n = Curl_llist_head(&ci->cookielist[i]); n; n = e) {
|
for(n = Curl_llist_head(&ci->cookielist[i]); n; n = e) {
|
||||||
co = Curl_node_elem(n);
|
co = Curl_node_elem(n);
|
||||||
e = Curl_node_next(n);
|
e = Curl_node_next(n);
|
||||||
if(co->expires && co->expires < now) {
|
if(co->expires) {
|
||||||
|
if(co->expires < now) {
|
||||||
Curl_node_remove(n);
|
Curl_node_remove(n);
|
||||||
freecookie(co);
|
freecookie(co);
|
||||||
ci->numcookies--;
|
ci->numcookies--;
|
||||||
}
|
}
|
||||||
else {
|
else if(co->expires < ci->next_expiration)
|
||||||
/*
|
/*
|
||||||
* If this cookie has an expiration timestamp earlier than what we
|
* If this cookie has an expiration timestamp earlier than what we
|
||||||
* have seen so far then record it for the next round of expirations.
|
* have seen so far then record it for the next round of expirations.
|
||||||
*/
|
*/
|
||||||
if(co->expires && co->expires < ci->next_expiration)
|
|
||||||
ci->next_expiration = co->expires;
|
ci->next_expiration = co->expires;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -666,7 +666,6 @@ parse_cookie_header(struct Curl_easy *data,
|
||||||
if(*maxage == '\"')
|
if(*maxage == '\"')
|
||||||
maxage++;
|
maxage++;
|
||||||
rc = curlx_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
|
rc = curlx_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);
|
||||||
|
|
||||||
switch(rc) {
|
switch(rc) {
|
||||||
case STRE_OVERFLOW:
|
case STRE_OVERFLOW:
|
||||||
/* overflow, used max value */
|
/* overflow, used max value */
|
||||||
|
|
@ -678,8 +677,7 @@ parse_cookie_header(struct Curl_easy *data,
|
||||||
break;
|
break;
|
||||||
case STRE_OK:
|
case STRE_OK:
|
||||||
if(!co->expires)
|
if(!co->expires)
|
||||||
/* already expired */
|
co->expires = 1; /* expire now */
|
||||||
co->expires = 1;
|
|
||||||
else if(CURL_OFF_T_MAX - now < co->expires)
|
else if(CURL_OFF_T_MAX - now < co->expires)
|
||||||
/* would overflow */
|
/* would overflow */
|
||||||
co->expires = CURL_OFF_T_MAX;
|
co->expires = CURL_OFF_T_MAX;
|
||||||
|
|
@ -698,18 +696,15 @@ parse_cookie_header(struct Curl_easy *data,
|
||||||
* will be treated as a session cookie
|
* will be treated as a session cookie
|
||||||
*/
|
*/
|
||||||
char dbuf[MAX_DATE_LENGTH + 1];
|
char dbuf[MAX_DATE_LENGTH + 1];
|
||||||
|
time_t date = 0;
|
||||||
memcpy(dbuf, curlx_str(&val), curlx_strlen(&val));
|
memcpy(dbuf, curlx_str(&val), curlx_strlen(&val));
|
||||||
dbuf[curlx_strlen(&val)] = 0;
|
dbuf[curlx_strlen(&val)] = 0;
|
||||||
co->expires = Curl_getdate_capped(dbuf);
|
if(!Curl_getdate_capped(dbuf, &date)) {
|
||||||
|
if(!date)
|
||||||
/*
|
date++;
|
||||||
* Session cookies have expires set to 0 so if we get that back
|
co->expires = (curl_off_t)date;
|
||||||
* from the date parser let's add a second to make it a
|
}
|
||||||
* non-session cookie
|
else
|
||||||
*/
|
|
||||||
if(co->expires == 0)
|
|
||||||
co->expires = 1;
|
|
||||||
else if(co->expires < 0)
|
|
||||||
co->expires = 0;
|
co->expires = 0;
|
||||||
cap_expires(now, co);
|
cap_expires(now, co);
|
||||||
}
|
}
|
||||||
|
|
@ -1103,7 +1098,7 @@ Curl_cookie_add(struct Curl_easy *data,
|
||||||
|
|
||||||
if(!ci->running && /* read from a file */
|
if(!ci->running && /* read from a file */
|
||||||
ci->newsession && /* clean session cookies */
|
ci->newsession && /* clean session cookies */
|
||||||
!co->expires) /* this is a session cookie since it does not expire */
|
!co->expires) /* this is a session cookie */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
co->livecookie = ci->running;
|
co->livecookie = ci->running;
|
||||||
|
|
|
||||||
10
lib/ftp.c
10
lib/ftp.c
|
|
@ -2102,6 +2102,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
|
||||||
int year, month, day, hour, minute, second;
|
int year, month, day, hour, minute, second;
|
||||||
struct pingpong *pp = &ftpc->pp;
|
struct pingpong *pp = &ftpc->pp;
|
||||||
char *resp = curlx_dyn_ptr(&pp->recvbuf) + 4;
|
char *resp = curlx_dyn_ptr(&pp->recvbuf) + 4;
|
||||||
|
bool showtime = FALSE;
|
||||||
if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) {
|
if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) {
|
||||||
/* we have a time, reformat it */
|
/* we have a time, reformat it */
|
||||||
char timebuf[24];
|
char timebuf[24];
|
||||||
|
|
@ -2109,7 +2110,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
|
||||||
"%04d%02d%02d %02d:%02d:%02d GMT",
|
"%04d%02d%02d %02d:%02d:%02d GMT",
|
||||||
year, month, day, hour, minute, second);
|
year, month, day, hour, minute, second);
|
||||||
/* now, convert this into a time() value: */
|
/* now, convert this into a time() value: */
|
||||||
data->info.filetime = Curl_getdate_capped(timebuf);
|
if(!Curl_getdate_capped(timebuf, &data->info.filetime))
|
||||||
|
showtime = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CURL_FTP_HTTPSTYLE_HEAD
|
#ifdef CURL_FTP_HTTPSTYLE_HEAD
|
||||||
|
|
@ -2122,10 +2124,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
|
||||||
warning: comparison of unsigned expression in '>= 0' is always true */
|
warning: comparison of unsigned expression in '>= 0' is always true */
|
||||||
#pragma GCC diagnostic ignored "-Wtype-limits"
|
#pragma GCC diagnostic ignored "-Wtype-limits"
|
||||||
#endif
|
#endif
|
||||||
if(data->req.no_body &&
|
if(data->req.no_body && ftpc->file &&
|
||||||
ftpc->file &&
|
data->set.get_filetime && showtime) {
|
||||||
data->set.get_filetime &&
|
|
||||||
(data->info.filetime >= 0) ) {
|
|
||||||
#if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__))
|
#if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__))
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
12
lib/hsts.c
12
lib/hsts.c
|
|
@ -426,7 +426,7 @@ static CURLcode hsts_add(struct hsts *h, const char *line)
|
||||||
bool subdomain = FALSE;
|
bool subdomain = FALSE;
|
||||||
struct stsentry *e;
|
struct stsentry *e;
|
||||||
char dbuf[MAX_HSTS_DATELEN + 1];
|
char dbuf[MAX_HSTS_DATELEN + 1];
|
||||||
time_t expires;
|
time_t expires = 0;
|
||||||
const char *hp = curlx_str(&host);
|
const char *hp = curlx_str(&host);
|
||||||
|
|
||||||
/* The date parser works on a null-terminated string. The maximum length
|
/* The date parser works on a null-terminated string. The maximum length
|
||||||
|
|
@ -434,8 +434,10 @@ static CURLcode hsts_add(struct hsts *h, const char *line)
|
||||||
memcpy(dbuf, curlx_str(&date), curlx_strlen(&date));
|
memcpy(dbuf, curlx_str(&date), curlx_strlen(&date));
|
||||||
dbuf[curlx_strlen(&date)] = 0;
|
dbuf[curlx_strlen(&date)] = 0;
|
||||||
|
|
||||||
expires = strcmp(dbuf, UNLIMITED) ? Curl_getdate_capped(dbuf) :
|
if(!strcmp(dbuf, UNLIMITED))
|
||||||
TIME_T_MAX;
|
expires = TIME_T_MAX;
|
||||||
|
else
|
||||||
|
Curl_getdate_capped(dbuf, &expires);
|
||||||
|
|
||||||
if(hp[0] == '.') {
|
if(hp[0] == '.') {
|
||||||
curlx_str_nudge(&host, 1);
|
curlx_str_nudge(&host, 1);
|
||||||
|
|
@ -478,14 +480,14 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
|
||||||
e.name[0] = 0; /* just to make it clean */
|
e.name[0] = 0; /* just to make it clean */
|
||||||
sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp);
|
sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp);
|
||||||
if(sc == CURLSTS_OK) {
|
if(sc == CURLSTS_OK) {
|
||||||
time_t expires;
|
time_t expires = 0;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
DEBUGASSERT(e.name[0]);
|
DEBUGASSERT(e.name[0]);
|
||||||
if(!e.name[0])
|
if(!e.name[0])
|
||||||
/* bail out if no name was stored */
|
/* bail out if no name was stored */
|
||||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||||
if(e.expire[0])
|
if(e.expire[0])
|
||||||
expires = Curl_getdate_capped(e.expire);
|
Curl_getdate_capped(e.expire, &expires);
|
||||||
else
|
else
|
||||||
expires = TIME_T_MAX; /* the end of time */
|
expires = TIME_T_MAX; /* the end of time */
|
||||||
result = hsts_create(h, e.name, strlen(e.name),
|
result = hsts_create(h, e.name, strlen(e.name),
|
||||||
|
|
|
||||||
|
|
@ -3196,7 +3196,8 @@ static CURLcode http_header_l(struct Curl_easy *data,
|
||||||
(data->set.timecondition || data->set.get_filetime)) ?
|
(data->set.timecondition || data->set.get_filetime)) ?
|
||||||
HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
|
HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
|
||||||
if(v) {
|
if(v) {
|
||||||
k->timeofdoc = Curl_getdate_capped(v);
|
if(Curl_getdate_capped(v, &k->timeofdoc))
|
||||||
|
k->timeofdoc = 0;
|
||||||
if(data->set.get_filetime)
|
if(data->set.get_filetime)
|
||||||
data->info.filetime = k->timeofdoc;
|
data->info.filetime = k->timeofdoc;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
|
@ -3311,14 +3312,12 @@ static CURLcode http_header_r(struct Curl_easy *data,
|
||||||
if(v) {
|
if(v) {
|
||||||
/* Retry-After = HTTP-date / delay-seconds */
|
/* Retry-After = HTTP-date / delay-seconds */
|
||||||
curl_off_t retry_after = 0; /* zero for unknown or "now" */
|
curl_off_t retry_after = 0; /* zero for unknown or "now" */
|
||||||
time_t date;
|
time_t date = 0;
|
||||||
curlx_str_passblanks(&v);
|
curlx_str_passblanks(&v);
|
||||||
|
|
||||||
/* try it as a date first, because a date can otherwise start with and
|
/* try it as a date first, because a date can otherwise start with and
|
||||||
get treated as a number */
|
get treated as a number */
|
||||||
date = Curl_getdate_capped(v);
|
if(!Curl_getdate_capped(v, &date)) {
|
||||||
|
|
||||||
if((time_t)-1 != date) {
|
|
||||||
time_t current = time(NULL);
|
time_t current = time(NULL);
|
||||||
if(date >= current)
|
if(date >= current)
|
||||||
/* convert date to number of seconds into the future */
|
/* convert date to number of seconds into the future */
|
||||||
|
|
|
||||||
|
|
@ -589,26 +589,12 @@ time_t curl_getdate(const char *p, const time_t *now)
|
||||||
|
|
||||||
/* Curl_getdate_capped() differs from curl_getdate() in that this will return
|
/* Curl_getdate_capped() differs from curl_getdate() in that this will return
|
||||||
TIME_T_MAX in case the parsed time value was too big, instead of an
|
TIME_T_MAX in case the parsed time value was too big, instead of an
|
||||||
error. */
|
error. Returns non-zero on error. */
|
||||||
|
|
||||||
time_t Curl_getdate_capped(const char *p)
|
int Curl_getdate_capped(const char *p, time_t *tp)
|
||||||
{
|
{
|
||||||
time_t parsed = -1;
|
int rc = parsedate(p, tp);
|
||||||
int rc = parsedate(p, &parsed);
|
return (rc == PARSEDATE_FAIL);
|
||||||
|
|
||||||
switch(rc) {
|
|
||||||
case PARSEDATE_OK:
|
|
||||||
if(parsed == (time_t)-1)
|
|
||||||
/* avoid returning -1 for a working scenario */
|
|
||||||
parsed++;
|
|
||||||
return parsed;
|
|
||||||
case PARSEDATE_LATER:
|
|
||||||
/* this returns the maximum time value */
|
|
||||||
return parsed;
|
|
||||||
default:
|
|
||||||
return -1; /* everything else is fail */
|
|
||||||
}
|
|
||||||
/* UNREACHABLE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,10 @@ extern const char * const Curl_month[12];
|
||||||
|
|
||||||
CURLcode Curl_gmtime(time_t intime, struct tm *store);
|
CURLcode Curl_gmtime(time_t intime, struct tm *store);
|
||||||
|
|
||||||
/* Curl_getdate_capped() differs from curl_getdate() in that this will return
|
/* Curl_getdate_capped() differs from curl_getdate() in that this returns
|
||||||
TIME_T_MAX in case the parsed time value was too big, instead of an
|
TIME_T_MAX in case the parsed time value was too big, instead of an
|
||||||
error. */
|
error. */
|
||||||
|
|
||||||
time_t Curl_getdate_capped(const char *p);
|
int Curl_getdate_capped(const char *p, time_t *store);
|
||||||
|
|
||||||
#endif /* HEADER_CURL_PARSEDATE_H */
|
#endif /* HEADER_CURL_PARSEDATE_H */
|
||||||
|
|
|
||||||
|
|
@ -1855,9 +1855,9 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data,
|
||||||
}
|
}
|
||||||
else if(!strncmp(cmd, "atime", 5) ||
|
else if(!strncmp(cmd, "atime", 5) ||
|
||||||
!strncmp(cmd, "mtime", 5)) {
|
!strncmp(cmd, "mtime", 5)) {
|
||||||
time_t date = Curl_getdate_capped(sshc->quote_path1);
|
time_t date;
|
||||||
bool fail = FALSE;
|
bool fail = FALSE;
|
||||||
if(date == -1) {
|
if(Curl_getdate_capped(sshc->quote_path1, &date)) {
|
||||||
failf(data, "incorrect date format for %.*s", 5, cmd);
|
failf(data, "incorrect date format for %.*s", 5, cmd);
|
||||||
fail = TRUE;
|
fail = TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1390,16 +1390,16 @@ sftp_quote_stat(struct Curl_easy *data,
|
||||||
}
|
}
|
||||||
else if(!strncmp(cmd, "atime", 5) ||
|
else if(!strncmp(cmd, "atime", 5) ||
|
||||||
!strncmp(cmd, "mtime", 5)) {
|
!strncmp(cmd, "mtime", 5)) {
|
||||||
time_t date = Curl_getdate_capped(sshc->quote_path1);
|
time_t date;
|
||||||
bool fail = FALSE;
|
bool fail = FALSE;
|
||||||
|
|
||||||
if(date == -1) {
|
if(Curl_getdate_capped(sshc->quote_path1, &date)) {
|
||||||
failf(data, "incorrect date format for %.*s", 5, cmd);
|
failf(data, "incorrect date format for %.*s", 5, cmd);
|
||||||
fail = TRUE;
|
fail = TRUE;
|
||||||
}
|
}
|
||||||
#if SIZEOF_TIME_T > SIZEOF_LONG
|
#if SIZEOF_TIME_T > SIZEOF_LONG
|
||||||
if(date > 0xffffffff) {
|
if(date > 0xffffffff) {
|
||||||
/* if 'long' cannot old >32-bit, this date cannot be sent */
|
/* if 'long' cannot hold >32-bit, this date cannot be sent */
|
||||||
failf(data, "date overflow");
|
failf(data, "date overflow");
|
||||||
fail = TRUE;
|
fail = TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue