From 4310d82385d83bde50cbece5d1fc798612535778 Mon Sep 17 00:00:00 2001
From: ijammy <mzhang@yottaa.com>
Date: Wed, 6 Jun 2012 15:07:54 +0800
Subject: [PATCH] fix timezone process

---
 lib/libvarnish/time.c |  151 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 148 insertions(+), 3 deletions(-)

diff --git a/lib/libvarnish/time.c b/lib/libvarnish/time.c
index 8242853..654c0d7 100644
--- a/lib/libvarnish/time.c
+++ b/lib/libvarnish/time.c
@@ -53,6 +53,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <math.h>
+#include <ctype.h>
 
 #include "libvarnish.h"
 
@@ -109,23 +110,158 @@ TIM_format(double t, char *p)
 
 /* XXX: add statistics ? */
 static const char *fmts[] = {
-	"%a, %d %b %Y %T GMT",	/* RFC 822 & RFC 1123 */
-	"%A, %d-%b-%y %T GMT",	/* RFC 850 */
+	"%a, %d %b %Y %T",	/* RFC 822 & RFC 1123 */
+	"%A, %d-%b-%y %T",	/* RFC 850 */
 	"%a %b %d %T %Y",	/* ANSI-C asctime() */
 	"%F %T",		/* ISO 8601 */
 	NULL
 };
 
+
+/*
+ * NOTES:
+ * Seems that the libc function strptime was totally broken against %z, %Z.
+ * Let's transfer this kind like timezone by ourselves......
+ */
+typedef struct {
+	const char *timezone;
+	int        delta_hours; /* hour delta */
+} timezone_delta;
+
+#define TIMEZONE_DELTA(tz,delta)	   \
+	{				   \
+		.timezone = tz,		   \
+		.delta_hours = delta	   \
+	}				   
+
+static const timezone_delta tz_delta[] = {
+	TIMEZONE_DELTA("UT" , 0),
+	TIMEZONE_DELTA("GMT", 0),
+	TIMEZONE_DELTA("EST",-5),
+	TIMEZONE_DELTA("EDT",-4),
+	TIMEZONE_DELTA("CST",-6),
+	TIMEZONE_DELTA("CDT",-5),
+	TIMEZONE_DELTA("MST",-7),
+	TIMEZONE_DELTA("MDT",-6),
+	TIMEZONE_DELTA("PST",-8),
+	TIMEZONE_DELTA("PDT",-7)
+};
+
+#define HOURS(i)      ((i & 0xFF00) >> 8)
+#define SET_HOURS(i,h)  (i |= (h & 0xFF) << 8)
+
+#define MINUTES(i)    (i & 0x00FF)
+#define SET_MINUTES(i,m) (i |= (m & 0xFF))
+
+#define IS_NEG(i)     (i & 0xFF0000)
+#define SET_NEG(i)    (i|= 0x010000)
+#define IS_ERROR(i)   (i & 0xFF000000)
+#define SET_ERROR(i)  (i|= 0x01000000)
+
+
+static unsigned int
+two_digits(const char *p)
+{
+	int i = 0;
+	unsigned int sum = 0;
+
+	for(;i < 2 && *p && isdigit(*p); ++i,++p){
+		sum *= 10;
+		sum = sum + (*p - '0');
+	}
+
+	if(i == 2)
+		return sum;
+	else
+		return SET_ERROR(sum);
+}
+
+/*
+ * Parse the timezone like +0800,-0800,etc
+ */
+static unsigned int
+parse_delta(const char *p)
+{
+	unsigned int result = 0;
+	const char *curr;
+	int i = 0;
+
+	if(!p)
+		return SET_ERROR(result);
+	/* skip blank */
+	while( *p == ' '){ ++p;}
+
+	if(*p != '+' &&  *p != '-')
+		return SET_ERROR(result);
+	if(*p == '-')
+		SET_NEG(result);
+
+	curr = p + 1;
+	i = two_digits(curr);
+	if(IS_ERROR(i))
+		return SET_ERROR(result);
+	else{
+		SET_HOURS(result,i);
+		curr += 2;
+	}
+
+	i = two_digits(curr);
+	if(IS_ERROR(i))
+		return SET_ERROR(result);
+	else
+		SET_MINUTES(result,i);
+	return result;
+}
+
+static int 
+match_timezone(const char *zone,int *delta)
+{
+	int n = sizeof(tz_delta)/sizeof(timezone_delta);
+	int i = 0;
+
+	if(!zone)
+		return 0;
+	while( *zone == ' '){ ++zone; }
+	for(;i < n; ++i){
+		if(!strcmp(tz_delta[i].timezone,zone)){
+			if(delta){
+				*delta = tz_delta[i].delta_hours;
+				return 1;
+			}
+			break;
+		}
+	}
+	
+	return 0;
+}
+
 time_t
 TIM_parse(const char *p)
 {
 	time_t t;
 	struct tm tm;
 	const char **r;
+	const char *zone;
+	unsigned int result = 0;
+	int delta = 0;
 
 	for (r = fmts; *r != NULL; r++) {
 		memset(&tm, 0, sizeof tm);
-		if (strptime(p, *r, &tm) != NULL) {
+		if ((zone = strptime(p, *r, &tm)) != NULL) {
+
+			result = match_timezone(zone,&delta);
+			if(result){
+				delta *= 3600;
+			}else{
+				result = parse_delta(zone);
+				if(!IS_ERROR(result)){
+					delta += (HOURS(result) * 3600);
+					delta += (MINUTES(result) * 60);
+					if(IS_NEG(result))
+						delta *= -1;
+				}
+			}
+				
 			/*
 			 * Make sure this is initialized on the off-chance
 			 * that some raving loonie would apply DST to UTC.
@@ -133,6 +269,7 @@ TIM_parse(const char *p)
 			tm.tm_isdst = -1;
 #if defined(HAVE_TIMEGM)
 			t = timegm(&tm);
+			t += delta;
 #else
 			/*
 			 * Ahh, another POSIX_STUPIDITY, how unexpected.
@@ -284,7 +421,15 @@ main(int argc, char **argv)
 	/* Examples from RFC2616 section 3.3.1 */
 	tst("Sun, 06 Nov 1994 08:49:37 GMT", 784111777);
 	tst("Sunday, 06-Nov-94 08:49:37 GMT", 784111777);
+	tst("Sunday, 06-Nov-94 08:49:37 CST", 784090177);
+	tst("Sunday, 06-Nov-94 08:49:37 PST", 784082977);
 	tst("Sun Nov  6 08:49:37 1994", 784111777);
+	tst("Sun, 06 Nov 1994 08:49:37 +0000", 784111777);
+	tst("Sun, 06 Nov 1994 08:49:37 -0000", 784111777);
+	tst("Sun, 06 Nov 1994 08:49:37 +0100",784115377);
+	tst("Sun, 06 Nov 1994 08:49:37 -0100",784108177);
+	tst("Sun, 06 Nov 1994 08:49:37 +0010", 784112377);
+	tst("Sun, 06 Nov 1994 08:49:37 -0010", 784111177);
 
 	tst_delta();
 
-- 
1.7.7.5 (Apple Git-26)

