date.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. 'use strict'
  2. /**
  3. * @see https://www.rfc-editor.org/rfc/rfc9110.html#name-date-time-formats
  4. *
  5. * @param {string} date
  6. * @returns {Date | undefined}
  7. */
  8. function parseHttpDate (date) {
  9. // Sun, 06 Nov 1994 08:49:37 GMT ; IMF-fixdate
  10. // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
  11. // Sunday, 06-Nov-94 08:49:37 GMT ; obsolete RFC 850 format
  12. switch (date[3]) {
  13. case ',': return parseImfDate(date)
  14. case ' ': return parseAscTimeDate(date)
  15. default: return parseRfc850Date(date)
  16. }
  17. }
  18. function makeDate (year, monthIdx, day, hour, minute, second, weekday) {
  19. const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
  20. // Date.UTC treats years 0-99 as 1900-1999. Reset the full year so component
  21. // checks below validate the HTTP date as written.
  22. if (year >= 0 && year <= 99) {
  23. result.setUTCFullYear(year)
  24. }
  25. return result.getUTCFullYear() === year &&
  26. result.getUTCMonth() === monthIdx &&
  27. result.getUTCDate() === day &&
  28. result.getUTCHours() === hour &&
  29. result.getUTCMinutes() === minute &&
  30. result.getUTCSeconds() === second &&
  31. result.getUTCDay() === weekday
  32. ? result
  33. : undefined
  34. }
  35. /**
  36. * @see https://httpwg.org/specs/rfc9110.html#preferred.date.format
  37. *
  38. * @param {string} date
  39. * @returns {Date | undefined}
  40. */
  41. function parseImfDate (date) {
  42. if (
  43. date.length !== 29 ||
  44. date[4] !== ' ' ||
  45. date[7] !== ' ' ||
  46. date[11] !== ' ' ||
  47. date[16] !== ' ' ||
  48. date[19] !== ':' ||
  49. date[22] !== ':' ||
  50. date[25] !== ' ' ||
  51. date[26] !== 'G' ||
  52. date[27] !== 'M' ||
  53. date[28] !== 'T'
  54. ) {
  55. return undefined
  56. }
  57. let weekday = -1
  58. if (date[0] === 'S' && date[1] === 'u' && date[2] === 'n') { // Sunday
  59. weekday = 0
  60. } else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n') { // Monday
  61. weekday = 1
  62. } else if (date[0] === 'T' && date[1] === 'u' && date[2] === 'e') { // Tuesday
  63. weekday = 2
  64. } else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd') { // Wednesday
  65. weekday = 3
  66. } else if (date[0] === 'T' && date[1] === 'h' && date[2] === 'u') { // Thursday
  67. weekday = 4
  68. } else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i') { // Friday
  69. weekday = 5
  70. } else if (date[0] === 'S' && date[1] === 'a' && date[2] === 't') { // Saturday
  71. weekday = 6
  72. } else {
  73. return undefined // Not a valid day of the week
  74. }
  75. let day = 0
  76. if (date[5] === '0') {
  77. // Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
  78. const code = date.charCodeAt(6)
  79. if (code < 49 || code > 57) {
  80. return undefined // Not a digit
  81. }
  82. day = code - 48 // Convert ASCII code to number
  83. } else {
  84. const code1 = date.charCodeAt(5)
  85. if (code1 < 49 || code1 > 51) {
  86. return undefined // Not a digit between 1 and 3
  87. }
  88. const code2 = date.charCodeAt(6)
  89. if (code2 < 48 || code2 > 57) {
  90. return undefined // Not a digit
  91. }
  92. day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  93. }
  94. let monthIdx = -1
  95. if (
  96. (date[8] === 'J' && date[9] === 'a' && date[10] === 'n')
  97. ) {
  98. monthIdx = 0 // Jan
  99. } else if (
  100. (date[8] === 'F' && date[9] === 'e' && date[10] === 'b')
  101. ) {
  102. monthIdx = 1 // Feb
  103. } else if (
  104. (date[8] === 'M' && date[9] === 'a')
  105. ) {
  106. if (date[10] === 'r') {
  107. monthIdx = 2 // Mar
  108. } else if (date[10] === 'y') {
  109. monthIdx = 4 // May
  110. } else {
  111. return undefined // Invalid month
  112. }
  113. } else if (
  114. (date[8] === 'J')
  115. ) {
  116. if (date[9] === 'a' && date[10] === 'n') {
  117. monthIdx = 0 // Jan
  118. } else if (date[9] === 'u') {
  119. if (date[10] === 'n') {
  120. monthIdx = 5 // Jun
  121. } else if (date[10] === 'l') {
  122. monthIdx = 6 // Jul
  123. } else {
  124. return undefined // Invalid month
  125. }
  126. } else {
  127. return undefined // Invalid month
  128. }
  129. } else if (
  130. (date[8] === 'A')
  131. ) {
  132. if (date[9] === 'p' && date[10] === 'r') {
  133. monthIdx = 3 // Apr
  134. } else if (date[9] === 'u' && date[10] === 'g') {
  135. monthIdx = 7 // Aug
  136. } else {
  137. return undefined // Invalid month
  138. }
  139. } else if (
  140. (date[8] === 'S' && date[9] === 'e' && date[10] === 'p')
  141. ) {
  142. monthIdx = 8 // Sep
  143. } else if (
  144. (date[8] === 'O' && date[9] === 'c' && date[10] === 't')
  145. ) {
  146. monthIdx = 9 // Oct
  147. } else if (
  148. (date[8] === 'N' && date[9] === 'o' && date[10] === 'v')
  149. ) {
  150. monthIdx = 10 // Nov
  151. } else if (
  152. (date[8] === 'D' && date[9] === 'e' && date[10] === 'c')
  153. ) {
  154. monthIdx = 11 // Dec
  155. } else {
  156. // Not a valid month
  157. return undefined
  158. }
  159. const yearDigit1 = date.charCodeAt(12)
  160. if (yearDigit1 < 48 || yearDigit1 > 57) {
  161. return undefined // Not a digit
  162. }
  163. const yearDigit2 = date.charCodeAt(13)
  164. if (yearDigit2 < 48 || yearDigit2 > 57) {
  165. return undefined // Not a digit
  166. }
  167. const yearDigit3 = date.charCodeAt(14)
  168. if (yearDigit3 < 48 || yearDigit3 > 57) {
  169. return undefined // Not a digit
  170. }
  171. const yearDigit4 = date.charCodeAt(15)
  172. if (yearDigit4 < 48 || yearDigit4 > 57) {
  173. return undefined // Not a digit
  174. }
  175. const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
  176. let hour = 0
  177. if (date[17] === '0') {
  178. const code = date.charCodeAt(18)
  179. if (code < 48 || code > 57) {
  180. return undefined // Not a digit
  181. }
  182. hour = code - 48 // Convert ASCII code to number
  183. } else {
  184. const code1 = date.charCodeAt(17)
  185. if (code1 < 48 || code1 > 50) {
  186. return undefined // Not a digit between 0 and 2
  187. }
  188. const code2 = date.charCodeAt(18)
  189. if (code2 < 48 || code2 > 57) {
  190. return undefined // Not a digit
  191. }
  192. if (code1 === 50 && code2 > 51) {
  193. return undefined // Hour cannot be greater than 23
  194. }
  195. hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  196. }
  197. let minute = 0
  198. if (date[20] === '0') {
  199. const code = date.charCodeAt(21)
  200. if (code < 48 || code > 57) {
  201. return undefined // Not a digit
  202. }
  203. minute = code - 48 // Convert ASCII code to number
  204. } else {
  205. const code1 = date.charCodeAt(20)
  206. if (code1 < 48 || code1 > 53) {
  207. return undefined // Not a digit between 0 and 5
  208. }
  209. const code2 = date.charCodeAt(21)
  210. if (code2 < 48 || code2 > 57) {
  211. return undefined // Not a digit
  212. }
  213. minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  214. }
  215. let second = 0
  216. if (date[23] === '0') {
  217. const code = date.charCodeAt(24)
  218. if (code < 48 || code > 57) {
  219. return undefined // Not a digit
  220. }
  221. second = code - 48 // Convert ASCII code to number
  222. } else {
  223. const code1 = date.charCodeAt(23)
  224. if (code1 < 48 || code1 > 53) {
  225. return undefined // Not a digit between 0 and 5
  226. }
  227. const code2 = date.charCodeAt(24)
  228. if (code2 < 48 || code2 > 57) {
  229. return undefined // Not a digit
  230. }
  231. second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  232. }
  233. return makeDate(year, monthIdx, day, hour, minute, second, weekday)
  234. }
  235. /**
  236. * @see https://httpwg.org/specs/rfc9110.html#obsolete.date.formats
  237. *
  238. * @param {string} date
  239. * @returns {Date | undefined}
  240. */
  241. function parseAscTimeDate (date) {
  242. // This is assumed to be in UTC
  243. if (
  244. date.length !== 24 ||
  245. date[7] !== ' ' ||
  246. date[10] !== ' ' ||
  247. date[19] !== ' '
  248. ) {
  249. return undefined
  250. }
  251. let weekday = -1
  252. if (date[0] === 'S' && date[1] === 'u' && date[2] === 'n') { // Sunday
  253. weekday = 0
  254. } else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n') { // Monday
  255. weekday = 1
  256. } else if (date[0] === 'T' && date[1] === 'u' && date[2] === 'e') { // Tuesday
  257. weekday = 2
  258. } else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd') { // Wednesday
  259. weekday = 3
  260. } else if (date[0] === 'T' && date[1] === 'h' && date[2] === 'u') { // Thursday
  261. weekday = 4
  262. } else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i') { // Friday
  263. weekday = 5
  264. } else if (date[0] === 'S' && date[1] === 'a' && date[2] === 't') { // Saturday
  265. weekday = 6
  266. } else {
  267. return undefined // Not a valid day of the week
  268. }
  269. let monthIdx = -1
  270. if (
  271. (date[4] === 'J' && date[5] === 'a' && date[6] === 'n')
  272. ) {
  273. monthIdx = 0 // Jan
  274. } else if (
  275. (date[4] === 'F' && date[5] === 'e' && date[6] === 'b')
  276. ) {
  277. monthIdx = 1 // Feb
  278. } else if (
  279. (date[4] === 'M' && date[5] === 'a')
  280. ) {
  281. if (date[6] === 'r') {
  282. monthIdx = 2 // Mar
  283. } else if (date[6] === 'y') {
  284. monthIdx = 4 // May
  285. } else {
  286. return undefined // Invalid month
  287. }
  288. } else if (
  289. (date[4] === 'J')
  290. ) {
  291. if (date[5] === 'a' && date[6] === 'n') {
  292. monthIdx = 0 // Jan
  293. } else if (date[5] === 'u') {
  294. if (date[6] === 'n') {
  295. monthIdx = 5 // Jun
  296. } else if (date[6] === 'l') {
  297. monthIdx = 6 // Jul
  298. } else {
  299. return undefined // Invalid month
  300. }
  301. } else {
  302. return undefined // Invalid month
  303. }
  304. } else if (
  305. (date[4] === 'A')
  306. ) {
  307. if (date[5] === 'p' && date[6] === 'r') {
  308. monthIdx = 3 // Apr
  309. } else if (date[5] === 'u' && date[6] === 'g') {
  310. monthIdx = 7 // Aug
  311. } else {
  312. return undefined // Invalid month
  313. }
  314. } else if (
  315. (date[4] === 'S' && date[5] === 'e' && date[6] === 'p')
  316. ) {
  317. monthIdx = 8 // Sep
  318. } else if (
  319. (date[4] === 'O' && date[5] === 'c' && date[6] === 't')
  320. ) {
  321. monthIdx = 9 // Oct
  322. } else if (
  323. (date[4] === 'N' && date[5] === 'o' && date[6] === 'v')
  324. ) {
  325. monthIdx = 10 // Nov
  326. } else if (
  327. (date[4] === 'D' && date[5] === 'e' && date[6] === 'c')
  328. ) {
  329. monthIdx = 11 // Dec
  330. } else {
  331. // Not a valid month
  332. return undefined
  333. }
  334. let day = 0
  335. if (date[8] === ' ') {
  336. // Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
  337. const code = date.charCodeAt(9)
  338. if (code < 49 || code > 57) {
  339. return undefined // Not a digit
  340. }
  341. day = code - 48 // Convert ASCII code to number
  342. } else {
  343. const code1 = date.charCodeAt(8)
  344. if (code1 < 49 || code1 > 51) {
  345. return undefined // Not a digit between 1 and 3
  346. }
  347. const code2 = date.charCodeAt(9)
  348. if (code2 < 48 || code2 > 57) {
  349. return undefined // Not a digit
  350. }
  351. day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  352. }
  353. let hour = 0
  354. if (date[11] === '0') {
  355. const code = date.charCodeAt(12)
  356. if (code < 48 || code > 57) {
  357. return undefined // Not a digit
  358. }
  359. hour = code - 48 // Convert ASCII code to number
  360. } else {
  361. const code1 = date.charCodeAt(11)
  362. if (code1 < 48 || code1 > 50) {
  363. return undefined // Not a digit between 0 and 2
  364. }
  365. const code2 = date.charCodeAt(12)
  366. if (code2 < 48 || code2 > 57) {
  367. return undefined // Not a digit
  368. }
  369. if (code1 === 50 && code2 > 51) {
  370. return undefined // Hour cannot be greater than 23
  371. }
  372. hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  373. }
  374. let minute = 0
  375. if (date[14] === '0') {
  376. const code = date.charCodeAt(15)
  377. if (code < 48 || code > 57) {
  378. return undefined // Not a digit
  379. }
  380. minute = code - 48 // Convert ASCII code to number
  381. } else {
  382. const code1 = date.charCodeAt(14)
  383. if (code1 < 48 || code1 > 53) {
  384. return undefined // Not a digit between 0 and 5
  385. }
  386. const code2 = date.charCodeAt(15)
  387. if (code2 < 48 || code2 > 57) {
  388. return undefined // Not a digit
  389. }
  390. minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  391. }
  392. let second = 0
  393. if (date[17] === '0') {
  394. const code = date.charCodeAt(18)
  395. if (code < 48 || code > 57) {
  396. return undefined // Not a digit
  397. }
  398. second = code - 48 // Convert ASCII code to number
  399. } else {
  400. const code1 = date.charCodeAt(17)
  401. if (code1 < 48 || code1 > 53) {
  402. return undefined // Not a digit between 0 and 5
  403. }
  404. const code2 = date.charCodeAt(18)
  405. if (code2 < 48 || code2 > 57) {
  406. return undefined // Not a digit
  407. }
  408. second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  409. }
  410. const yearDigit1 = date.charCodeAt(20)
  411. if (yearDigit1 < 48 || yearDigit1 > 57) {
  412. return undefined // Not a digit
  413. }
  414. const yearDigit2 = date.charCodeAt(21)
  415. if (yearDigit2 < 48 || yearDigit2 > 57) {
  416. return undefined // Not a digit
  417. }
  418. const yearDigit3 = date.charCodeAt(22)
  419. if (yearDigit3 < 48 || yearDigit3 > 57) {
  420. return undefined // Not a digit
  421. }
  422. const yearDigit4 = date.charCodeAt(23)
  423. if (yearDigit4 < 48 || yearDigit4 > 57) {
  424. return undefined // Not a digit
  425. }
  426. const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
  427. return makeDate(year, monthIdx, day, hour, minute, second, weekday)
  428. }
  429. /**
  430. * @see https://httpwg.org/specs/rfc9110.html#obsolete.date.formats
  431. *
  432. * @param {string} date
  433. * @returns {Date | undefined}
  434. */
  435. function parseRfc850Date (date) {
  436. let commaIndex = -1
  437. let weekday = -1
  438. if (date[0] === 'S') {
  439. if (date[1] === 'u' && date[2] === 'n' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
  440. weekday = 0 // Sunday
  441. commaIndex = 6
  442. } else if (date[1] === 'a' && date[2] === 't' && date[3] === 'u' && date[4] === 'r' && date[5] === 'd' && date[6] === 'a' && date[7] === 'y') {
  443. weekday = 6 // Saturday
  444. commaIndex = 8
  445. }
  446. } else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
  447. weekday = 1 // Monday
  448. commaIndex = 6
  449. } else if (date[0] === 'T') {
  450. if (date[1] === 'u' && date[2] === 'e' && date[3] === 's' && date[4] === 'd' && date[5] === 'a' && date[6] === 'y') {
  451. weekday = 2 // Tuesday
  452. commaIndex = 7
  453. } else if (date[1] === 'h' && date[2] === 'u' && date[3] === 'r' && date[4] === 's' && date[5] === 'd' && date[6] === 'a' && date[7] === 'y') {
  454. weekday = 4 // Thursday
  455. commaIndex = 8
  456. }
  457. } else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd' && date[3] === 'n' && date[4] === 'e' && date[5] === 's' && date[6] === 'd' && date[7] === 'a' && date[8] === 'y') {
  458. weekday = 3 // Wednesday
  459. commaIndex = 9
  460. } else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
  461. weekday = 5 // Friday
  462. commaIndex = 6
  463. } else {
  464. // Not a valid day name
  465. return undefined
  466. }
  467. if (
  468. date[commaIndex] !== ',' ||
  469. (date.length - commaIndex - 1) !== 23 ||
  470. date[commaIndex + 1] !== ' ' ||
  471. date[commaIndex + 4] !== '-' ||
  472. date[commaIndex + 8] !== '-' ||
  473. date[commaIndex + 11] !== ' ' ||
  474. date[commaIndex + 14] !== ':' ||
  475. date[commaIndex + 17] !== ':' ||
  476. date[commaIndex + 20] !== ' ' ||
  477. date[commaIndex + 21] !== 'G' ||
  478. date[commaIndex + 22] !== 'M' ||
  479. date[commaIndex + 23] !== 'T'
  480. ) {
  481. return undefined
  482. }
  483. let day = 0
  484. if (date[commaIndex + 2] === '0') {
  485. // Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
  486. const code = date.charCodeAt(commaIndex + 3)
  487. if (code < 49 || code > 57) {
  488. return undefined // Not a digit
  489. }
  490. day = code - 48 // Convert ASCII code to number
  491. } else {
  492. const code1 = date.charCodeAt(commaIndex + 2)
  493. if (code1 < 49 || code1 > 51) {
  494. return undefined // Not a digit between 1 and 3
  495. }
  496. const code2 = date.charCodeAt(commaIndex + 3)
  497. if (code2 < 48 || code2 > 57) {
  498. return undefined // Not a digit
  499. }
  500. day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  501. }
  502. let monthIdx = -1
  503. if (
  504. (date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'n')
  505. ) {
  506. monthIdx = 0 // Jan
  507. } else if (
  508. (date[commaIndex + 5] === 'F' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'b')
  509. ) {
  510. monthIdx = 1 // Feb
  511. } else if (
  512. (date[commaIndex + 5] === 'M' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'r')
  513. ) {
  514. monthIdx = 2 // Mar
  515. } else if (
  516. (date[commaIndex + 5] === 'A' && date[commaIndex + 6] === 'p' && date[commaIndex + 7] === 'r')
  517. ) {
  518. monthIdx = 3 // Apr
  519. } else if (
  520. (date[commaIndex + 5] === 'M' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'y')
  521. ) {
  522. monthIdx = 4 // May
  523. } else if (
  524. (date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'n')
  525. ) {
  526. monthIdx = 5 // Jun
  527. } else if (
  528. (date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'l')
  529. ) {
  530. monthIdx = 6 // Jul
  531. } else if (
  532. (date[commaIndex + 5] === 'A' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'g')
  533. ) {
  534. monthIdx = 7 // Aug
  535. } else if (
  536. (date[commaIndex + 5] === 'S' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'p')
  537. ) {
  538. monthIdx = 8 // Sep
  539. } else if (
  540. (date[commaIndex + 5] === 'O' && date[commaIndex + 6] === 'c' && date[commaIndex + 7] === 't')
  541. ) {
  542. monthIdx = 9 // Oct
  543. } else if (
  544. (date[commaIndex + 5] === 'N' && date[commaIndex + 6] === 'o' && date[commaIndex + 7] === 'v')
  545. ) {
  546. monthIdx = 10 // Nov
  547. } else if (
  548. (date[commaIndex + 5] === 'D' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'c')
  549. ) {
  550. monthIdx = 11 // Dec
  551. } else {
  552. // Not a valid month
  553. return undefined
  554. }
  555. const yearDigit1 = date.charCodeAt(commaIndex + 9)
  556. if (yearDigit1 < 48 || yearDigit1 > 57) {
  557. return undefined // Not a digit
  558. }
  559. const yearDigit2 = date.charCodeAt(commaIndex + 10)
  560. if (yearDigit2 < 48 || yearDigit2 > 57) {
  561. return undefined // Not a digit
  562. }
  563. let year = (yearDigit1 - 48) * 10 + (yearDigit2 - 48) // Convert ASCII codes to number
  564. // RFC 6265 states that the year is in the range 1970-2069.
  565. // @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.1
  566. //
  567. // 3. If the year-value is greater than or equal to 70 and less than or
  568. // equal to 99, increment the year-value by 1900.
  569. // 4. If the year-value is greater than or equal to 0 and less than or
  570. // equal to 69, increment the year-value by 2000.
  571. year += year < 70 ? 2000 : 1900
  572. let hour = 0
  573. if (date[commaIndex + 12] === '0') {
  574. const code = date.charCodeAt(commaIndex + 13)
  575. if (code < 48 || code > 57) {
  576. return undefined // Not a digit
  577. }
  578. hour = code - 48 // Convert ASCII code to number
  579. } else {
  580. const code1 = date.charCodeAt(commaIndex + 12)
  581. if (code1 < 48 || code1 > 50) {
  582. return undefined // Not a digit between 0 and 2
  583. }
  584. const code2 = date.charCodeAt(commaIndex + 13)
  585. if (code2 < 48 || code2 > 57) {
  586. return undefined // Not a digit
  587. }
  588. if (code1 === 50 && code2 > 51) {
  589. return undefined // Hour cannot be greater than 23
  590. }
  591. hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  592. }
  593. let minute = 0
  594. if (date[commaIndex + 15] === '0') {
  595. const code = date.charCodeAt(commaIndex + 16)
  596. if (code < 48 || code > 57) {
  597. return undefined // Not a digit
  598. }
  599. minute = code - 48 // Convert ASCII code to number
  600. } else {
  601. const code1 = date.charCodeAt(commaIndex + 15)
  602. if (code1 < 48 || code1 > 53) {
  603. return undefined // Not a digit between 0 and 5
  604. }
  605. const code2 = date.charCodeAt(commaIndex + 16)
  606. if (code2 < 48 || code2 > 57) {
  607. return undefined // Not a digit
  608. }
  609. minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  610. }
  611. let second = 0
  612. if (date[commaIndex + 18] === '0') {
  613. const code = date.charCodeAt(commaIndex + 19)
  614. if (code < 48 || code > 57) {
  615. return undefined // Not a digit
  616. }
  617. second = code - 48 // Convert ASCII code to number
  618. } else {
  619. const code1 = date.charCodeAt(commaIndex + 18)
  620. if (code1 < 48 || code1 > 53) {
  621. return undefined // Not a digit between 0 and 5
  622. }
  623. const code2 = date.charCodeAt(commaIndex + 19)
  624. if (code2 < 48 || code2 > 57) {
  625. return undefined // Not a digit
  626. }
  627. second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  628. }
  629. return makeDate(year, monthIdx, day, hour, minute, second, weekday)
  630. }
  631. module.exports = {
  632. parseHttpDate
  633. }