bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch/* RFC 7231, Section 7.1.1.1: Date/Time Formats
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch The defined syntax is as follows:
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch HTTP-date = IMF-fixdate / obs-date
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch Preferred format:
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; fixed length/zone/capitalization subset of the format
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; see Section 3.3 of [RFC5322]
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch day-name = %x4D.6F.6E ; "Mon", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x54.75.65 ; "Tue", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x57.65.64 ; "Wed", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x54.68.75 ; "Thu", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x46.72.69 ; "Fri", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x53.61.74 ; "Sat", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x53.75.6E ; "Sun", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch date1 = day SP month SP year
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; e.g., 02 Jun 1982
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch month = %x4A.61.6E ; "Jan", case-sensitive
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch / %x46.65.62 ; "Feb", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x4D.61.72 ; "Mar", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x41.70.72 ; "Apr", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x4D.61.79 ; "May", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x4A.75.6E ; "Jun", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x4A.75.6C ; "Jul", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x41.75.67 ; "Aug", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x53.65.70 ; "Sep", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x4F.63.74 ; "Oct", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x4E.6F.76 ; "Nov", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x44.65.63 ; "Dec", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch year = 4DIGIT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch GMT = %x47.4D.54 ; "GMT", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch time-of-day = hour ":" minute ":" second
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; 00:00:00 - 23:59:60 (leap second)
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch hour = 2DIGIT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch minute = 2DIGIT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch second = 2DIGIT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch Obsolete formats:
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch obs-date = rfc850-date / asctime-date
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch date2 = day "-" month "-" 2DIGIT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; e.g., 02-Jun-82
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch day-name-l = %x4D.6F.6E.64.61.79 ; "Monday", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x54.75.65.73.64.61.79 ; "Tuesday", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x57.65.64.6E.65.73.64.61.79 ; "Wednesday", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x54.68.75.72.73.64.61.79 ; "Thursday", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x46.72.69.64.61.79 ; "Friday", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x53.61.74.75.72.64.61.79 ; "Saturday", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch / %x53.75.6E.64.61.79 ; "Sunday", case-sensitive
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch asctime-date = day-name SP date3 SP time-of-day SP year
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch date3 = month SP ( 2DIGIT / ( SP 1DIGIT ))
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; e.g., Jun 2
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic inline int
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_sp(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic inline int
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_number(struct http_date_parser *parser,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch *number_r = ((*number_r) * 10) + parser->cur[0] - '0';
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic inline int
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_word(struct http_date_parser *parser,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || !i_isalpha(parser->cur[0]))
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || !i_isalpha(parser->cur[0]))
76b50cc56df43d114f2363ec3066cf4a807eca49Stephan Bosch if (parser->cur < parser->end && i_isalpha(parser->cur[0]))
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic inline int
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_year(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* year = 4DIGIT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 4, &parser->tm.tm_year) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic inline int
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_month(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_word(parser, 3, &month) <= 0 || str_len(month) != 3)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch for (i = 0; i < 12; i++) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (strcmp(month_names[i], str_c(month)) == 0) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic inline int
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_day(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* day = 2DIGIT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 2, &parser->tm.tm_mday) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_time_of_day(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* time-of-day = hour ":" minute ":" second
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ; 00:00:00 - 23:59:59
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch hour = 2DIGIT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch minute = 2DIGIT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch second = 2DIGIT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* hour = 2DIGIT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 2, &parser->tm.tm_hour) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || parser->cur[0] != ':')
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* minute = 2DIGIT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 2, &parser->tm.tm_min) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || parser->cur[0] != ':')
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* second = 2DIGIT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 2, &parser->tm.tm_sec) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic inline int
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_time_gmt(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* Remaining: {...} SP time-of-day SP GMT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP time-of-day */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_word(parser, 3, &gmt) <= 0 ||
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Boschhttp_date_parse_format_imf_fixdate(struct http_date_parser *parser)
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; fixed length/zone/capitalization subset of the format
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; see Section 3.3 of [RFC5322]
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch date1 = day SP month SP year
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; e.g., 02 Jun 1982
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch Remaining: {...} SP day SP month SP year SP time-of-day SP GMT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP month */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP year */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP time-of-day SP GMT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_format_rfc850(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch date2 = day "-" month "-" 2DIGIT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ; day-month-year (e.g., 02-Jun-82)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch Remaining: "," SP day "-" month "-" 2DIGIT SP time-of-day SP GMT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || parser->cur[0] != ',')
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || parser->cur[0] != '-')
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (parser->cur >= parser->end || parser->cur[0] != '-')
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 2, &parser->tm.tm_year) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP time-of-day SP GMT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_format_asctime(struct http_date_parser *parser)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch asctime-date = day-name SP date3 SP time-of-day SP year
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch date3 = month SP ( 2DIGIT / ( SP 1DIGIT ))
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ; month day (e.g., Jun 2)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch Remaining: {...} month SP ( 2DIGIT / ( SP 1DIGIT )) SP time-of-day SP year
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP 1DIGIT / 2DIGIT */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 2, &parser->tm.tm_mday) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_number(parser, 1, &parser->tm.tm_mday) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP time-of-day */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* SP year */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschhttp_date_parse_format_any(struct http_date_parser *parser)
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch HTTP-date = IMF-fixdate / obs-date
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; fixed length/zone/capitalization subset of the format
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch ; see Section 3.3 of [RFC5322]
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch obs-date = rfc850-date / asctime-date
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch asctime-date = day-name SP date3 SP time-of-day SP year
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (http_date_parse_word(parser, 9, &dayname) <= 0)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* rfc850-date */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch for (i = 0; i < 7; i++) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (strcmp(weekday_names_long[i], str_c(dayname)) == 0) {
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* IMF-fixdate / asctime-date */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch for (i = 0; i < 7; i++) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (strcmp(weekday_names[i], str_c(dayname)) == 0) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* asctime-date */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch return http_date_parse_format_asctime(parser);
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch /* IMF-fixdate */
6ee9ce5ed955a1283dc22ad28980bf9cc23d4c4eStephan Bosch return http_date_parse_format_imf_fixdate(parser);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschbool http_date_parse(const unsigned char *data, size_t size,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschbool http_date_parse_tm(const unsigned char *data, size_t size,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch return t_strdup_printf("%s, %02d %s %04d %02d:%02d:%02d GMT",