http-date.c revision 2454dfa32c93c20a8522c6ed42fe057baaac9f9a
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include "lib.h"
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include "str.h"
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include "utc-mktime.h"
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include "http-date.h"
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <ctype.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/* RFC 7231, Section 7.1.1.1: Date/Time Formats
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon The defined syntax is as follows:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon HTTP-date = IMF-fixdate / obs-date
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon Preferred format:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; fixed length/zone/capitalization subset of the format
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; see Section 3.3 of [RFC5322]
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon day-name = %x4D.6F.6E ; "Mon", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x54.75.65 ; "Tue", case-sensitive
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon / %x57.65.64 ; "Wed", case-sensitive
633fc3a6eed35d918db16925b7048d7a2e28064aSebastien Roy / %x54.68.75 ; "Thu", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x46.72.69 ; "Fri", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x53.61.74 ; "Sat", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x53.75.6E ; "Sun", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon date1 = day SP month SP year
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; e.g., 02 Jun 1982
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon day = 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon month = %x4A.61.6E ; "Jan", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x46.65.62 ; "Feb", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x4D.61.72 ; "Mar", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x41.70.72 ; "Apr", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x4D.61.79 ; "May", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x4A.75.6E ; "Jun", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x4A.75.6C ; "Jul", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x41.75.67 ; "Aug", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x53.65.70 ; "Sep", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x4F.63.74 ; "Oct", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x4E.6F.76 ; "Nov", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x44.65.63 ; "Dec", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon year = 4DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon GMT = %x47.4D.54 ; "GMT", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon time-of-day = hour ":" minute ":" second
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; 00:00:00 - 23:59:60 (leap second)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon hour = 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon minute = 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon second = 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon Obsolete formats:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon obs-date = rfc850-date / asctime-date
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon date2 = day "-" month "-" 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; e.g., 02-Jun-82
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon day-name-l = %x4D.6F.6E.64.61.79 ; "Monday", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x54.75.65.73.64.61.79 ; "Tuesday", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x57.65.64.6E.65.73.64.61.79 ; "Wednesday", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x54.68.75.72.73.64.61.79 ; "Thursday", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x46.72.69.64.61.79 ; "Friday", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x53.61.74.75.72.64.61.79 ; "Saturday", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon / %x53.75.6E.64.61.79 ; "Sunday", case-sensitive
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon asctime-date = day-name SP date3 SP time-of-day SP year
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon date3 = month SP ( 2DIGIT / ( SP 1DIGIT ))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; e.g., Jun 2
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic const char *month_names[] = {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "Jan", "Feb", "Mar", "Apr", "May", "Jun",
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon};
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic const char *weekday_names[] = {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon};
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic const char *weekday_names_long[] = {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon};
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstruct http_date_parser {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon const unsigned char *cur, *end;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon struct tm tm;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int timezone_offset;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon};
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic inline int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_sp(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur[0] != ' ')
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic inline int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_number(struct http_date_parser *parser,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int digits, int *number_r)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int i;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *number_r = parser->cur[0] - '0';
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon for (i=0; i < digits-1; i++) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *number_r = ((*number_r) * 10) + parser->cur[0] - '0';
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic inline int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_word(struct http_date_parser *parser,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int maxchars, string_t **word_r)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon string_t *word;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int i;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || !i_isalpha(parser->cur[0]))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon word = t_str_new(maxchars);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon str_append_c(word, parser->cur[0]);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon for (i=0; i < maxchars-1; i++) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || !i_isalpha(parser->cur[0]))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon str_append_c(word, parser->cur[0]);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (i_isalpha(parser->cur[0]))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *word_r = word;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic inline int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_year(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* year = 4DIGIT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 4, &parser->tm.tm_year) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->tm.tm_year < 1900)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->tm.tm_year -= 1900;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic inline int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_month(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon string_t *month;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int i;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_word(parser, 3, &month) <= 0 || str_len(month) != 3)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon for (i = 0; i < 12; i++) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (strcmp(month_names[i], str_c(month)) == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (i >= 12)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->tm.tm_mon = i;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic inline int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_day(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* day = 2DIGIT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 2, &parser->tm.tm_mday) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_time_of_day(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* time-of-day = hour ":" minute ":" second
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; 00:00:00 - 23:59:59
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon hour = 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon minute = 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon second = 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* hour = 2DIGIT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 2, &parser->tm.tm_hour) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* ":" */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || parser->cur[0] != ':')
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* minute = 2DIGIT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 2, &parser->tm.tm_min) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* ":" */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || parser->cur[0] != ':')
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* second = 2DIGIT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 2, &parser->tm.tm_sec) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic inline int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_time_gmt(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon string_t *gmt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Remaining: {...} SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP time-of-day */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_time_of_day(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP GMT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_word(parser, 3, &gmt) <= 0 ||
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon strcmp("GMT", str_c(gmt)) != 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_format_imf_fixdate(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; fixed length/zone/capitalization subset of the format
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; see Section 3.3 of [RFC5322]
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon date1 = day SP month SP year
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; e.g., 02 Jun 1982
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon Remaining: {...} SP day SP month SP year SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP day */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_day(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP month */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_month(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP year */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_year(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP time-of-day SP GMT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return http_date_parse_time_gmt(parser);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_format_rfc850(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon date2 = day "-" month "-" 2DIGIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; day-month-year (e.g., 02-Jun-82)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon Remaining: "," SP day "-" month "-" 2DIGIT SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* "," SP */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || parser->cur[0] != ',')
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* day */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_day(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* "-" */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || parser->cur[0] != '-')
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* month */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_month(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* "-" */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur >= parser->end || parser->cur[0] != '-')
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* 2DIGIT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 2, &parser->tm.tm_year) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->tm.tm_year < 70)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->tm.tm_year += 100;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP time-of-day SP GMT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return http_date_parse_time_gmt(parser);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_format_asctime(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int ret;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon asctime-date = day-name SP date3 SP time-of-day SP year
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon date3 = month SP ( 2DIGIT / ( SP 1DIGIT ))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; month day (e.g., Jun 2)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon Remaining: {...} month SP ( 2DIGIT / ( SP 1DIGIT )) SP time-of-day SP year
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* month */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_month(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP 1DIGIT / 2DIGIT */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((ret=http_date_parse_sp(parser)) < 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (ret == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 2, &parser->tm.tm_mday) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_number(parser, 1, &parser->tm.tm_mday) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP time-of-day */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_time_of_day(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* SP year */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_sp(parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return http_date_parse_year(parser);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic int
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonhttp_date_parse_format_any(struct http_date_parser *parser)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon string_t *dayname;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int i;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon HTTP-date = IMF-fixdate / obs-date
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon IMF-fixdate = day-name "," SP date1 SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; fixed length/zone/capitalization subset of the format
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ; see Section 3.3 of [RFC5322]
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon obs-date = rfc850-date / asctime-date
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon rfc850-date = day-name-l "," SP date2 SP time-of-day SP GMT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon asctime-date = day-name SP date3 SP time-of-day SP year
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_word(parser, 9, &dayname) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (str_len(dayname) > 3) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* rfc850-date */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon for (i = 0; i < 7; i++) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (strcmp(weekday_names_long[i], str_c(dayname)) == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (i >= 7)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return http_date_parse_format_rfc850(parser);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* IMF-fixdate / asctime-date */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon for (i = 0; i < 7; i++) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (strcmp(weekday_names[i], str_c(dayname)) == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (i >= 7 || parser->cur >= parser->end)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur[0] == ' ') {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* asctime-date */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return http_date_parse_format_asctime(parser);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser->cur[0] != ',')
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* IMF-fixdate */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser->cur++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return http_date_parse_format_imf_fixdate(parser);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonbool http_date_parse(const unsigned char *data, size_t size,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon time_t *timestamp_r)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon struct http_date_parser parser;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon time_t timestamp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon i_zero(&parser);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser.cur = data;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser.end = data + size;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (http_date_parse_format_any(&parser) <= 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (parser.cur != parser.end)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon parser.tm.tm_isdst = -1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon timestamp = utc_mktime(&parser.tm);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (timestamp == (time_t)-1)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *timestamp_r = timestamp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonbool http_date_parse_tm(const unsigned char *data, size_t size,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon struct tm *tm_r)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon time_t timestamp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon struct tm *tm;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (!http_date_parse(data, size, &timestamp))
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tm = gmtime(&timestamp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *tm_r = *tm;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonconst char *http_date_create_tm(struct tm *tm)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return t_strdup_printf("%s, %02d %s %04d %02d:%02d:%02d GMT",
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon weekday_names[tm->tm_wday],
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tm->tm_mday,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon month_names[tm->tm_mon],
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tm->tm_year+1900,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tm->tm_hour, tm->tm_min, tm->tm_sec);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonconst char *http_date_create(time_t timestamp)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon struct tm *tm;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tm = gmtime(&timestamp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return http_date_create_tm(tm);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon