xref: /plan9/sys/src/libhttpd/date.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
1 #include <u.h>
2 #include <libc.h>
3 #include <httpd.h>
4 
5 /*
6  * print dates in the format
7  * Wkd, DD Mon YYYY HH:MM:SS GMT
8  * parse dates of formats
9  * Wkd, DD Mon YYYY HH:MM:SS GMT
10  * Weekday, DD-Mon-YY HH:MM:SS GMT
11  * Wkd Mon ( D|DD) HH:MM:SS YYYY
12  * plus anything similar
13  */
14 static char *
15 weekdayname[7] =
16 {
17 	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
18 };
19 static char *
20 wdayname[7] =
21 {
22 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
23 };
24 
25 static char *
26 monname[12] =
27 {
28 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
29 };
30 
31 static	int	dateindex(char*, char**, int);
32 
33 static int
dtolower(int c)34 dtolower(int c)
35 {
36 	if(c >= 'A' && c <= 'Z')
37 		return c - 'A' + 'a';
38 	return c;
39 }
40 
41 static int
disalpha(int c)42 disalpha(int c)
43 {
44 	return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
45 }
46 
47 static int
disdig(int c)48 disdig(int c)
49 {
50 	return c >= '0' && c <= '9';
51 }
52 
53 int
hdatefmt(Fmt * f)54 hdatefmt(Fmt *f)
55 {
56 	Tm *tm;
57 	ulong t;
58 
59 	t = va_arg(f->args, ulong);
60 	tm = gmtime(t);
61 	return fmtprint(f, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
62 		wdayname[tm->wday], tm->mday, monname[tm->mon], tm->year+1900,
63 		tm->hour, tm->min, tm->sec);
64 }
65 
66 static char*
dateword(char * date,char * buf)67 dateword(char *date, char *buf)
68 {
69 	char *p;
70 	int c;
71 
72 	p = buf;
73 	while(!disalpha(c = *date) && !disdig(c) && c)
74 		date++;
75 	while(disalpha(c = *date)){
76 		if(p - buf < 30)
77 			*p++ = dtolower(c);
78 		date++;
79 	}
80 	*p = 0;
81 	return date;
82 }
83 
84 static int
datenum(char ** d)85 datenum(char **d)
86 {
87 	char *date;
88 	int c, n;
89 
90 	date = *d;
91 	while(!disdig(c = *date) && c)
92 		date++;
93 	if(c == 0){
94 		*d = date;
95 		return -1;
96 	}
97 	n = 0;
98 	while(disdig(c = *date)){
99 		n = n * 10 + c - '0';
100 		date++;
101 	}
102 	*d = date;
103 	return n;
104 }
105 
106 /*
107  * parse a date and return the seconds since the epoch
108  * return 0 for a failure
109  */
110 ulong
hdate2sec(char * date)111 hdate2sec(char *date)
112 {
113 	Tm tm;
114 	char buf[32];
115 
116 	/*
117 	 * Weekday|Wday
118 	 */
119 	date = dateword(date, buf);
120 	tm.wday = dateindex(buf, wdayname, 7);
121 	if(tm.wday < 0)
122 		tm.wday = dateindex(buf, weekdayname, 7);
123 	if(tm.wday < 0)
124 		return 0;
125 
126 	/*
127 	 * check for the two major formats
128 	 */
129 	date = dateword(date, buf);
130 	tm.mon = dateindex(buf, monname, 12);
131 	if(tm.mon >= 0){
132 		/*
133 		 * MM
134 		 */
135 		tm.mday = datenum(&date);
136 		if(tm.mday < 1 || tm.mday > 31)
137 			return 0;
138 
139 		/*
140 		 * HH:MM:SS
141 		 */
142 		tm.hour = datenum(&date);
143 		if(tm.hour < 0 || tm.hour >= 24)
144 			return 0;
145 		tm.min = datenum(&date);
146 		if(tm.min < 0 || tm.min >= 60)
147 			return 0;
148 		tm.sec = datenum(&date);
149 		if(tm.sec < 0 || tm.sec >= 60)
150 			return 0;
151 
152 		/*
153 		 * YYYY
154 		 */
155 		tm.year = datenum(&date);
156 		if(tm.year < 70 || tm.year > 99 && tm.year < 1970)
157 			return 0;
158 		if(tm.year >= 1970)
159 			tm.year -= 1900;
160 	}else{
161 		/*
162 		 * MM-Mon-(YY|YYYY)
163 		 */
164 		tm.mday = datenum(&date);
165 		if(tm.mday < 1 || tm.mday > 31)
166 			return 0;
167 		date = dateword(date, buf);
168 		tm.mon = dateindex(buf, monname, 12);
169 		if(tm.mon < 0 || tm.mon >= 12)
170 			return 0;
171 		tm.year = datenum(&date);
172 		if(tm.year < 70 || tm.year > 99 && tm.year < 1970)
173 			return 0;
174 		if(tm.year >= 1970)
175 			tm.year -= 1900;
176 
177 		/*
178 		 * HH:MM:SS
179 		 */
180 		tm.hour = datenum(&date);
181 		if(tm.hour < 0 || tm.hour >= 24)
182 			return 0;
183 		tm.min = datenum(&date);
184 		if(tm.min < 0 || tm.min >= 60)
185 			return 0;
186 		tm.sec = datenum(&date);
187 		if(tm.sec < 0 || tm.sec >= 60)
188 			return 0;
189 
190 		/*
191 		 * timezone
192 		 */
193 		dateword(date, buf);
194 		if(strncmp(buf, "gmt", 3) != 0)
195 			return 0;
196 	}
197 
198 	strcpy(tm.zone, "GMT");
199 	tm.tzoff = 0;
200 	tm.yday = 0;
201 	return tm2sec(&tm);
202 }
203 
204 static int
dateindex(char * d,char ** tab,int n)205 dateindex(char *d, char **tab, int n)
206 {
207 	int i;
208 
209 	for(i = 0; i < n; i++)
210 		if(cistrcmp(d, tab[i]) == 0)
211 			return i;
212 	return -1;
213 }
214