[337] | 1 | /***************************************************************************
|
---|
| 2 | * _ _ ____ _
|
---|
| 3 | * Project ___| | | | _ \| |
|
---|
| 4 | * / __| | | | |_) | |
|
---|
| 5 | * | (__| |_| | _ <| |___
|
---|
| 6 | * \___|\___/|_| \_\_____|
|
---|
| 7 | *
|
---|
| 8 | * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
---|
| 9 | *
|
---|
| 10 | * This software is licensed as described in the file COPYING, which
|
---|
| 11 | * you should have received as part of this distribution. The terms
|
---|
| 12 | * are also available at https://curl.haxx.se/docs/copyright.html.
|
---|
| 13 | *
|
---|
| 14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
---|
| 15 | * copies of the Software, and permit persons to whom the Software is
|
---|
| 16 | * furnished to do so, under the terms of the COPYING file.
|
---|
| 17 | *
|
---|
| 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
---|
| 19 | * KIND, either express or implied.
|
---|
| 20 | *
|
---|
| 21 | ***************************************************************************/
|
---|
| 22 | /*
|
---|
| 23 | A brief summary of the date string formats this parser groks:
|
---|
| 24 |
|
---|
| 25 | RFC 2616 3.3.1
|
---|
| 26 |
|
---|
| 27 | Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
|
---|
| 28 | Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
|
---|
| 29 | Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
|
---|
| 30 |
|
---|
| 31 | we support dates without week day name:
|
---|
| 32 |
|
---|
| 33 | 06 Nov 1994 08:49:37 GMT
|
---|
| 34 | 06-Nov-94 08:49:37 GMT
|
---|
| 35 | Nov 6 08:49:37 1994
|
---|
| 36 |
|
---|
| 37 | without the time zone:
|
---|
| 38 |
|
---|
| 39 | 06 Nov 1994 08:49:37
|
---|
| 40 | 06-Nov-94 08:49:37
|
---|
| 41 |
|
---|
| 42 | weird order:
|
---|
| 43 |
|
---|
| 44 | 1994 Nov 6 08:49:37 (GNU date fails)
|
---|
| 45 | GMT 08:49:37 06-Nov-94 Sunday
|
---|
| 46 | 94 6 Nov 08:49:37 (GNU date fails)
|
---|
| 47 |
|
---|
| 48 | time left out:
|
---|
| 49 |
|
---|
| 50 | 1994 Nov 6
|
---|
| 51 | 06-Nov-94
|
---|
| 52 | Sun Nov 6 94
|
---|
| 53 |
|
---|
| 54 | unusual separators:
|
---|
| 55 |
|
---|
| 56 | 1994.Nov.6
|
---|
| 57 | Sun/Nov/6/94/GMT
|
---|
| 58 |
|
---|
| 59 | commonly used time zone names:
|
---|
| 60 |
|
---|
| 61 | Sun, 06 Nov 1994 08:49:37 CET
|
---|
| 62 | 06 Nov 1994 08:49:37 EST
|
---|
| 63 |
|
---|
| 64 | time zones specified using RFC822 style:
|
---|
| 65 |
|
---|
| 66 | Sun, 12 Sep 2004 15:05:58 -0700
|
---|
| 67 | Sat, 11 Sep 2004 21:32:11 +0200
|
---|
| 68 |
|
---|
| 69 | compact numerical date strings:
|
---|
| 70 |
|
---|
| 71 | 20040912 15:05:58 -0700
|
---|
| 72 | 20040911 +0200
|
---|
| 73 |
|
---|
| 74 | */
|
---|
| 75 |
|
---|
| 76 | #include "curl_setup.h"
|
---|
| 77 |
|
---|
| 78 | #ifdef HAVE_LIMITS_H
|
---|
| 79 | #include <limits.h>
|
---|
| 80 | #endif
|
---|
| 81 |
|
---|
| 82 | #include <curl/curl.h>
|
---|
| 83 | #include "strcase.h"
|
---|
| 84 | #include "warnless.h"
|
---|
| 85 | #include "parsedate.h"
|
---|
| 86 |
|
---|
| 87 | const char * const Curl_wkday[] =
|
---|
| 88 | {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
|
---|
| 89 | static const char * const weekday[] =
|
---|
| 90 | { "Monday", "Tuesday", "Wednesday", "Thursday",
|
---|
| 91 | "Friday", "Saturday", "Sunday" };
|
---|
| 92 | const char * const Curl_month[]=
|
---|
| 93 | { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
---|
| 94 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
---|
| 95 |
|
---|
| 96 | struct tzinfo {
|
---|
| 97 | char name[5];
|
---|
| 98 | int offset; /* +/- in minutes */
|
---|
| 99 | };
|
---|
| 100 |
|
---|
| 101 | /*
|
---|
| 102 | * parsedate()
|
---|
| 103 | *
|
---|
| 104 | * Returns:
|
---|
| 105 | *
|
---|
| 106 | * PARSEDATE_OK - a fine conversion
|
---|
| 107 | * PARSEDATE_FAIL - failed to convert
|
---|
| 108 | * PARSEDATE_LATER - time overflow at the far end of time_t
|
---|
| 109 | * PARSEDATE_SOONER - time underflow at the low end of time_t
|
---|
| 110 | */
|
---|
| 111 |
|
---|
| 112 | static int parsedate(const char *date, time_t *output);
|
---|
| 113 |
|
---|
| 114 | #define PARSEDATE_OK 0
|
---|
| 115 | #define PARSEDATE_FAIL -1
|
---|
| 116 | #define PARSEDATE_LATER 1
|
---|
| 117 | #define PARSEDATE_SOONER 2
|
---|
| 118 |
|
---|
| 119 | /* Here's a bunch of frequently used time zone names. These were supported
|
---|
| 120 | by the old getdate parser. */
|
---|
| 121 | #define tDAYZONE -60 /* offset for daylight savings time */
|
---|
| 122 | static const struct tzinfo tz[]= {
|
---|
| 123 | {"GMT", 0}, /* Greenwich Mean */
|
---|
| 124 | {"UTC", 0}, /* Universal (Coordinated) */
|
---|
| 125 | {"WET", 0}, /* Western European */
|
---|
| 126 | {"BST", 0 tDAYZONE}, /* British Summer */
|
---|
| 127 | {"WAT", 60}, /* West Africa */
|
---|
| 128 | {"AST", 240}, /* Atlantic Standard */
|
---|
| 129 | {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */
|
---|
| 130 | {"EST", 300}, /* Eastern Standard */
|
---|
| 131 | {"EDT", 300 tDAYZONE}, /* Eastern Daylight */
|
---|
| 132 | {"CST", 360}, /* Central Standard */
|
---|
| 133 | {"CDT", 360 tDAYZONE}, /* Central Daylight */
|
---|
| 134 | {"MST", 420}, /* Mountain Standard */
|
---|
| 135 | {"MDT", 420 tDAYZONE}, /* Mountain Daylight */
|
---|
| 136 | {"PST", 480}, /* Pacific Standard */
|
---|
| 137 | {"PDT", 480 tDAYZONE}, /* Pacific Daylight */
|
---|
| 138 | {"YST", 540}, /* Yukon Standard */
|
---|
| 139 | {"YDT", 540 tDAYZONE}, /* Yukon Daylight */
|
---|
| 140 | {"HST", 600}, /* Hawaii Standard */
|
---|
| 141 | {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */
|
---|
| 142 | {"CAT", 600}, /* Central Alaska */
|
---|
| 143 | {"AHST", 600}, /* Alaska-Hawaii Standard */
|
---|
| 144 | {"NT", 660}, /* Nome */
|
---|
| 145 | {"IDLW", 720}, /* International Date Line West */
|
---|
| 146 | {"CET", -60}, /* Central European */
|
---|
| 147 | {"MET", -60}, /* Middle European */
|
---|
| 148 | {"MEWT", -60}, /* Middle European Winter */
|
---|
| 149 | {"MEST", -60 tDAYZONE}, /* Middle European Summer */
|
---|
| 150 | {"CEST", -60 tDAYZONE}, /* Central European Summer */
|
---|
| 151 | {"MESZ", -60 tDAYZONE}, /* Middle European Summer */
|
---|
| 152 | {"FWT", -60}, /* French Winter */
|
---|
| 153 | {"FST", -60 tDAYZONE}, /* French Summer */
|
---|
| 154 | {"EET", -120}, /* Eastern Europe, USSR Zone 1 */
|
---|
| 155 | {"WAST", -420}, /* West Australian Standard */
|
---|
| 156 | {"WADT", -420 tDAYZONE}, /* West Australian Daylight */
|
---|
| 157 | {"CCT", -480}, /* China Coast, USSR Zone 7 */
|
---|
| 158 | {"JST", -540}, /* Japan Standard, USSR Zone 8 */
|
---|
| 159 | {"EAST", -600}, /* Eastern Australian Standard */
|
---|
| 160 | {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */
|
---|
| 161 | {"GST", -600}, /* Guam Standard, USSR Zone 9 */
|
---|
| 162 | {"NZT", -720}, /* New Zealand */
|
---|
| 163 | {"NZST", -720}, /* New Zealand Standard */
|
---|
| 164 | {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */
|
---|
| 165 | {"IDLE", -720}, /* International Date Line East */
|
---|
| 166 | /* Next up: Military timezone names. RFC822 allowed these, but (as noted in
|
---|
| 167 | RFC 1123) had their signs wrong. Here we use the correct signs to match
|
---|
| 168 | actual military usage.
|
---|
| 169 | */
|
---|
| 170 | {"A", 1 * 60}, /* Alpha */
|
---|
| 171 | {"B", 2 * 60}, /* Bravo */
|
---|
| 172 | {"C", 3 * 60}, /* Charlie */
|
---|
| 173 | {"D", 4 * 60}, /* Delta */
|
---|
| 174 | {"E", 5 * 60}, /* Echo */
|
---|
| 175 | {"F", 6 * 60}, /* Foxtrot */
|
---|
| 176 | {"G", 7 * 60}, /* Golf */
|
---|
| 177 | {"H", 8 * 60}, /* Hotel */
|
---|
| 178 | {"I", 9 * 60}, /* India */
|
---|
| 179 | /* "J", Juliet is not used as a timezone, to indicate the observer's local
|
---|
| 180 | time */
|
---|
| 181 | {"K", 10 * 60}, /* Kilo */
|
---|
| 182 | {"L", 11 * 60}, /* Lima */
|
---|
| 183 | {"M", 12 * 60}, /* Mike */
|
---|
| 184 | {"N", -1 * 60}, /* November */
|
---|
| 185 | {"O", -2 * 60}, /* Oscar */
|
---|
| 186 | {"P", -3 * 60}, /* Papa */
|
---|
| 187 | {"Q", -4 * 60}, /* Quebec */
|
---|
| 188 | {"R", -5 * 60}, /* Romeo */
|
---|
| 189 | {"S", -6 * 60}, /* Sierra */
|
---|
| 190 | {"T", -7 * 60}, /* Tango */
|
---|
| 191 | {"U", -8 * 60}, /* Uniform */
|
---|
| 192 | {"V", -9 * 60}, /* Victor */
|
---|
| 193 | {"W", -10 * 60}, /* Whiskey */
|
---|
| 194 | {"X", -11 * 60}, /* X-ray */
|
---|
| 195 | {"Y", -12 * 60}, /* Yankee */
|
---|
| 196 | {"Z", 0}, /* Zulu, zero meridian, a.k.a. UTC */
|
---|
| 197 | };
|
---|
| 198 |
|
---|
| 199 | /* returns:
|
---|
| 200 | -1 no day
|
---|
| 201 | 0 monday - 6 sunday
|
---|
| 202 | */
|
---|
| 203 |
|
---|
| 204 | static int checkday(const char *check, size_t len)
|
---|
| 205 | {
|
---|
| 206 | int i;
|
---|
| 207 | const char * const *what;
|
---|
| 208 | bool found = FALSE;
|
---|
| 209 | if(len > 3)
|
---|
| 210 | what = &weekday[0];
|
---|
| 211 | else
|
---|
| 212 | what = &Curl_wkday[0];
|
---|
| 213 | for(i = 0; i<7; i++) {
|
---|
| 214 | if(strcasecompare(check, what[0])) {
|
---|
| 215 | found = TRUE;
|
---|
| 216 | break;
|
---|
| 217 | }
|
---|
| 218 | what++;
|
---|
| 219 | }
|
---|
| 220 | return found?i:-1;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | static int checkmonth(const char *check)
|
---|
| 224 | {
|
---|
| 225 | int i;
|
---|
| 226 | const char * const *what;
|
---|
| 227 | bool found = FALSE;
|
---|
| 228 |
|
---|
| 229 | what = &Curl_month[0];
|
---|
| 230 | for(i = 0; i<12; i++) {
|
---|
| 231 | if(strcasecompare(check, what[0])) {
|
---|
| 232 | found = TRUE;
|
---|
| 233 | break;
|
---|
| 234 | }
|
---|
| 235 | what++;
|
---|
| 236 | }
|
---|
| 237 | return found?i:-1; /* return the offset or -1, no real offset is -1 */
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | /* return the time zone offset between GMT and the input one, in number
|
---|
| 241 | of seconds or -1 if the timezone wasn't found/legal */
|
---|
| 242 |
|
---|
| 243 | static int checktz(const char *check)
|
---|
| 244 | {
|
---|
| 245 | unsigned int i;
|
---|
| 246 | const struct tzinfo *what;
|
---|
| 247 | bool found = FALSE;
|
---|
| 248 |
|
---|
| 249 | what = tz;
|
---|
| 250 | for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
|
---|
| 251 | if(strcasecompare(check, what->name)) {
|
---|
| 252 | found = TRUE;
|
---|
| 253 | break;
|
---|
| 254 | }
|
---|
| 255 | what++;
|
---|
| 256 | }
|
---|
| 257 | return found?what->offset*60:-1;
|
---|
| 258 | }
|
---|
| 259 |
|
---|
| 260 | static void skip(const char **date)
|
---|
| 261 | {
|
---|
| 262 | /* skip everything that aren't letters or digits */
|
---|
| 263 | while(**date && !ISALNUM(**date))
|
---|
| 264 | (*date)++;
|
---|
| 265 | }
|
---|
| 266 |
|
---|
| 267 | enum assume {
|
---|
| 268 | DATE_MDAY,
|
---|
| 269 | DATE_YEAR,
|
---|
| 270 | DATE_TIME
|
---|
| 271 | };
|
---|
| 272 |
|
---|
| 273 | /* this is a clone of 'struct tm' but with all fields we don't need or use
|
---|
| 274 | cut out */
|
---|
| 275 | struct my_tm {
|
---|
| 276 | int tm_sec;
|
---|
| 277 | int tm_min;
|
---|
| 278 | int tm_hour;
|
---|
| 279 | int tm_mday;
|
---|
| 280 | int tm_mon;
|
---|
| 281 | int tm_year;
|
---|
| 282 | };
|
---|
| 283 |
|
---|
| 284 | /* struct tm to time since epoch in GMT time zone.
|
---|
| 285 | * This is similar to the standard mktime function but for GMT only, and
|
---|
| 286 | * doesn't suffer from the various bugs and portability problems that
|
---|
| 287 | * some systems' implementations have.
|
---|
| 288 | */
|
---|
| 289 | static time_t my_timegm(struct my_tm *tm)
|
---|
| 290 | {
|
---|
| 291 | static const int month_days_cumulative [12] =
|
---|
| 292 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
---|
| 293 | int month, year, leap_days;
|
---|
| 294 |
|
---|
| 295 | if(tm->tm_year < 70)
|
---|
| 296 | /* we don't support years before 1970 as they will cause this function
|
---|
| 297 | to return a negative value */
|
---|
| 298 | return -1;
|
---|
| 299 |
|
---|
| 300 | year = tm->tm_year + 1900;
|
---|
| 301 | month = tm->tm_mon;
|
---|
| 302 | if(month < 0) {
|
---|
| 303 | year += (11 - month) / 12;
|
---|
| 304 | month = 11 - (11 - month) % 12;
|
---|
| 305 | }
|
---|
| 306 | else if(month >= 12) {
|
---|
| 307 | year -= month / 12;
|
---|
| 308 | month = month % 12;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | leap_days = year - (tm->tm_mon <= 1);
|
---|
| 312 | leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
|
---|
| 313 | - (1969 / 4) + (1969 / 100) - (1969 / 400));
|
---|
| 314 |
|
---|
| 315 | return ((((time_t) (year - 1970) * 365
|
---|
| 316 | + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24
|
---|
| 317 | + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 | /*
|
---|
| 321 | * parsedate()
|
---|
| 322 | *
|
---|
| 323 | * Returns:
|
---|
| 324 | *
|
---|
| 325 | * PARSEDATE_OK - a fine conversion
|
---|
| 326 | * PARSEDATE_FAIL - failed to convert
|
---|
| 327 | * PARSEDATE_LATER - time overflow at the far end of time_t
|
---|
| 328 | * PARSEDATE_SOONER - time underflow at the low end of time_t
|
---|
| 329 | */
|
---|
| 330 |
|
---|
| 331 | static int parsedate(const char *date, time_t *output)
|
---|
| 332 | {
|
---|
| 333 | time_t t = 0;
|
---|
| 334 | int wdaynum = -1; /* day of the week number, 0-6 (mon-sun) */
|
---|
| 335 | int monnum = -1; /* month of the year number, 0-11 */
|
---|
| 336 | int mdaynum = -1; /* day of month, 1 - 31 */
|
---|
| 337 | int hournum = -1;
|
---|
| 338 | int minnum = -1;
|
---|
| 339 | int secnum = -1;
|
---|
| 340 | int yearnum = -1;
|
---|
| 341 | int tzoff = -1;
|
---|
| 342 | struct my_tm tm;
|
---|
| 343 | enum assume dignext = DATE_MDAY;
|
---|
| 344 | const char *indate = date; /* save the original pointer */
|
---|
| 345 | int part = 0; /* max 6 parts */
|
---|
| 346 |
|
---|
| 347 | while(*date && (part < 6)) {
|
---|
| 348 | bool found = FALSE;
|
---|
| 349 |
|
---|
| 350 | skip(&date);
|
---|
| 351 |
|
---|
| 352 | if(ISALPHA(*date)) {
|
---|
| 353 | /* a name coming up */
|
---|
| 354 | char buf[32]="";
|
---|
| 355 | size_t len;
|
---|
| 356 | if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
---|
| 357 | "abcdefghijklmnopqrstuvwxyz]", buf))
|
---|
| 358 | len = strlen(buf);
|
---|
| 359 | else
|
---|
| 360 | len = 0;
|
---|
| 361 |
|
---|
| 362 | if(wdaynum == -1) {
|
---|
| 363 | wdaynum = checkday(buf, len);
|
---|
| 364 | if(wdaynum != -1)
|
---|
| 365 | found = TRUE;
|
---|
| 366 | }
|
---|
| 367 | if(!found && (monnum == -1)) {
|
---|
| 368 | monnum = checkmonth(buf);
|
---|
| 369 | if(monnum != -1)
|
---|
| 370 | found = TRUE;
|
---|
| 371 | }
|
---|
| 372 |
|
---|
| 373 | if(!found && (tzoff == -1)) {
|
---|
| 374 | /* this just must be a time zone string */
|
---|
| 375 | tzoff = checktz(buf);
|
---|
| 376 | if(tzoff != -1)
|
---|
| 377 | found = TRUE;
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | if(!found)
|
---|
| 381 | return PARSEDATE_FAIL; /* bad string */
|
---|
| 382 |
|
---|
| 383 | date += len;
|
---|
| 384 | }
|
---|
| 385 | else if(ISDIGIT(*date)) {
|
---|
| 386 | /* a digit */
|
---|
| 387 | int val;
|
---|
| 388 | char *end;
|
---|
| 389 | int len = 0;
|
---|
| 390 | if((secnum == -1) &&
|
---|
| 391 | (3 == sscanf(date, "%02d:%02d:%02d%n",
|
---|
| 392 | &hournum, &minnum, &secnum, &len))) {
|
---|
| 393 | /* time stamp! */
|
---|
| 394 | date += len;
|
---|
| 395 | }
|
---|
| 396 | else if((secnum == -1) &&
|
---|
| 397 | (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) {
|
---|
| 398 | /* time stamp without seconds */
|
---|
| 399 | date += len;
|
---|
| 400 | secnum = 0;
|
---|
| 401 | }
|
---|
| 402 | else {
|
---|
| 403 | long lval;
|
---|
| 404 | int error;
|
---|
| 405 | int old_errno;
|
---|
| 406 |
|
---|
| 407 | old_errno = errno;
|
---|
| 408 | errno = 0;
|
---|
| 409 | lval = strtol(date, &end, 10);
|
---|
| 410 | error = errno;
|
---|
| 411 | if(errno != old_errno)
|
---|
| 412 | errno = old_errno;
|
---|
| 413 |
|
---|
| 414 | if(error)
|
---|
| 415 | return PARSEDATE_FAIL;
|
---|
| 416 |
|
---|
| 417 | #if LONG_MAX != INT_MAX
|
---|
| 418 | if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
|
---|
| 419 | return PARSEDATE_FAIL;
|
---|
| 420 | #endif
|
---|
| 421 |
|
---|
| 422 | val = curlx_sltosi(lval);
|
---|
| 423 |
|
---|
| 424 | if((tzoff == -1) &&
|
---|
| 425 | ((end - date) == 4) &&
|
---|
| 426 | (val <= 1400) &&
|
---|
| 427 | (indate< date) &&
|
---|
| 428 | ((date[-1] == '+' || date[-1] == '-'))) {
|
---|
| 429 | /* four digits and a value less than or equal to 1400 (to take into
|
---|
| 430 | account all sorts of funny time zone diffs) and it is preceded
|
---|
| 431 | with a plus or minus. This is a time zone indication. 1400 is
|
---|
| 432 | picked since +1300 is frequently used and +1400 is mentioned as
|
---|
| 433 | an edge number in the document "ISO C 200X Proposal: Timezone
|
---|
| 434 | Functions" at http://david.tribble.com/text/c0xtimezone.html If
|
---|
| 435 | anyone has a more authoritative source for the exact maximum time
|
---|
| 436 | zone offsets, please speak up! */
|
---|
| 437 | found = TRUE;
|
---|
| 438 | tzoff = (val/100 * 60 + val%100)*60;
|
---|
| 439 |
|
---|
| 440 | /* the + and - prefix indicates the local time compared to GMT,
|
---|
| 441 | this we need ther reversed math to get what we want */
|
---|
| 442 | tzoff = date[-1]=='+'?-tzoff:tzoff;
|
---|
| 443 | }
|
---|
| 444 |
|
---|
| 445 | if(((end - date) == 8) &&
|
---|
| 446 | (yearnum == -1) &&
|
---|
| 447 | (monnum == -1) &&
|
---|
| 448 | (mdaynum == -1)) {
|
---|
| 449 | /* 8 digits, no year, month or day yet. This is YYYYMMDD */
|
---|
| 450 | found = TRUE;
|
---|
| 451 | yearnum = val/10000;
|
---|
| 452 | monnum = (val%10000)/100-1; /* month is 0 - 11 */
|
---|
| 453 | mdaynum = val%100;
|
---|
| 454 | }
|
---|
| 455 |
|
---|
| 456 | if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
|
---|
| 457 | if((val > 0) && (val<32)) {
|
---|
| 458 | mdaynum = val;
|
---|
| 459 | found = TRUE;
|
---|
| 460 | }
|
---|
| 461 | dignext = DATE_YEAR;
|
---|
| 462 | }
|
---|
| 463 |
|
---|
| 464 | if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
|
---|
| 465 | yearnum = val;
|
---|
| 466 | found = TRUE;
|
---|
| 467 | if(yearnum < 1900) {
|
---|
| 468 | if(yearnum > 70)
|
---|
| 469 | yearnum += 1900;
|
---|
| 470 | else
|
---|
| 471 | yearnum += 2000;
|
---|
| 472 | }
|
---|
| 473 | if(mdaynum == -1)
|
---|
| 474 | dignext = DATE_MDAY;
|
---|
| 475 | }
|
---|
| 476 |
|
---|
| 477 | if(!found)
|
---|
| 478 | return PARSEDATE_FAIL;
|
---|
| 479 |
|
---|
| 480 | date = end;
|
---|
| 481 | }
|
---|
| 482 | }
|
---|
| 483 |
|
---|
| 484 | part++;
|
---|
| 485 | }
|
---|
| 486 |
|
---|
| 487 | if(-1 == secnum)
|
---|
| 488 | secnum = minnum = hournum = 0; /* no time, make it zero */
|
---|
| 489 |
|
---|
| 490 | if((-1 == mdaynum) ||
|
---|
| 491 | (-1 == monnum) ||
|
---|
| 492 | (-1 == yearnum))
|
---|
| 493 | /* lacks vital info, fail */
|
---|
| 494 | return PARSEDATE_FAIL;
|
---|
| 495 |
|
---|
| 496 | #if SIZEOF_TIME_T < 5
|
---|
| 497 | /* 32 bit time_t can only hold dates to the beginning of 2038 */
|
---|
| 498 | if(yearnum > 2037) {
|
---|
| 499 | *output = 0x7fffffff;
|
---|
| 500 | return PARSEDATE_LATER;
|
---|
| 501 | }
|
---|
| 502 | #endif
|
---|
| 503 |
|
---|
| 504 | if(yearnum < 1970) {
|
---|
| 505 | *output = 0;
|
---|
| 506 | return PARSEDATE_SOONER;
|
---|
| 507 | }
|
---|
| 508 |
|
---|
| 509 | if((mdaynum > 31) || (monnum > 11) ||
|
---|
| 510 | (hournum > 23) || (minnum > 59) || (secnum > 60))
|
---|
| 511 | return PARSEDATE_FAIL; /* clearly an illegal date */
|
---|
| 512 |
|
---|
| 513 | tm.tm_sec = secnum;
|
---|
| 514 | tm.tm_min = minnum;
|
---|
| 515 | tm.tm_hour = hournum;
|
---|
| 516 | tm.tm_mday = mdaynum;
|
---|
| 517 | tm.tm_mon = monnum;
|
---|
| 518 | tm.tm_year = yearnum - 1900;
|
---|
| 519 |
|
---|
| 520 | /* my_timegm() returns a time_t. time_t is often 32 bits, even on many
|
---|
| 521 | architectures that feature 64 bit 'long'.
|
---|
| 522 |
|
---|
| 523 | Some systems have 64 bit time_t and deal with years beyond 2038. However,
|
---|
| 524 | even on some of the systems with 64 bit time_t mktime() returns -1 for
|
---|
| 525 | dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
|
---|
| 526 | */
|
---|
| 527 | t = my_timegm(&tm);
|
---|
| 528 |
|
---|
| 529 | /* time zone adjust (cast t to int to compare to negative one) */
|
---|
| 530 | if(-1 != (int)t) {
|
---|
| 531 |
|
---|
| 532 | /* Add the time zone diff between local time zone and GMT. */
|
---|
| 533 | long delta = (long)(tzoff!=-1?tzoff:0);
|
---|
| 534 |
|
---|
| 535 | if((delta>0) && (t > LONG_MAX - delta)) {
|
---|
| 536 | *output = 0x7fffffff;
|
---|
| 537 | return PARSEDATE_LATER; /* time_t overflow */
|
---|
| 538 | }
|
---|
| 539 |
|
---|
| 540 | t += delta;
|
---|
| 541 | }
|
---|
| 542 |
|
---|
| 543 | *output = t;
|
---|
| 544 |
|
---|
| 545 | return PARSEDATE_OK;
|
---|
| 546 | }
|
---|
| 547 |
|
---|
| 548 | time_t curl_getdate(const char *p, const time_t *now)
|
---|
| 549 | {
|
---|
| 550 | time_t parsed = -1;
|
---|
| 551 | int rc = parsedate(p, &parsed);
|
---|
| 552 | (void)now; /* legacy argument from the past that we ignore */
|
---|
| 553 |
|
---|
| 554 | switch(rc) {
|
---|
| 555 | case PARSEDATE_OK:
|
---|
| 556 | case PARSEDATE_LATER:
|
---|
| 557 | case PARSEDATE_SOONER:
|
---|
| 558 | return parsed;
|
---|
| 559 | }
|
---|
| 560 | /* everything else is fail */
|
---|
| 561 | return -1;
|
---|
| 562 | }
|
---|
| 563 |
|
---|
| 564 | /*
|
---|
| 565 | * Curl_gmtime() is a gmtime() replacement for portability. Do not use the
|
---|
| 566 | * gmtime_r() or gmtime() functions anywhere else but here.
|
---|
| 567 | *
|
---|
| 568 | */
|
---|
| 569 |
|
---|
| 570 | CURLcode Curl_gmtime(time_t intime, struct tm *store)
|
---|
| 571 | {
|
---|
| 572 | const struct tm *tm;
|
---|
| 573 | #ifdef HAVE_GMTIME_R
|
---|
| 574 | /* thread-safe version */
|
---|
| 575 | tm = (struct tm *)gmtime_r(&intime, store);
|
---|
| 576 | #else
|
---|
| 577 | tm = gmtime(&intime);
|
---|
| 578 | if(tm)
|
---|
| 579 | *store = *tm; /* copy the pointed struct to the local copy */
|
---|
| 580 | #endif
|
---|
| 581 |
|
---|
| 582 | if(!tm)
|
---|
| 583 | return CURLE_BAD_FUNCTION_ARGUMENT;
|
---|
| 584 | return CURLE_OK;
|
---|
| 585 | }
|
---|