Yet Another HTTP Library: /home/cmouse/projects/libyahttp/yahttp/utility.hpp Source File

Yet Another HTTP Library yahttp

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
utility.hpp
Go to the documentation of this file.
1 #ifndef _YAHTTP_UTILITY_HPP
2 #define _YAHTTP_UTILITY_HPP 1
3
4 namespace YaHTTP {
5 static const char *MONTHS[] = {0,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",0}; //<! List of months
6 static const char *DAYS[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat",0}; //<! List of days
7
9 struct ASCIICINullSafeComparator {
10 bool operator() (const std::string& lhs, const std::string& rhs) const {
11 char v;
12 std::string::const_iterator lhi = lhs.begin();
13 std::string::const_iterator rhi = rhs.begin();
14 for(;lhi != lhs.end() && rhi != rhs.end(); lhi++, rhi++)
15 if ((v = ::tolower(*lhi) - ::tolower(*rhi)) != 0) return v<0;
16 if (lhi == lhs.end() && rhi != rhs.end()) return true;
17 if (lhi != lhs.end() && rhi == rhs.end()) return false;
18 return false; // they are equal
19 }
20 };
21
22 typedef std::map<std::string,std::string,ASCIICINullSafeComparator> strstr_map_t; //<! String to String map
23
25 class DateTime {
26 public:
27 bool isSet; //<! if this is initialized yet
28
29 int year; //<! year, 0 is year 0, not 1900
30
31 int month; //<! month, range 1-12
32 int day; //<! day, range 1-31
33 int wday; //<! week day, range 1-7
34
35 int hours; //<! hours, range 0-23
36 int minutes; //<! minutes, range 0-59
37 int seconds; //<! seconds, range 0-60
38
39 int utc_offset; //<! UTC offset with minutes (hhmm)
40
41 DateTime() {
42 initialize();
43 }; //<! Construct and initialize
44
45 void initialize() {
46 isSet = false;
47 year = month = day = wday = hours = minutes = seconds = utc_offset = 0;
48 month = 1; // it's invalid otherwise
49 }; //<! Creates year 0 date
50
51 void setLocal() {
52 fromLocaltime(time((time_t*)NULL));
53 }; //<! sets current local time
54
55 void setGm() {
56 fromGmtime(time((time_t*)NULL));
57 }; //<! sets current gmtime (almost UTC)
58
59 void fromLocaltime(time_t t) {
60 #ifdef HAVE_LOCALTIME_R
61 struct tm tm;
62 localtime_r(&t, &tm);
63 fromTm(&tm);
64 #else
65 struct tm *tm;
66 tm = localtime(&t);
67 fromTm(tm);
68 #endif
69 #ifndef HAVE_TM_GMTOFF
70 time_t t2;
71 # ifdef HAVE_LOCALTIME_R
72 gmtime_r(&t, &tm);
73 t2 = mktime(&tm);
74 # else
75 tm = gmtime(&t);
76 t2 = mktime(tm);
77 # endif
78 this->utc_offset = ((t2-t)/10)*10; // removes any possible differences.
79 #endif
80 }; //<! uses localtime for time
81
82 void fromGmtime(time_t t) {
83 #ifdef HAVE_GMTIME_R
84 struct tm tm;
85 gmtime_r(&t, &tm);
86 fromTm(&tm);
87 #else
88 struct tm *tm;
89 tm = gmtime(&t);
90 fromTm(tm);
91 #endif
92 #ifndef HAVE_TM_GMTOFF
93 this->utc_offset = 0;
94 #endif
95 }; //<! uses gmtime for time
96
97 void fromTm(const struct tm *tm) {
98 year = tm->tm_year + 1900;
99 month = tm->tm_mon + 1;
100 day = tm->tm_mday;
101 hours = tm->tm_hour;
102 minutes = tm->tm_min;
103 seconds = tm->tm_sec;
104 wday = tm->tm_wday;
105 #ifdef HAVE_TM_GMTOFF
106 utc_offset = tm->tm_gmtoff;
107 #endif
108 isSet = true;
109 }; //<! parses date from struct tm
110
111 void validate() const {
112 if (wday < 0 || wday > 6) throw "Invalid date";
113 if (month < 1 || month > 12) throw "Invalid date";
114 if (year < 0) throw "Invalid date";
115 if (hours < 0 || hours > 23 ||
116 minutes < 0 || minutes > 59 ||
117 seconds < 0 || seconds > 60) throw "Invalid date";
118 }; //<! make sure we are within ranges (not a *REAL* validation, just range check)
119
120 std::string rfc_str() const {
121 std::ostringstream oss;
122 validate();
123 oss << DAYS[wday] << ", " << std::setfill('0') << std::setw(2) << day << " " << MONTHS[month] << " " <<
124 std::setfill('0') << std::setw(2) << year << " " <<
125 std::setfill('0') << std::setw(2) << hours << ":" <<
126 std::setfill('0') << std::setw(2) << minutes << ":" <<
127 std::setfill('0') << std::setw(2) << seconds << " ";
128 if (utc_offset>=0) oss << "+";
129 else oss << "-";
130 int tmp_off = ( utc_offset < 0 ? utc_offset*-1 : utc_offset );
131 oss << std::setfill('0') << std::setw(2) << (tmp_off/3600);
132 oss << std::setfill('0') << std::setw(2) << (tmp_off%3600)/60;
133
134 return oss.str();
135 }; //<! converts this date into a RFC-822 format
136
137 std::string cookie_str() const {
138 std::ostringstream oss;
139 validate();
140 oss << std::setfill('0') << std::setw(2) << day << "-" << MONTHS[month] << "-" << year << " " <<
141 std::setfill('0') << std::setw(2) << hours << ":" <<
142 std::setfill('0') << std::setw(2) << minutes << ":" <<
143 std::setfill('0') << std::setw(2) << seconds << " GMT";
144 return oss.str();
145 }; //<! converts this date into a HTTP Cookie date
146
147 void parse822(const std::string &rfc822_date) {
148 struct tm tm;
149 const char *ptr;
150 #ifdef HAVE_TM_GMTOFF
151 if ( (ptr = strptime(rfc822_date.c_str(), "%a, %d %b %Y %T %z", &tm)) != NULL) {
152 #else
153 if ( (ptr = strptime(rfc822_date.c_str(), "%a, %d %b %Y %T", &tm)) != NULL) {
154 int sign;
155 // parse the timezone parameter
156 while(*ptr && ::isspace(*ptr)) ptr++;
157 if (*ptr == '+') sign = 0;
158 else if (*ptr == '-') sign = -1;
159 else throw "Unparseable date";
160 ptr++;
161 utc_offset = ::atoi(ptr) * sign;
162 while(*ptr && ::isdigit(*ptr)) ptr++;
163 #endif
164 while(*ptr && ::isspace(*ptr)) ptr++;
165 if (*ptr) throw "Unparseable date"; // must be final.
166 fromTm(&tm);
167 } else {
168 throw "Unparseable date";
169 }
170 }; //<! parses RFC-822 date
171
172 void parseCookie(const std::string &cookie_date) {
173 struct tm tm;
174 const char *ptr;
175 if ( (ptr = strptime(cookie_date.c_str(), "%d-%b-%Y %T", &tm)) != NULL) {
176 while(*ptr && ( ::isspace(*ptr) || ::isalnum(*ptr) )) ptr++;
177 if (*ptr) throw "Unparseable date (non-final)"; // must be final.
178 fromTm(&tm);
179 this->utc_offset = 0;
180 } else {
181 throw "Unparseable date (did not match pattern cookie)";
182 }
183 }; //<! parses HTTP Cookie date
184
185 time_t unixtime() const {
186 struct tm tm;
187 tm.tm_year = year-1900;
188 tm.tm_mon = month-1;
189 tm.tm_mday = day;
190 tm.tm_hour = hours;
191 tm.tm_min = minutes;
192 tm.tm_sec = seconds;
193 tm.tm_isdst = 0;
194 #ifdef HAVE_TM_GMTOFF
195 tm.tm_gmtoff = utc_offset;
196 #endif
197 return mktime(&tm);
198 }; //<! returns this datetime as unixtime. will not work for dates before 1970/1/1 00:00:00 GMT
199 };
200
202 class Utility {
203 public:
204 static std::string decodeURL(const std::string& component) {
205 std::string result = component;
206 size_t pos1,pos2;
207 pos2 = 0;
208 while((pos1 = result.find_first_of("%", pos2))!=std::string::npos) {
209 std::string code;
210 char a,b,c;
211 if (pos1 + 2 > result.length()) return result; // end of result
212 code = result.substr(pos1+1, 2);
213 a = std::tolower(code[0]); b = std::tolower(code[1]);
214
215 if ((( '0' > a || a > '9') && ('a' > a || a > 'f')) ||
216 (( '0' > b || b > '9') && ('a' > b || b > 'f'))) {
217 pos2 = pos1+3;
218 continue;
219 }
220
221 if ('0' <= a && a <= '9') a = a - '0';
222 if ('a' <= a && a <= 'f') a = a - 'a' + 0x0a;
223 if ('0' <= b && b <= '9') b = b - '0';
224 if ('a' <= b && b <= 'f') b = b - 'a' + 0x0a;
225
226 c = (a<<4)+b;
227 result = result.replace(pos1,3,1,c);
228 pos2=pos1;
229 }
230 return result;
231 }; //<! Decodes %xx from string into bytes
232
233 static std::string encodeURL(const std::string& component, bool asUrl = true) {
234 std::string result = component;
235 std::string skip = "+-.:,&;_#%[]?/@(){}=";
236 char repl[3];
237 size_t pos;
238 for(std::string::iterator iter = result.begin(); iter != result.end(); iter++) {
239 if (!std::isalnum(*iter) && (!asUrl || skip.find(*iter) == std::string::npos)) {
240 // replace with different thing
241 pos = std::distance(result.begin(), iter);
242 ::snprintf(repl,3,"%02x", static_cast<unsigned char>(*iter));
243 result = result.replace(pos, 1, "%", 1).insert(pos+1, repl, 2);
244 iter = result.begin() + pos + 2;
245 }
246 }
247 return result;
248 }; //<! Escapes any characters into %xx representation when necessary, set asUrl to false to fully encode the url
249
250 static std::string encodeURL(const std::wstring& component, bool asUrl = true) {
251 unsigned char const *p = reinterpret_cast<unsigned char const*>(&component[0]);
252 std::size_t s = component.size() * sizeof((*component.begin()));
253 std::vector<unsigned char> vec(p, p+s);
254
255 std::ostringstream result;
256 std::string skip = "+-.,&;_#%[]?/@(){}=";
257 for(std::vector<unsigned char>::iterator iter = vec.begin(); iter != vec.end(); iter++) {
258 if (!std::isalnum((char)*iter) && (!asUrl || skip.find((char)*iter) == std::string::npos)) {
259 // bit more complex replace
260 result << "%" << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(*iter);
261 } else result << (char)*iter;
262 }
263 return result.str();
264 }; //<! Escapes any characters into %xx representation when necessary, set asUrl to false to fully encode the url, for wide strings, returns ordinary string
265
266 static std::string status2text(int status) {
267 switch(status) {
268 case 200:
269 return "OK";
270 case 201:
271 return "Created";
272 case 202:
273 return "Accepted";
274 case 203:
275 return "Non-Authoritative Information";
276 case 204:
277 return "No Content";
278 case 205:
279 return "Reset Content";
280 case 206:
281 return "Partial Content";
282 case 300:
283 return "Multiple Choices";
284 case 301:
285 return "Moved Permanently";
286 case 302:
287 return "Found";
288 case 303:
289 return "See Other";
290 case 304:
291 return "Not Modified";
292 case 305:
293 return "Use Proxy";
294 case 307:
295 return "Temporary Redirect";
296 case 400:
297 return "Bad Request";
298 case 401:
299 return "Unauthorized";
300 case 402:
301 return "Payment Required";
302 case 403:
303 return "Forbidden";
304 case 404:
305 return "Not Found";
306 case 405:
307 return "Method Not Allowed";
308 case 406:
309 return "Not Acceptable";
310 case 407:
311 return "Proxy Authentication Required";
312 case 408:
313 return "Request Time-out";
314 case 409:
315 return "Conflict";
316 case 410:
317 return "Gone";
318 case 411:
319 return "Length Required";
320 case 412:
321 return "Precondition Failed";
322 case 413:
323 return "Request Entity Too Large";
324 case 414:
325 return "Request-URI Too Large";
326 case 415:
327 return "Unsupported Media Type";
328 case 416:
329 return "Requested range not satisfiable";
330 case 417:
331 return "Expectation Failed";
332 case 500:
333 return "Internal Server Error";
334 case 501:
335 return "Not Implemented";
336 case 502:
337 return "Bad Gateway";
338 case 503:
339 return "Service Unavailable";
340 case 504:
341 return "Gateway Time-out";
342 case 505:
343 return "HTTP Version not supported";
344 default:
345 return "Unknown Status";
346 }
347 }; //<! static HTTP codes to text mappings
348
349 static strstr_map_t parseUrlParameters(std::string parameters) {
350 std::string::size_type pos = 0;
351 strstr_map_t parameter_map;
352 while (pos != std::string::npos) {
353 // find next parameter start
354 std::string::size_type nextpos = parameters.find("&", pos);
355 std::string::size_type delim = parameters.find("=", pos);
356 if (delim > nextpos) {
357 delim = nextpos;
358 }
359 std::string key;
360 std::string value;
361 if (delim == std::string::npos) {
362 key = parameters.substr(pos);
363 } else {
364 key = parameters.substr(pos, delim-pos);
365 if (nextpos == std::string::npos) {
366 value = parameters.substr(delim+1);
367 } else {
368 value = parameters.substr(delim+1, nextpos-delim-1);
369 }
370 }
371 if (key.empty()) {
372 // no parameters at all
373 break;
374 }
375 key = decodeURL(key);
376 value = decodeURL(value);
377 parameter_map[key] = value;
378 if (nextpos == std::string::npos) {
379 // no more parameters left
380 break;
381 }
382
383 pos = nextpos+1;
384 }
385 return parameter_map;
386 }; //<! parses URL parameters into string map
387
388 static bool iequals(const std::string& a, const std::string& b, size_t length) {
389 std::string::const_iterator ai, bi;
390 size_t i;
391 for(ai = a.begin(), bi = b.begin(), i = 0; ai != a.end() && bi != b.end() && i < length; ai++,bi++,i++) {
392 if (::toupper(*ai) != ::toupper(*bi)) return false;
393 }
394
395 if (ai == a.end() && bi == b.end()) return true;
396 if ((ai == a.end() && bi != b.end()) ||
397 (ai != a.end() && bi == b.end())) return false;
398
399 return ::toupper(*ai) == ::toupper(*bi);
400 }; //<! case-insensitive comparison with length
401
402 static bool iequals(const std::string& a, const std::string& b) {
403 if (a.size() != b.size()) return false;
404 return iequals(a,b,a.size());
405 }; //<! case-insensitive comparison
406
407 static void trimLeft(std::string &str) {
408 const std::locale &loc = std::locale::classic();
409 std::string::iterator iter = str.begin();
410 while(iter != str.end() && std::isspace(*iter, loc)) iter++;
411 str.erase(str.begin(), iter);
412 }; //<! removes whitespace from left
413
414 static void trimRight(std::string &str) {
415 const std::locale &loc = std::locale::classic();
416 std::string::reverse_iterator iter = str.rbegin();
417 while(iter != str.rend() && std::isspace(*iter, loc)) iter++;
418 str.erase(iter.base(), str.end());
419 }; //<! removes whitespace from right
420
421 static void trim(std::string &str) {
422 trimLeft(str);
423 trimRight(str);
424 }; //<! removes whitespace from left and right
425
426 static std::string camelizeHeader(const std::string &str) {
427 std::string::const_iterator iter = str.begin();
428 std::string result;
429 const std::locale &loc = std::locale::classic();
430
431 bool doNext = true;
432
433 while(iter != str.end()) {
434 if (doNext)
435 result.insert(result.end(), std::toupper(*iter, loc));
436 else
437 result.insert(result.end(), std::tolower(*iter, loc));
438 doNext = (*(iter++) == '-');
439 }
440
441 return result;
442 }; //<! camelizes headers, such as, content-type => Content-Type
443 };
444 };
445 #endif
YaHTTP::Utility::trimRight
static void trimRight(std::string &str)
Definition: utility.hpp:414
YaHTTP::strstr_map_t
std::map< std::string, std::string, ASCIICINullSafeComparator > strstr_map_t
Definition: utility.hpp:22
YaHTTP::Utility::encodeURL
static std::string encodeURL(const std::string &component, bool asUrl=true)
Definition: utility.hpp:233
YaHTTP::DateTime::minutes
int minutes
Definition: utility.hpp:36
YaHTTP::DateTime::validate
void validate() const
Definition: utility.hpp:111
YaHTTP::DateTime::year
int year
Definition: utility.hpp:29
YaHTTP::DateTime::initialize
void initialize()
Definition: utility.hpp:45
YaHTTP::DAYS
static const char * DAYS[]
Definition: utility.hpp:6
YaHTTP::DateTime::utc_offset
int utc_offset
Definition: utility.hpp:39
YaHTTP::Utility::decodeURL
static std::string decodeURL(const std::string &component)
Definition: utility.hpp:204
YaHTTP::ASCIICINullSafeComparator
Definition: utility.hpp:9
YaHTTP::DateTime::month
int month
Definition: utility.hpp:31
YaHTTP::DateTime
Definition: utility.hpp:25
YaHTTP::DateTime::parseCookie
void parseCookie(const std::string &cookie_date)
Definition: utility.hpp:172
YaHTTP::DateTime::fromGmtime
void fromGmtime(time_t t)
Definition: utility.hpp:82
YaHTTP::DateTime::wday
int wday
Definition: utility.hpp:33
YaHTTP::Utility::iequals
static bool iequals(const std::string &a, const std::string &b)
Definition: utility.hpp:402
YaHTTP::ASCIICINullSafeComparator::operator()
bool operator()(const std::string &lhs, const std::string &rhs) const
Definition: utility.hpp:10
YaHTTP::DateTime::isSet
bool isSet
Definition: utility.hpp:27
YaHTTP::DateTime::hours
int hours
Definition: utility.hpp:35
YaHTTP::MONTHS
static const char * MONTHS[]
Definition: utility.hpp:5
YaHTTP::Utility::camelizeHeader
static std::string camelizeHeader(const std::string &str)
Definition: utility.hpp:426
YaHTTP::DateTime::day
int day
Definition: utility.hpp:32
YaHTTP::Utility::status2text
static std::string status2text(int status)
Definition: utility.hpp:266
YaHTTP::DateTime::parse822
void parse822(const std::string &rfc822_date)
Definition: utility.hpp:147
YaHTTP::DateTime::fromTm
void fromTm(const struct tm *tm)
Definition: utility.hpp:97
YaHTTP::DateTime::fromLocaltime
void fromLocaltime(time_t t)
Definition: utility.hpp:59
YaHTTP::DateTime::setLocal
void setLocal()
Definition: utility.hpp:51
YaHTTP::Utility::trimLeft
static void trimLeft(std::string &str)
Definition: utility.hpp:407
YaHTTP::DateTime::rfc_str
std::string rfc_str() const
Definition: utility.hpp:120
YaHTTP::Utility::parseUrlParameters
static strstr_map_t parseUrlParameters(std::string parameters)
Definition: utility.hpp:349
YaHTTP::DateTime::unixtime
time_t unixtime() const
Definition: utility.hpp:185
YaHTTP::DateTime::setGm
void setGm()
Definition: utility.hpp:55
YaHTTP::DateTime::DateTime
DateTime()
Definition: utility.hpp:41
YaHTTP::Utility
Definition: utility.hpp:202
YaHTTP::DateTime::seconds
int seconds
Definition: utility.hpp:37
YaHTTP::Utility::trim
static void trim(std::string &str)
Definition: utility.hpp:421
YaHTTP::Utility::iequals
static bool iequals(const std::string &a, const std::string &b, size_t length)
Definition: utility.hpp:388
YaHTTP::DateTime::cookie_str
std::string cookie_str() const
Definition: utility.hpp:137
YaHTTP::Utility::encodeURL
static std::string encodeURL(const std::wstring &component, bool asUrl=true)
Definition: utility.hpp:250