From c77aa79f51702179032b681fef2df31399fcec4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 31 Jul 2018 12:53:01 +0200 Subject: [core] update parse_date from cURL 7.61.0 --- src/parsedate/parsedate.cpp | 201 +++++++++++++++++++++----------------------- src/parsedate/parsedate.hpp | 7 +- 2 files changed, 100 insertions(+), 108 deletions(-) diff --git a/src/parsedate/parsedate.cpp b/src/parsedate/parsedate.cpp index ff945589bb..3697693f9d 100644 --- a/src/parsedate/parsedate.cpp +++ b/src/parsedate/parsedate.cpp @@ -5,11 +5,11 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2018, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -89,11 +89,6 @@ extern "C" { #include #include - -#define ERRNO (errno) -#define SET_ERRNO(x) (errno = (x)) - - /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because its behavior is altered by the current locale. */ char raw_toupper(char in) @@ -156,16 +151,19 @@ char raw_toupper(char in) } /* - * raw_equal() is for doing "raw" case insensitive strings. This is meant - * to be locale independent and only compare strings we know are safe for - * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for - * some further explanation to why this function is necessary. + * strcasecompare() is for doing "raw" case insensitive strings. This is + * meant to be locale independent and only compare strings we know are safe + * for this. See + * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some + * further explanation to why this function is necessary. * * The function is capable of comparing a-z case insensitively even for * non-ascii. + * + * @unittest: 1301 */ -int raw_equal(const char *first, const char *second) +int strcasecompare(const char *first, const char *second) { while(*first && *second) { if(raw_toupper(*first) != raw_toupper(*second)) @@ -201,23 +199,25 @@ int raw_equal(const char *first, const char *second) #endif +#define TIME_T_MIN 0 +#define TIME_T_MAX INT_MAX /* ** signed long to signed int */ -int clamp_to_int(long slnum) +int curlx_sltosi(long slnum) { return slnum > INT_MAX ? INT_MAX : slnum < INT_MIN ? INT_MIN : (int)slnum; } -const char * const wkday[] = +const char * const Curl_wkday[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; static const char * const weekday[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" }; -const char * const month[]= +const char * const Curl_month[]= { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; @@ -249,6 +249,7 @@ static int parsedate(const char *date, time_t *output); #define tDAYZONE -60 /* offset for daylight savings time */ static const struct tzinfo tz[]= { {"GMT", 0}, /* Greenwich Mean */ + {"UT", 0}, /* Universal Time */ {"UTC", 0}, /* Universal (Coordinated) */ {"WET", 0}, /* Western European */ {"BST", 0 tDAYZONE}, /* British Summer */ @@ -295,20 +296,20 @@ static const struct tzinfo tz[]= { RFC 1123) had their signs wrong. Here we use the correct signs to match actual military usage. */ - {"A", +1 * 60}, /* Alpha */ - {"B", +2 * 60}, /* Bravo */ - {"C", +3 * 60}, /* Charlie */ - {"D", +4 * 60}, /* Delta */ - {"E", +5 * 60}, /* Echo */ - {"F", +6 * 60}, /* Foxtrot */ - {"G", +7 * 60}, /* Golf */ - {"H", +8 * 60}, /* Hotel */ - {"I", +9 * 60}, /* India */ + {"A", 1 * 60}, /* Alpha */ + {"B", 2 * 60}, /* Bravo */ + {"C", 3 * 60}, /* Charlie */ + {"D", 4 * 60}, /* Delta */ + {"E", 5 * 60}, /* Echo */ + {"F", 6 * 60}, /* Foxtrot */ + {"G", 7 * 60}, /* Golf */ + {"H", 8 * 60}, /* Hotel */ + {"I", 9 * 60}, /* India */ /* "J", Juliet is not used as a timezone, to indicate the observer's local time */ - {"K", +10 * 60}, /* Kilo */ - {"L", +11 * 60}, /* Lima */ - {"M", +12 * 60}, /* Mike */ + {"K", 10 * 60}, /* Kilo */ + {"L", 11 * 60}, /* Lima */ + {"M", 12 * 60}, /* Mike */ {"N", -1 * 60}, /* November */ {"O", -2 * 60}, /* Oscar */ {"P", -3 * 60}, /* Papa */ @@ -333,14 +334,14 @@ static int checkday(const char *check, size_t len) { int i; const char * const *what; - bool found= FALSE; + bool found = FALSE; if(len > 3) what = &weekday[0]; else - what = &wkday[0]; - for(i=0; i<7; i++) { - if(raw_equal(check, what[0])) { - found=TRUE; + what = &Curl_wkday[0]; + for(i = 0; i<7; i++) { + if(strcasecompare(check, what[0])) { + found = TRUE; break; } what++; @@ -352,12 +353,12 @@ static int checkmonth(const char *check) { int i; const char * const *what; - bool found= FALSE; + bool found = FALSE; - what = &month[0]; - for(i=0; i<12; i++) { - if(raw_equal(check, what[0])) { - found=TRUE; + what = &Curl_month[0]; + for(i = 0; i<12; i++) { + if(strcasecompare(check, what[0])) { + found = TRUE; break; } what++; @@ -372,12 +373,12 @@ static int checktz(const char *check) { unsigned int i; const struct tzinfo *what; - bool found= FALSE; + bool found = FALSE; what = tz; - for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { - if(raw_equal(check, what->name)) { - found=TRUE; + for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) { + if(strcasecompare(check, what->name)) { + found = TRUE; break; } what++; @@ -406,26 +407,23 @@ struct my_tm { int tm_hour; int tm_mday; int tm_mon; - int tm_year; + int tm_year; /* full year */ }; /* struct tm to time since epoch in GMT time zone. * This is similar to the standard mktime function but for GMT only, and * doesn't suffer from the various bugs and portability problems that * some systems' implementations have. + * + * Returns 0 on success, otherwise non-zero. */ -static time_t my_timegm(struct my_tm *tm) +static void my_timegm(struct my_tm *tm, time_t *t) { static const int month_days_cumulative [12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; int month_, year, leap_days; - if(tm->tm_year < 70) - /* we don't support years before 1970 as they will cause this function - to return a negative value */ - return -1; - - year = tm->tm_year + 1900; + year = tm->tm_year; month_ = tm->tm_mon; if(month_ < 0) { year += (11 - month_) / 12; @@ -440,9 +438,9 @@ static time_t my_timegm(struct my_tm *tm) leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400) - (1969 / 4) + (1969 / 100) - (1969 / 400)); - return ((((time_t) (year - 1970) * 365 - + leap_days + month_days_cumulative [month_] + tm->tm_mday - 1) * 24 - + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec; + *t = ((((time_t) (year - 1970) * 365 + + leap_days + month_days_cumulative[month_] + tm->tm_mday - 1) * 24 + + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec; } /* @@ -459,21 +457,21 @@ static time_t my_timegm(struct my_tm *tm) static int parsedate(const char *date, time_t *output) { time_t t = 0; - int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */ - int monnum=-1; /* month of the year number, 0-11 */ - int mdaynum=-1; /* day of month, 1 - 31 */ - int hournum=-1; - int minnum=-1; - int secnum=-1; - int yearnum=-1; - int tzoff=-1; + int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */ + int monnum = -1; /* month of the year number, 0-11 */ + int mdaynum = -1; /* day of month, 1 - 31 */ + int hournum = -1; + int minnum = -1; + int secnum = -1; + int yearnum = -1; + int tzoff = -1; struct my_tm tm; enum assume dignext = DATE_MDAY; const char *indate = date; /* save the original pointer */ int part = 0; /* max 6 parts */ while(*date && (part < 6)) { - bool found=FALSE; + bool found = FALSE; skip(&date); @@ -514,15 +512,17 @@ static int parsedate(const char *date, time_t *output) /* a digit */ int val; char *end; + int len = 0; if((secnum == -1) && - (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { + (3 == sscanf(date, "%02d:%02d:%02d%n", + &hournum, &minnum, &secnum, &len))) { /* time stamp! */ - date += 8; + date += len; } else if((secnum == -1) && - (2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) { + (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { /* time stamp without seconds */ - date += 5; + date += len; secnum = 0; } else { @@ -530,12 +530,12 @@ static int parsedate(const char *date, time_t *output) int error; int old_errno; - old_errno = ERRNO; - SET_ERRNO(0); + old_errno = errno; + errno = 0; lval = strtol(date, &end, 10); - error = ERRNO; - if(error != old_errno) - SET_ERRNO(old_errno); + error = errno; + if(errno != old_errno) + errno = old_errno; if(error) return PARSEDATE_FAIL; @@ -545,7 +545,7 @@ static int parsedate(const char *date, time_t *output) return PARSEDATE_FAIL; #endif - val = clamp_to_int(lval); + val = curlx_sltosi(lval); if((tzoff == -1) && ((end - date) == 4) && @@ -564,7 +564,7 @@ static int parsedate(const char *date, time_t *output) tzoff = (val/100 * 60 + val%100)*60; /* the + and - prefix indicates the local time compared to GMT, - this we need ther reversed math to get what we want */ + this we need their reversed math to get what we want */ tzoff = date[-1]=='+'?-tzoff:tzoff; } @@ -590,7 +590,7 @@ static int parsedate(const char *date, time_t *output) if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) { yearnum = val; found = TRUE; - if(yearnum < 1900) { + if(yearnum < 100) { if(yearnum > 70) yearnum += 1900; else @@ -619,19 +619,18 @@ static int parsedate(const char *date, time_t *output) /* lacks vital info, fail */ return PARSEDATE_FAIL; -#if SIZEOF_TIME_T < 5 - /* 32 bit time_t can only hold dates to the beginning of 2038 */ - if(yearnum > 2037) { - *output = 0x7fffffff; - return PARSEDATE_LATER; - } -#endif - if(yearnum < 1970) { - *output = 0; + /* only positive numbers cannot return earlier */ + *output = TIME_T_MIN; return PARSEDATE_SOONER; } + /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */ + if(yearnum > 2037) { + *output = TIME_T_MAX; + return PARSEDATE_LATER; + } + if((mdaynum > 31) || (monnum > 11) || (hournum > 23) || (minnum > 59) || (secnum > 60)) return PARSEDATE_FAIL; /* clearly an illegal date */ @@ -641,29 +640,25 @@ static int parsedate(const char *date, time_t *output) tm.tm_hour = hournum; tm.tm_mday = mdaynum; tm.tm_mon = monnum; - tm.tm_year = yearnum - 1900; + tm.tm_year = yearnum; - /* my_timegm() returns a time_t. time_t is often 32 bits, even on many - architectures that feature 64 bit 'long'. - - Some systems have 64 bit time_t and deal with years beyond 2038. However, - even on some of the systems with 64 bit time_t mktime() returns -1 for - dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06) + /* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on + architectures that feature 64 bit 'long' but ultimately time_t is the + correct data type to use. */ - t = my_timegm(&tm); - - /* time zone adjust (cast t to int to compare to negative one) */ - if(-1 != (int)t) { + my_timegm(&tm, &t); - /* Add the time zone diff between local time zone and GMT. */ - long delta = (long)(tzoff!=-1?tzoff:0); + /* Add the time zone diff between local time zone and GMT. */ + if(tzoff == -1) + tzoff = 0; - if((delta>0) && (t > LONG_MAX - delta)) - return -1; /* time_t overflow */ - - t += delta; + if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) { + *output = TIME_T_MAX; + return PARSEDATE_LATER; /* time_t overflow */ } + t += tzoff; + *output = t; return PARSEDATE_OK; @@ -674,10 +669,10 @@ time_t parse_date(const char *p) time_t parsed = -1; int rc = parsedate(p, &parsed); - switch(rc) { - case PARSEDATE_OK: - case PARSEDATE_LATER: - case PARSEDATE_SOONER: + if(rc == PARSEDATE_OK) { + if(parsed == -1) + /* avoid returning -1 for a working scenario */ + parsed++; return parsed; } /* everything else is fail */ diff --git a/src/parsedate/parsedate.hpp b/src/parsedate/parsedate.hpp index 6905e361d4..40bfccb7a0 100644 --- a/src/parsedate/parsedate.hpp +++ b/src/parsedate/parsedate.hpp @@ -1,5 +1,4 @@ -#ifndef HEADER_PARSEDATE_H -#define HEADER_PARSEDATE_H +#pragma once /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -11,7 +10,7 @@ * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms - * are also available at http://curl.haxx.se/docs/copyright.html. + * are also available at https://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is @@ -34,5 +33,3 @@ time_t parse_date(const char *p); #ifdef __cplusplus } #endif - -#endif /* HEADER_PARSEDATE_H */ -- cgit v1.2.1