LTP GCOV extension - code coverage report
Current view: directory - ext/http - http_date_api.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 117
Code covered: 87.2 % Executed lines: 102
Legend: not executed executed

       1                 : /*
       2                 :     +--------------------------------------------------------------------+
       3                 :     | PECL :: http                                                       |
       4                 :     +--------------------------------------------------------------------+
       5                 :     | Redistribution and use in source and binary forms, with or without |
       6                 :     | modification, are permitted provided that the conditions mentioned |
       7                 :     | in the accompanying LICENSE file are met.                          |
       8                 :     +--------------------------------------------------------------------+
       9                 :     | Copyright (c) 2004-2007, Michael Wallner <mike@php.net>            |
      10                 :     +--------------------------------------------------------------------+
      11                 : */
      12                 : 
      13                 : /* $Id: http_date_api.c,v 1.17 2007/02/07 11:50:26 mike Exp $ */
      14                 : 
      15                 : #include "php_http.h"
      16                 : 
      17                 : #include "php_http_api.h"
      18                 : #include "php_http_date_api.h"
      19                 : 
      20                 : static inline int check_day(const char *day, size_t len);
      21                 : static inline int check_month(const char *month);
      22                 : static inline int check_tzone(const char *tzone);
      23                 : static inline time_t parse_date(const char *month);
      24                 : 
      25                 : /* {{{ day/month names */
      26                 : static const char *days[] = {
      27                 :         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
      28                 : };
      29                 : static const char *wkdays[] = {
      30                 :         "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
      31                 : };
      32                 : static const char *weekdays[] = {
      33                 :         "Monday", "Tuesday", "Wednesday",
      34                 :         "Thursday", "Friday", "Saturday", "Sunday"
      35                 : };
      36                 : static const char *months[] = {
      37                 :         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
      38                 :         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
      39                 : };
      40                 : enum assume_next {
      41                 :         DATE_MDAY,
      42                 :         DATE_YEAR,
      43                 :         DATE_TIME
      44                 : };
      45                 : #define DS -60
      46                 : static const struct time_zone {
      47                 :         const char *name;
      48                 :         const int offset;
      49                 : } time_zones[] = {
      50                 :     {"GMT", 0},     /* Greenwich Mean */
      51                 :     {"UTC", 0},     /* Universal (Coordinated) */
      52                 :     {"WET", 0},     /* Western European */
      53                 :     {"BST", 0 DS}, /* British Summer */
      54                 :     {"WAT", 60},    /* West Africa */
      55                 :     {"AST", 240},   /* Atlantic Standard */
      56                 :     {"ADT", 240 DS},/* Atlantic Daylight */
      57                 :     {"EST", 300},   /* Eastern Standard */
      58                 :     {"EDT", 300 DS},/* Eastern Daylight */
      59                 :     {"CST", 360},   /* Central Standard */
      60                 :     {"CDT", 360 DS},/* Central Daylight */
      61                 :     {"MST", 420},   /* Mountain Standard */
      62                 :     {"MDT", 420 DS},/* Mountain Daylight */
      63                 :     {"PST", 480},   /* Pacific Standard */
      64                 :     {"PDT", 480 DS},/* Pacific Daylight */
      65                 :     {"YST", 540},   /* Yukon Standard */
      66                 :     {"YDT", 540 DS},/* Yukon Daylight */
      67                 :     {"HST", 600},   /* Hawaii Standard */
      68                 :     {"HDT", 600 DS},/* Hawaii Daylight */
      69                 :     {"CAT", 600},   /* Central Alaska */
      70                 :     {"AHST", 600},  /* Alaska-Hawaii Standard */
      71                 :     {"NT",  660},   /* Nome */
      72                 :     {"IDLW", 720},  /* International Date Line West */
      73                 :     {"CET", -60},   /* Central European */
      74                 :     {"MET", -60},   /* Middle European */
      75                 :     {"MEWT", -60},  /* Middle European Winter */
      76                 :     {"MEST", -60 DS},/* Middle European Summer */
      77                 :     {"CEST", -60 DS},/* Central European Summer */
      78                 :     {"MESZ", -60 DS},/* Middle European Summer */
      79                 :     {"FWT", -60},   /* French Winter */
      80                 :     {"FST", -60 DS},/* French Summer */
      81                 :     {"EET", -120},  /* Eastern Europe, USSR Zone 1 */
      82                 :     {"WAST", -420}, /* West Australian Standard */
      83                 :     {"WADT", -420 DS},/* West Australian Daylight */
      84                 :     {"CCT", -480},  /* China Coast, USSR Zone 7 */
      85                 :     {"JST", -540},  /* Japan Standard, USSR Zone 8 */
      86                 :     {"EAST", -600}, /* Eastern Australian Standard */
      87                 :     {"EADT", -600 DS},/* Eastern Australian Daylight */
      88                 :     {"GST", -600},  /* Guam Standard, USSR Zone 9 */
      89                 :     {"NZT", -720},  /* New Zealand */
      90                 :     {"NZST", -720}, /* New Zealand Standard */
      91                 :     {"NZDT", -720 DS},/* New Zealand Daylight */
      92                 :     {"IDLE", -720}, /* International Date Line East */
      93                 : };
      94                 : /* }}} */
      95                 : 
      96                 : /* {{{ Day/Month/TZ checks for http_parse_date()
      97                 :         Originally by libcurl, Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al. */
      98                 : static inline int check_day(const char *day, size_t len)
      99               5 : {
     100                 :         int i;
     101               5 :         const char * const *check = (len > 3) ? &weekdays[0] : &wkdays[0];
     102              30 :         for (i = 0; i < 7; i++) {
     103              29 :             if (!strcmp(day, check[0])) {
     104               4 :                 return i;
     105                 :                 }
     106              25 :                 check++;
     107                 :         }
     108               1 :         return -1;
     109                 : }
     110                 : 
     111                 : static inline int check_month(const char *month)
     112               5 : {
     113                 :         int i;
     114               5 :         const char * const *check = &months[0];
     115              17 :         for (i = 0; i < 12; i++) {
     116              16 :                 if (!strcmp(month, check[0])) {
     117               4 :                         return i;
     118                 :                 }
     119              12 :                 check++;
     120                 :         }
     121               1 :         return -1;
     122                 : }
     123                 : 
     124                 : /* return the time zone offset between GMT and the input one, in number
     125                 :    of seconds or -1 if the timezone wasn't found/legal */
     126                 : 
     127                 : static inline int check_tzone(const char *tzone)
     128               5 : {
     129                 :         unsigned i;
     130               5 :         const struct time_zone *check = time_zones;
     131              48 :         for (i = 0; i < sizeof(time_zones) / sizeof(time_zones[0]); i++) {
     132              47 :                 if (!strcmp(tzone, check->name)) {
     133               4 :                         return check->offset * 60;
     134                 :                 }
     135              43 :                 check++;
     136                 :         }
     137               1 :         return -1;
     138                 : }
     139                 : /* }}} */
     140                 : 
     141                 : /* {{{ char *http_date(time_t) */
     142                 : PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC)
     143               9 : {
     144               9 :         char *date = NULL;
     145                 :         struct tm *gmtime, tmbuf;
     146                 : 
     147               9 :         if ((gmtime = php_gmtime_r(&t, &tmbuf))) {
     148               9 :                 spprintf(&date, 0,
     149                 :                         "%s, %02d %s %04d %02d:%02d:%02d GMT",
     150                 :                         days[gmtime->tm_wday], gmtime->tm_mday,
     151                 :                         months[gmtime->tm_mon], gmtime->tm_year + 1900,
     152                 :                         gmtime->tm_hour, gmtime->tm_min, gmtime->tm_sec
     153                 :                 );
     154                 :         }
     155                 : 
     156               9 :         return date;
     157                 : }
     158                 : /* }}} */
     159                 : 
     160                 : /* {{{ time_t http_parse_date(char *) */
     161                 : PHP_HTTP_API time_t _http_parse_date_ex(const char *date, zend_bool silent TSRMLS_DC)
     162               5 : {
     163               5 :         time_t t = parse_date(date);
     164                 :         
     165               5 :         if (-1 == t && !silent) {
     166               0 :                 http_error_ex(HE_NOTICE, HTTP_E_RUNTIME, "Could not parse date: %s", date);
     167                 :         }
     168                 :         
     169               5 :         return t;
     170                 : }
     171                 : /* }}} */
     172                 : 
     173                 : /*      time_t parse_date(char *)
     174                 :         Originally by libcurl, Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al. */
     175                 : static inline time_t parse_date(const char *date)
     176               5 : {
     177               5 :         time_t t = 0;
     178               5 :         int tz_offset = -1, year = -1, month = -1, monthday = -1, weekday = -1,
     179               5 :                 hours = -1, minutes = -1, seconds = -1;
     180                 :         struct tm tm;
     181               5 :         enum assume_next dignext = DATE_MDAY;
     182               5 :         const char *indate = date;
     183                 : 
     184               5 :         int part = 0; /* max 6 parts */
     185                 : 
     186              34 :         while (*date && (part < 6)) {
     187              25 :                 int found = 0;
     188                 : 
     189              75 :                 while (*date && !HTTP_IS_CTYPE(alnum, *date)) {
     190              25 :                         date++;
     191                 :                 }
     192                 : 
     193              25 :                 if (HTTP_IS_CTYPE(alpha, *date)) {
     194                 :                         /* a name coming up */
     195              13 :                         char buf[32] = "";
     196                 :                         size_t len;
     197              13 :                         sscanf(date, "%31[A-Za-z]", buf);
     198              13 :                         len = strlen(buf);
     199                 : 
     200              13 :                         if (weekday == -1) {
     201               5 :                                 weekday = check_day(buf, len);
     202               5 :                                 if (weekday != -1) {
     203               4 :                                         found = 1;
     204                 :                                 }
     205                 :                         }
     206                 : 
     207              13 :                         if (!found && (month == -1)) {
     208               5 :                                 month = check_month(buf);
     209               5 :                                 if (month != -1) {
     210               4 :                                         found = 1;
     211                 :                                 }
     212                 :                         }
     213                 : 
     214              13 :                         if (!found && (tz_offset == -1)) {
     215                 :                                 /* this just must be a time zone string */
     216               5 :                                 tz_offset = check_tzone(buf);
     217               5 :                                 if (tz_offset != -1) {
     218               4 :                                         found = 1;
     219                 :                                 }
     220                 :                         }
     221                 : 
     222              13 :                         if (!found) {
     223               1 :                                 return -1; /* bad string */
     224                 :                         }
     225              12 :                         date += len;
     226                 :                 }
     227              12 :                 else if (HTTP_IS_CTYPE(digit, *date)) {
     228                 :                         /* a digit */
     229                 :                         int val;
     230                 :                         char *end;
     231              16 :                         if ((seconds == -1) &&
     232                 :                                 (3 == sscanf(date, "%02d:%02d:%02d", &hours, &minutes, &seconds))) {
     233                 :                                 /* time stamp! */
     234               4 :                                 date += 8;
     235               4 :                                 found = 1;
     236                 :                         }
     237                 :                         else {
     238               8 :                                 val = (int) strtol(date, &end, 10);
     239                 : 
     240               8 :                                 if ((tz_offset == -1) && ((end - date) == 4) && (val < 1300) &&
     241                 :                                         (indate < date) && ((date[-1] == '+' || date[-1] == '-'))) {
     242                 :                                         /* four digits and a value less than 1300 and it is preceeded with
     243                 :                                         a plus or minus. This is a time zone indication. */
     244               0 :                                         found = 1;
     245               0 :                                         tz_offset = (val / 100 * 60 + val % 100) * 60;
     246                 : 
     247                 :                                         /* the + and - prefix indicates the local time compared to GMT,
     248                 :                                         this we need ther reversed math to get what we want */
     249               0 :                                         tz_offset = date[-1] == '+' ? -tz_offset : tz_offset;
     250                 :                                 }
     251                 : 
     252               8 :                                 if (((end - date) == 8) && (year == -1) && (month == -1) && (monthday == -1)) {
     253                 :                                         /* 8 digits, no year, month or day yet. This is YYYYMMDD */
     254               0 :                                         found = 1;
     255               0 :                                         year = val / 10000;
     256               0 :                                         month = (val % 10000) / 100 - 1; /* month is 0 - 11 */
     257               0 :                                         monthday = val % 100;
     258                 :                                 }
     259                 : 
     260               8 :                                 if (!found && (dignext == DATE_MDAY) && (monthday == -1)) {
     261               4 :                                         if ((val > 0) && (val < 32)) {
     262               4 :                                                 monthday = val;
     263               4 :                                                 found = 1;
     264                 :                                         }
     265               4 :                                         dignext = DATE_YEAR;
     266                 :                                 }
     267                 : 
     268               8 :                                 if (!found && (dignext == DATE_YEAR) && (year == -1)) {
     269               4 :                                         year = val;
     270               4 :                                         found = 1;
     271               4 :                                         if (year < 1900) {
     272               0 :                                                 year += year > 70 ? 1900 : 2000;
     273                 :                                         }
     274               4 :                                         if(monthday == -1) {
     275               0 :                                                 dignext = DATE_MDAY;
     276                 :                                         }
     277                 :                                 }
     278                 : 
     279               8 :                                 if (!found) {
     280               0 :                                         return -1;
     281                 :                                 }
     282                 : 
     283               8 :                                 date = end;
     284                 :                         }
     285                 :                 }
     286                 : 
     287              24 :                 part++;
     288                 :         }
     289                 : 
     290               4 :         if (-1 == seconds) {
     291               0 :                 seconds = minutes = hours = 0; /* no time, make it zero */
     292                 :         }
     293                 : 
     294               4 :         if ((-1 == monthday) || (-1 == month) || (-1 == year)) {
     295                 :                 /* lacks vital info, fail */
     296               0 :                 return -1;
     297                 :         }
     298                 : 
     299                 :         if (sizeof(time_t) < 5) {
     300                 :                 /* 32 bit time_t can only hold dates to the beginning of 2038 */
     301               4 :                 if (year > 2037) {
     302               2 :                         return 0x7fffffff;
     303                 :                 }
     304                 :         }
     305                 : 
     306               2 :         tm.tm_sec = seconds;
     307               2 :         tm.tm_min = minutes;
     308               2 :         tm.tm_hour = hours;
     309               2 :         tm.tm_mday = monthday;
     310               2 :         tm.tm_mon = month;
     311               2 :         tm.tm_year = year - 1900;
     312               2 :         tm.tm_wday = 0;
     313               2 :         tm.tm_yday = 0;
     314               2 :         tm.tm_isdst = 0;
     315                 : 
     316               2 :         t = mktime(&tm);
     317                 : 
     318                 :         /* time zone adjust */
     319               2 :         if (t != -1) {
     320                 :                 struct tm *gmt, keeptime2;
     321                 :                 long delta;
     322                 :                 time_t t2;
     323                 : 
     324               2 :                 if((gmt = php_gmtime_r(&t, &keeptime2))) {
     325               2 :                         tm = *gmt; /* MSVC quirks */
     326                 :                 } else {
     327               0 :                         return -1; /* illegal date/time */
     328                 :                 }
     329                 : 
     330               2 :                 t2 = mktime(&tm);
     331                 : 
     332                 :                 /* Add the time zone diff (between the given timezone and GMT) and the
     333                 :                 diff between the local time zone and GMT. */
     334               4 :                 delta = (tz_offset != -1 ? tz_offset : 0) + (t - t2);
     335                 : 
     336               2 :                 if((delta > 0) && (t + delta < t)) {
     337               0 :                         return -1; /* time_t overflow */
     338                 :                 }
     339                 : 
     340               2 :                 t += delta;
     341                 :         }
     342                 : 
     343               2 :         return t;
     344                 : }
     345                 : /* }}} */
     346                 : 
     347                 : 
     348                 : /*
     349                 :  * Local variables:
     350                 :  * tab-width: 4
     351                 :  * c-basic-offset: 4
     352                 :  * End:
     353                 :  * vim600: sw=4 ts=4 fdm=marker
     354                 :  * vim<600: sw=4 ts=4
     355                 :  */
     356                 : 

Generated by: LTP GCOV extension version 1.5