1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 /* 11 * nxt_time_parse() parses a time string given in RFC822, RFC850, or ISOC 12 * formats and returns nxt_time_t value >= 0 on success or -1 on failure. 13 */ 14 15 nxt_time_t 16 nxt_time_parse(const u_char *p, size_t len) 17 { 18 size_t n; 19 u_char c; 20 uint64_t s; 21 nxt_int_t yr, month, day, hour, min, sec; 22 nxt_uint_t year, days; 23 const u_char *end; 24 25 static nxt_int_t mday[12] = { 26 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 27 }; 28 29 enum { 30 RFC822 = 0, /* "Mon, 28 Sep 1970 12:00:00" */ 31 RFC850, /* "Monday, 28-Sep-70 12:00:00" */ 32 ISOC, /* "Mon Sep 28 12:00:00 1970" */ 33 } fmt; 34 35 fmt = RFC822; 36 end = p + len; 37 38 while (p < end) { 39 c = *p++; 40 41 if (c == ',') { 42 break; 43 } 44 45 if (c == ' ') { 46 fmt = ISOC; 47 break; 48 } 49 } 50 51 while (p < end) { 52 if (*p != ' ') { 53 break; 54 } 55 56 p++; 57 } 58 59 if (nxt_slow_path(p + 18 > end)) { 60 /* Lesser than RFC850 "28-Sep-70 12:00:00" length. */ 61 return -1; 62 } 63 64 day = 0; 65 66 if (fmt != ISOC) { 67 day = nxt_int_parse(p, 2); 68 if (nxt_slow_path(day <= 0)) { 69 return -1; 70 } 71 p += 2; 72 73 if (*p == ' ') { 74 if (nxt_slow_path(p + 18 > end)) { 75 /* Lesser than RFC822 " Sep 1970 12:00:00" length. */ 76 return -1; 77 } 78 79 /* RFC822 */ 80 81 } else if (*p == '-') { 82 fmt = RFC850; 83 84 } else { 85 return -1; 86 } 87 88 p++; 89 } 90 91 switch (*p) { 92 93 case 'J': 94 month = p[1] == 'a' ? 0 : p[2] == 'n' ? 5 : 6; 95 break; 96 97 case 'F': 98 month = 1; 99 break; 100 101 case 'M': 102 month = p[2] == 'r' ? 2 : 4; 103 break; 104 105 case 'A': 106 month = p[1] == 'p' ? 3 : 7; 107 break; 108 109 case 'S': 110 month = 8; 111 break; 112 113 case 'O': 114 month = 9; 115 break; 116 117 case 'N': 118 month = 10; 119 break; 120 121 case 'D': 122 month = 11; 123 break; 124 125 default: 126 return -1; 127 } 128 129 p += 3; 130 yr = 0; 131 132 switch (fmt) { 133 134 case RFC822: 135 if (nxt_slow_path(*p++ != ' ')) { 136 return -1; 137 } 138 139 yr = nxt_int_parse(p, 4); 140 if (nxt_slow_path(yr <= 0)) { 141 return -1; 142 } 143 p += 4; 144 145 break; 146 147 case RFC850: 148 if (nxt_slow_path(*p++ != '-')) { 149 return -1; 150 } 151 152 yr = nxt_int_parse(p, 2); 153 if (nxt_slow_path(yr <= 0)) { 154 return -1; 155 } 156 p += 2; 157 158 yr += (yr < 70) ? 2000 : 1900; 159 160 break; 161 162 default: /* ISOC */ 163 if (nxt_slow_path(*p++ != ' ')) { 164 return -1; 165 } 166 167 if (p[0] != ' ') { 168 n = 2; 169 170 if (p[1] == ' ') { 171 n = 1; 172 } 173 174 } else { 175 p++; 176 n = 1; 177 } 178 179 day = nxt_int_parse(p, n); 180 if (nxt_slow_path(day <= 0)) { 181 return -1; 182 } 183 p += n; 184 185 if (nxt_slow_path(p + 14 > end)) { 186 /* Lesser than ISOC " 12:00:00 1970" length. */ 187 return -1; 188 } 189 190 break; 191 } 192 193 if (nxt_slow_path(*p++ != ' ')) { 194 return -1; 195 } 196 197 hour = nxt_int_parse(p, 2); 198 if (nxt_slow_path(hour < 0)) { 199 return -1; 200 } 201 p += 2; 202 203 if (nxt_slow_path(*p++ != ':')) { 204 return -1; 205 } 206 207 min = nxt_int_parse(p, 2); 208 if (nxt_slow_path(min < 0)) { 209 return -1; 210 } 211 p += 2; 212 213 if (nxt_slow_path(*p++ != ':')) { 214 return -1; 215 } 216 217 sec = nxt_int_parse(p, 2); 218 if (nxt_slow_path(sec < 0)) { 219 return -1; 220 } 221 222 if (fmt == ISOC) { 223 p += 2; 224 225 if (nxt_slow_path(*p++ != ' ')) { 226 return -1; 227 } 228 229 yr = nxt_int_parse(p, 4); 230 if (nxt_slow_path(yr < 0)) { 231 return -1; 232 } 233 } 234 235 if (nxt_slow_path(hour > 23 || min > 59 || sec > 59)) { 236 return -1; 237 } 238 239 year = yr; 240 241 if (day == 29 && month == 1) { 242 243 if (nxt_slow_path((year & 3) != 0)) { 244 /* Not a leap year. */ 245 return -1; 246 } 247 248 if (nxt_slow_path((year % 100 == 0) && (year % 400) != 0)) { 249 /* Not a leap year. */ 250 return -1; 251 } 252 253 } else if (nxt_slow_path(day > mday[(nxt_uint_t) month])) { 254 return -1; 255 } 256 257 /* 258 * Shift new year to March 1 and start months 259 * from 1 (not 0), as required for Gauss' formula. 260 */ 261 262 if (--month <= 0) { 263 month += 12; 264 year -= 1; 265 } 266 267 /* Gauss' formula for Gregorian days since March 1, 1 BCE. */ 268 269 /* Days in years including leap years since March 1, 1 BCE. */ 270 days = 365 * year + year / 4 - year / 100 + year / 400 271 272 /* Days before the month. */ 273 + 367 * (nxt_uint_t) month / 12 - 30 274 275 /* Days before the day. */ 276 + (nxt_uint_t) day - 1; 277 278 /* 279 * 719527 days were between March 1, 1 BCE and March 1, 1970, 280 * 31 and 28 days were in January and February 1970. 281 */ 282 days = days - 719527 + 31 + 28; 283 284 s = (uint64_t) days * 86400 285 + (nxt_uint_t) hour * 3600 286 + (nxt_uint_t) min * 60 287 + (nxt_uint_t) sec; 288 289 #if (NXT_TIME_T_SIZE <= 4) 290 291 /* Y2038 */ 292 293 if (nxt_slow_path(s > 0x7fffffff)) { 294 return -1; 295 } 296 297 #endif 298 299 return (nxt_time_t) s; 300 } 301 302 303 /* 304 * nxt_term_parse() parses term string given in format "200", "10m", 305 * or "1d 1h" and returns nxt_int_t value >= 0 on success, -1 on failure, 306 * and -2 on overflow. The maximum valid value is 2^31 - 1 or about 307 * 68 years in seconds or about 24 days in milliseconds. 308 */ 309 310 nxt_int_t 311 nxt_term_parse(const u_char *p, size_t len, nxt_bool_t seconds) 312 { 313 u_char c, ch; 314 nxt_uint_t val, term, scale, max; 315 const u_char *end; 316 317 enum { 318 st_first_digit = 0, 319 st_digit, 320 st_letter, 321 st_space, 322 } state; 323 324 enum { 325 st_start = 0, 326 st_year, 327 st_month, 328 st_week, 329 st_day, 330 st_hour, 331 st_min, 332 st_sec, 333 st_msec, 334 st_last, 335 } step; 336 337 val = 0; 338 term = 0; 339 state = st_first_digit; 340 step = seconds ? st_start : st_month; 341 342 end = p + len; 343 344 while (p < end) { 345 346 ch = *p++; 347 348 if (state == st_space) { 349 350 if (ch == ' ') { 351 continue; 352 } 353 354 state = st_first_digit; 355 } 356 357 if (state != st_letter) { 358 359 /* Values below '0' become >= 208. */ 360 c = ch - '0'; 361 362 if (c <= 9) { 363 val = val * 10 + c; 364 state = st_digit; 365 continue; 366 } 367 368 if (state == st_first_digit) { 369 return -1; 370 } 371 372 state = st_letter; 373 } 374 375 switch (ch) { 376 377 case 'y': 378 if (step > st_start) { 379 return -1; 380 } 381 step = st_year; 382 max = NXT_INT32_T_MAX / (365 * 24 * 60 * 60); 383 scale = 365 * 24 * 60 * 60; 384 break; 385 386 case 'M': 387 if (step >= st_month) { 388 return -1; 389 } 390 step = st_month; 391 max = NXT_INT32_T_MAX / (30 * 24 * 60 * 60); 392 scale = 30 * 24 * 60 * 60; 393 break; 394 395 case 'w': 396 if (step >= st_week) { 397 return -1; 398 } 399 step = st_week; 400 max = NXT_INT32_T_MAX / (7 * 24 * 60 * 60); 401 scale = 7 * 24 * 60 * 60; 402 break; 403 404 case 'd': 405 if (step >= st_day) { 406 return -1; 407 } 408 step = st_day; 409 max = NXT_INT32_T_MAX / (24 * 60 * 60); 410 scale = 24 * 60 * 60; 411 break; 412 413 case 'h': 414 if (step >= st_hour) { 415 return -1; 416 } 417 step = st_hour; 418 max = NXT_INT32_T_MAX / (60 * 60); 419 scale = 60 * 60; 420 break; 421 422 case 'm': 423 if (p < end && *p == 's') { 424 if (seconds || step >= st_msec) { 425 return -1; 426 } 427 p++; 428 step = st_msec; 429 max = NXT_INT32_T_MAX; 430 scale = 1; 431 break; 432 } 433 434 if (step >= st_min) { 435 return -1; 436 } 437 step = st_min; 438 max = NXT_INT32_T_MAX / 60; 439 scale = 60; 440 break; 441 442 case 's': 443 if (step >= st_sec) { 444 return -1; 445 } 446 step = st_sec; 447 max = NXT_INT32_T_MAX; 448 scale = 1; 449 break; 450 451 case ' ': 452 if (step >= st_sec) { 453 return -1; 454 } 455 step = st_last; 456 max = NXT_INT32_T_MAX; 457 scale = 1; 458 break; 459 460 default: 461 return -1; 462 } 463 464 if (!seconds && step != st_msec) { 465 scale *= 1000; 466 max /= 1000; 467 } 468 469 if (val > max) { 470 return -2; 471 } 472 473 term += val * scale; 474 475 if (term > NXT_INT32_T_MAX) { 476 return -2; 477 } 478 479 val = 0; 480 481 state = st_space; 482 } 483 484 if (!seconds) { 485 val *= 1000; 486 } 487 488 return term + val; 489 } 490