1 /* 2 * Copyright 2010-2016 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Christophe Huriaux, c.huriaux@gmail.com 7 * Adrien Destugues, pulkomandy@gmail.com 8 */ 9 10 #include <HttpTime.h> 11 12 #include <new> 13 14 #include <cstdio> 15 16 17 // The formats used should be, in order of preference (according to RFC2616, 18 // section 3.3): 19 // RFC1123 / RFC822: "Sun, 06 Nov 1994 08:49:37 GMT" 20 // RFC1036 / RFC850: "Sunday, 06-Nov-94 08:49:37 GMT" 21 // asctime : "Sun Nov 6 08:49:37 1994" 22 // 23 // RFC1123 is the preferred one because it has 4 digit years. 24 // 25 // But of course in real life, all possible mixes of the formats are used. 26 // Believe it or not, it's even possible to find some website that gets this 27 // right and use one of the 3 formats above. 28 // Often seen variants are: 29 // - RFC1036 but with 4 digit year, 30 // - Missing or different timezone indicator 31 // - Invalid weekday 32 static const char* kDateFormats[] = { 33 // RFC1123 34 "%a, %d %b %Y %H:%M:%S", // without timezone 35 "%a, %d %b %Y %H:%M:%S GMT", // canonical 36 37 // RFC1036 38 "%A, %d-%b-%y %H:%M:%S", // without timezone 39 "%A, %d-%b-%y %H:%M:%S GMT", // canonical 40 41 // RFC1036 with 4 digit year 42 "%a, %d-%b-%Y %H:%M:%S", // without timezone 43 "%a, %d-%b-%Y %H:%M:%S GMT", // with 4-digit year 44 "%a, %d-%b-%Y %H:%M:%S UTC", // "UTC" timezone 45 46 // asctime 47 "%a %d %b %H:%M:%S %Y" 48 }; 49 50 #ifdef LIBNETAPI_DEPRECATED 51 using namespace BPrivate; 52 #else 53 using namespace BPrivate::Network; 54 #endif 55 56 57 BHttpTime::BHttpTime() 58 : 59 fDate(0), 60 fDateFormat(B_HTTP_TIME_FORMAT_PREFERRED) 61 { 62 } 63 64 65 BHttpTime::BHttpTime(BDateTime date) 66 : 67 fDate(date), 68 fDateFormat(B_HTTP_TIME_FORMAT_PREFERRED) 69 { 70 } 71 72 73 BHttpTime::BHttpTime(const BString& dateString) 74 : 75 fDateString(dateString), 76 fDate(0), 77 fDateFormat(B_HTTP_TIME_FORMAT_PREFERRED) 78 { 79 } 80 81 82 // #pragma mark Date modification 83 84 85 void 86 BHttpTime::SetString(const BString& string) 87 { 88 fDateString = string; 89 } 90 91 92 void 93 BHttpTime::SetDate(BDateTime date) 94 { 95 fDate = date; 96 } 97 98 99 // #pragma mark Date conversion 100 101 102 BDateTime 103 BHttpTime::Parse() 104 { 105 struct tm expireTime; 106 107 if (fDateString.Length() < 4) 108 return 0; 109 110 memset(&expireTime, 0, sizeof(struct tm)); 111 112 fDateFormat = B_HTTP_TIME_FORMAT_PARSED; 113 unsigned int i; 114 for (i = 0; i < sizeof(kDateFormats) / sizeof(const char*); 115 i++) { 116 const char* result = strptime(fDateString.String(), kDateFormats[i], 117 &expireTime); 118 119 // We need to parse the complete value for the "Expires" key. 120 // Otherwise, we consider this to be a session cookie (or try another 121 // one of the date formats). 122 if (result == fDateString.String() + fDateString.Length()) { 123 fDateFormat = i; 124 break; 125 } 126 } 127 128 // Did we identify some valid format? 129 if (fDateFormat == B_HTTP_TIME_FORMAT_PARSED) 130 return 0; 131 132 // Now convert the struct tm from strptime into a BDateTime. 133 BTime time(expireTime.tm_hour, expireTime.tm_min, expireTime.tm_sec); 134 BDate date(expireTime.tm_year + 1900, expireTime.tm_mon + 1, 135 expireTime.tm_mday); 136 BDateTime dateTime(date, time); 137 return dateTime; 138 } 139 140 141 BString 142 BHttpTime::ToString(int8 format) 143 { 144 BString expirationFinal; 145 struct tm expirationTm; 146 expirationTm.tm_sec = fDate.Time().Second(); 147 expirationTm.tm_min = fDate.Time().Minute(); 148 expirationTm.tm_hour = fDate.Time().Hour(); 149 expirationTm.tm_mday = fDate.Date().Day(); 150 expirationTm.tm_mon = fDate.Date().Month() - 1; 151 expirationTm.tm_year = fDate.Date().Year() - 1900; 152 // strftime starts weekday count at 0 for Sunday, 153 // while DayOfWeek starts at 1 for Monday and thus uses 7 for Sunday 154 expirationTm.tm_wday = fDate.Date().DayOfWeek() % 7; 155 expirationTm.tm_yday = 0; 156 expirationTm.tm_isdst = 0; 157 158 if (format == B_HTTP_TIME_FORMAT_PARSED) 159 format = fDateFormat; 160 161 if (format != B_HTTP_TIME_FORMAT_PARSED) { 162 static const uint16 kTimetToStringMaxLength = 128; 163 char expirationString[kTimetToStringMaxLength + 1]; 164 size_t strLength; 165 166 strLength = strftime(expirationString, kTimetToStringMaxLength, 167 kDateFormats[format], &expirationTm); 168 169 expirationFinal.SetTo(expirationString, strLength); 170 } 171 return expirationFinal; 172 } 173