httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rob Hartill <r...@imdb.com>
Subject Re: Apache 1.1.1 parsedate port to 64-bit time_t (+ minor speedups)
Date Mon, 04 Nov 1996 20:10:56 GMT

Hi,

Thanks for the information and patches. I'm forwarding your mail to
the developers list.

regards,
rob

Paul Eggert wrote:
>
>Apache 1.1.1's parsedate function assumes that time_t is a signed
>32-bit integer; this assumption isn't true for NetBSD on Alphas, which
>uses 64-bit time_t.
>
>Here's a patch that removes this 32-bit assumption from the parsedate
>function and its auxiliaries.  A naive removal slows down the code, so
>I took the opportunity to tune the function until it was a tad faster
>than before on my Ultrasparc (compiled with GCC).
>
>1996-11-03  Paul Eggert  <eggert@twinsun.com>
>
>	* mod_proxy.c (datetime2sec):
>	Do not assume that time_t is signed 32-bit.
>	Renamed from tm2sec; now takes 6 arguments rather than
>	struct tm *, for speed.
>	Ignore any input leap second.  Tune.
>	(parsedate): Now takes just 1 argument, for speed (the 2nd was 0).
>	Simplify, since we now pass 6 args to datetime2sec.
>	Calculate mday the same way we calculate other 2-digit values.
>	Calculate year by staggering multiples of 10.
>	Make `months' static, so that the compiler won't copy it.
>
>===================================================================
>RCS file: mod_proxy.c,v
>retrieving revision 1.1.1.0
>retrieving revision 1.1.1.1
>diff -c -r1.1.1.0 -r1.1.1.1
>*** mod_proxy.c	1996/07/03 15:02:58	1.1.1.0
>--- mod_proxy.c	1996/11/04 06:48:15	1.1.1.1
>***************
>*** 1087,1098 ****
>  }
>  
>  /*
>!  * This routine converts a tm structure into the number of seconds
>!  * since 1st January 1970 UT
>   * 
>!  * The return value is a non-negative integer on success or -1 if the
>!  * input date is out of the domain Thu, 01 Jan 1970 00:00:00 to
>!  * Tue, 19 Jan 2038 03:14:07 inclusive
>   *
>   * Notes
>   *   This routine has been tested on 1000000 valid dates generated
>--- 1087,1098 ----
>  }
>  
>  /*
>!  * This routine converts a Gregorian date and time into the number of seconds
>!  * since 1970-01-01 UTC, not counting leap seconds.  YEAR is the Gregorian
>!  * year; MON is the origin-0 month (i.e. 0 represents January).
>   * 
>!  * The return value is a time_t value on success; it is -1 if the
>!  * input date cannot be represented as a time_t.
>   *
>   * Notes
>   *   This routine has been tested on 1000000 valid dates generated
>***************
>*** 1100,1126 ****
>   * 
>   *   This routine is very fast, much faster than mktime().
>   */
>! static int
>! tm2sec(const struct tm *t)
>  {
>!     int days, year;
>      static const int dayoffs[12]=
>!     {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
>! 
>!     year = t->tm_year;
>! /* shift new year to 1st March; which is where it should be */
>!     if (t->tm_mon < 2) year--;  /* now years and months since 1st March 1900 */
>!     days = t->tm_mday - 1 + dayoffs[t->tm_mon];
>! 
>! /* find the number of days since 1st March 1900 (in the Gregorian calendar) */
>!     days += year * 365 + year/4 - year/100 + (year/100 + 3)/4;
>!     days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
>! 
>!     days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;
>!     if (year < 69 || year > 138 || days < 0) /* must have overflowed */
>  	return -1;
>      else
>! 	return days;
>  }
>  
>  /*
>--- 1100,1135 ----
>   * 
>   *   This routine is very fast, much faster than mktime().
>   */
>! static time_t
>! datetime2sec(int year, int mon, int mday, int hour, int min, int sec)
>  {
>! /* Find year relative to 2000-03-01, and divide by 4, 100, 400.  */
>!     int y4 = (year -= 2000 + (mon < 2)) >> 2;
>!     int y100 = y4 / 25 - (y4 % 25 < 0);
>!     int y400 = y100 >> 2;
>! 
>! /* Find number of days since 1970-01-01.
>!  * 2000-03-01 is 11017 days since 1970-01-01;
>!  * subtract 1 since mday is origin-1.
>!  */
>! #   define DAYOFFS_ADJUST(n) ((n) + 11017 - 1)
>      static const int dayoffs[12]=
>!     {DAYOFFS_ADJUST(306), DAYOFFS_ADJUST(337), DAYOFFS_ADJUST(  0),
>!      DAYOFFS_ADJUST( 31), DAYOFFS_ADJUST( 61), DAYOFFS_ADJUST( 92),
>!      DAYOFFS_ADJUST(122), DAYOFFS_ADJUST(153), DAYOFFS_ADJUST(184),
>!      DAYOFFS_ADJUST(214), DAYOFFS_ADJUST(245), DAYOFFS_ADJUST(275)};
>!     int days = year * 365 + y4 - y100 + y400 + mday + dayoffs[mon];
>! 
>! /* Find number of seconds since 1970-01-01, ignoring leap seconds.  */
>!     int secoffs = (hour * 60 + min) * 60 + (sec % 60);
>!     time_t secs = days * (time_t) SEC_ONE_DAY + secoffs;
>! 
>! /* Check for overflow.  */
>!     if (days + (days < 0) != 
>! 	(secs + (secs < 0 ? SEC_ONE_DAY - secoffs : 0)) / SEC_ONE_DAY)
>  	return -1;
>      else
>! 	return secs;
>  }
>  
>  /*
>***************
>*** 1139,1149 ****
>   * The spec is not clear as to whether the day and months are
>   * case-sensitive or not. This code assumes they are.
>   *
>!  * It fills in the year, month, mday, hour, min, sec and is_dst fields of
>!  * date. It does not set the wday or yday fields.
>!  * On failure is sets the year to 0.
>!  * 
>!  * It also returns the number of seconds since 1 Jan 1970 UT, or
>   * -1 if this would be out of range or if the date is invalid.
>   *
>   * Notes
>--- 1148,1154 ----
>   * The spec is not clear as to whether the day and months are
>   * case-sensitive or not. This code assumes they are.
>   *
>!  * It returns the number of seconds since 1970-01-01 UTC, or
>   * -1 if this would be out of range or if the date is invalid.
>   *
>   * Notes
>***************
>*** 1153,1201 ****
>   *   This routine is very fast; it would be 10x slower if it
>   *   used sscanf.
>   */
>! static int
>! parsedate(const char *date, struct tm *d)
>  {
>!     int mint, mon, year;
>!     struct tm x;
>!     const int months[12]={
>  	('J' << 16) | ( 'a' << 8) | 'n', ('F' << 16) | ( 'e' << 8)
| 'b',
>  	('M' << 16) | ( 'a' << 8) | 'r', ('A' << 16) | ( 'p' << 8)
| 'r',
>  	('M' << 16) | ( 'a' << 8) | 'y', ('J' << 16) | ( 'u' << 8)
| 'n',
>  	('J' << 16) | ( 'u' << 8) | 'l', ('A' << 16) | ( 'u' << 8)
| 'g',
>  	('S' << 16) | ( 'e' << 8) | 'p', ('O' << 16) | ( 'c' << 8)
| 't',
>  	('N' << 16) | ( 'o' << 8) | 'v', ('D' << 16) | ( 'e' << 8)
| 'c'};
>-     if (d == NULL) d = &x;
>  
>-     d->tm_year = 0;  /* bad date */
>      if (!checkmask(date, "@$$, ## @$$ #### ##:##:## GMT")) return -1;
>  
>  /* we don't test the weekday */
>!     d->tm_mday = (date[5] - '0') * 10 + (date[6] - '0');
>!     if (d->tm_mday == 0 || d->tm_mday > 31) return -1;
>  
>      mint = (date[8] << 16) | (date[9] << 8) | date[10];
>      for (mon=0; mon < 12; mon++) if (mint == months[mon]) break;
>      if (mon == 12) return -1;
>      
>!     d->tm_mon = mon;
>!     year = date[12] * 1000 + date[13] * 100 + date[14] * 10 + date[15] -
>  	         ('0' * 1111);
>!     d->tm_hour = date[17] * 10 + date[18] - '0' * 11;
>!     d->tm_min  = date[20] * 10 + date[21] - '0' * 11;
>!     d->tm_sec = date[23] * 10 + date[24] - '0' * 11;
>! 
>!     if (d->tm_hour > 23 || d->tm_min > 59 || d->tm_sec > 61) return
-1;
>! 
>!     if (d->tm_mday == 31 && (mon == 1 || mon == 3 || mon == 5 || mon == 8
||
>! 			     mon == 10)) return -1;
>!     if (d->tm_mday > 29 && mon == 1) return -1;
>!     if (d->tm_mday == 29 && mon == 1)
>! 	if (year%4 != 0 || (year%100 == 0 && year%400 != 0)) return -1;
>! 
>!     d->tm_year = year - 1900;
>!     d->tm_isdst = 0;
>!     return tm2sec(d);
>  }
>  
>  /*
>--- 1158,1200 ----
>   *   This routine is very fast; it would be 10x slower if it
>   *   used sscanf.
>   */
>! static time_t
>! parsedate(const char *date)
>  {
>!     int mint, year, mon, mday, hour, min, sec;
>!     static const int months[12]={
>  	('J' << 16) | ( 'a' << 8) | 'n', ('F' << 16) | ( 'e' << 8)
| 'b',
>  	('M' << 16) | ( 'a' << 8) | 'r', ('A' << 16) | ( 'p' << 8)
| 'r',
>  	('M' << 16) | ( 'a' << 8) | 'y', ('J' << 16) | ( 'u' << 8)
| 'n',
>  	('J' << 16) | ( 'u' << 8) | 'l', ('A' << 16) | ( 'u' << 8)
| 'g',
>  	('S' << 16) | ( 'e' << 8) | 'p', ('O' << 16) | ( 'c' << 8)
| 't',
>  	('N' << 16) | ( 'o' << 8) | 'v', ('D' << 16) | ( 'e' << 8)
| 'c'};
>  
>      if (!checkmask(date, "@$$, ## @$$ #### ##:##:## GMT")) return -1;
>  
>  /* we don't test the weekday */
>!     mday = date[5] * 10 + date[6] - '0' * 11;
>!     if (mday <= 0 || mday > 31) return -1;
>  
>      mint = (date[8] << 16) | (date[9] << 8) | date[10];
>      for (mon=0; mon < 12; mon++) if (mint == months[mon]) break;
>      if (mon == 12) return -1;
>      
>!     year = ((date[12] * 10 + date[13]) * 10 + date[14]) * 10 + date[15] -
>  	         ('0' * 1111);
>!     hour = date[17] * 10 + date[18] - '0' * 11;
>!     min = date[20] * 10 + date[21] - '0' * 11;
>!     sec = date[23] * 10 + date[24] - '0' * 11;
>! 
>!     if (hour > 23 || min > 59 || sec > 60) return -1;
>! 
>!     if (mday == 31 && (mon == 3 || mon == 5 || mon == 8 ||
>! 		       mon == 10)) return -1;
>!     if (mday >= 29 && mon == 1 &&
>! 	! (mday == 29 && ((year&3) == 0 && (year%100 != 0 || year%400 ==
0))))
>!       return -1;
>! 
>!     return datetime2sec(year, mon, mday, hour, min, sec);
>  }
>  
>  /*
>***************
>*** 1632,1638 ****
>      {
>  /* this may modify the value in the original table */
>  	imstr = date_canon(r->pool, imstr);
>! 	c->ims = parsedate(imstr, NULL);
>  	if (c->ims == -1)  /* bad or out of range date; remove it */
>  	    table_set(r->headers_in, "If-Modified-Since", NULL);
>      }
>--- 1631,1637 ----
>      {
>  /* this may modify the value in the original table */
>  	imstr = date_canon(r->pool, imstr);
>! 	c->ims = parsedate(imstr);
>  	if (c->ims == -1)  /* bad or out of range date; remove it */
>  	    table_set(r->headers_in, "If-Modified-Since", NULL);
>      }
>***************
>*** 1784,1790 ****
>   * read it
>   */
>      expire = get_header(resp_hdrs, "Expire");
>!     if (expire != NULL) expc = parsedate(expire->value, NULL);
>      else expc = -1;
>  
>  /*
>--- 1783,1789 ----
>   * read it
>   */
>      expire = get_header(resp_hdrs, "Expire");
>!     if (expire != NULL) expc = parsedate(expire->value);
>      else expc = -1;
>  
>  /*
>***************
>*** 1793,1799 ****
>      lmods = get_header(resp_hdrs, "Last-Modified");
>      if (lmods != NULL)
>      {
>! 	lmod = parsedate(lmods->value, NULL);
>  	if (lmod == -1)
>  	{
>  /* kill last modified date */
>--- 1792,1798 ----
>      lmods = get_header(resp_hdrs, "Last-Modified");
>      if (lmods != NULL)
>      {
>! 	lmod = parsedate(lmods->value);
>  	if (lmod == -1)
>  	{
>  /* kill last modified date */
>***************
>*** 1838,1844 ****
>   * Read the date. Generate one if one is not supplied
>   */
>      dates = get_header(resp_hdrs, "Date");
>!     if (dates != NULL) date = parsedate(dates->value, NULL);
>      else date = -1;
>  	
>      now = time(NULL);
>--- 1837,1843 ----
>   * Read the date. Generate one if one is not supplied
>   */
>      dates = get_header(resp_hdrs, "Date");
>!     if (dates != NULL) date = parsedate(dates->value);
>      else date = -1;
>  	
>      now = time(NULL);
>***************
>*** 1873,1879 ****
>      if (expire == NULL && c->fp != NULL)  /* no expiry data sent in response
*/
>      {
>  	expire = get_header(c->hdrs, "Expires");
>! 	if (expire != NULL) expc = parsedate(expire->value, NULL);
>      }
>  /* so we now have the expiry date */
>  /* if no expiry date then
>--- 1872,1878 ----
>      if (expire == NULL && c->fp != NULL)  /* no expiry data sent in response
*/
>      {
>  	expire = get_header(c->hdrs, "Expires");
>! 	if (expire != NULL) expc = parsedate(expire->value);
>      }
>  /* so we now have the expiry date */
>  /* if no expiry date then
>


-- 
Rob Hartill.       Internet Movie Database Ltd.    http://www.imdb.com/  

Mime
View raw message