BBS2chProxyURL.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #include <sstream>
  2. #include <algorithm>
  3. #include <map>
  4. #include <string.h>
  5. #include <ctype.h>
  6. #include "BBS2chProxyURL.h"
  7. #include "BBS2chProxyFormData.h"
  8. static std::string trim(const std::string& str, const char *trimCharacters = " \t\v\r\n")
  9. {
  10. std::string trimmed;
  11. size_t start = str.find_first_not_of(trimCharacters);
  12. if (start != std::string::npos) {
  13. size_t end = str.find_last_not_of(trimCharacters);
  14. trimmed = str.substr(start, end-start+1);
  15. }
  16. return trimmed;
  17. }
  18. static std::string trimEnd(const std::string& str, const char *trimCharacters = " \t\v\r\n")
  19. {
  20. std::string trimmed;
  21. size_t pos = str.find_last_not_of(trimCharacters);
  22. if (pos != std::string::npos) {
  23. trimmed = str.substr(0, pos+1);
  24. }
  25. return trimmed;
  26. }
  27. BBS2chProxyURL::BBS2chProxyURL(const char *url) : _port(0), _dirty(true)
  28. {
  29. const char *ptr = url;
  30. while (isspace(*ptr)) ptr++;
  31. const char *start = ptr;
  32. ptr = strstr(start, "://");
  33. if (ptr) {
  34. _scheme = std::string(start, ptr-start);
  35. ptr += 3;
  36. }
  37. if (!ptr) {
  38. ptr = start;
  39. }
  40. std::transform(_scheme.begin(), _scheme.end(), _scheme.begin(), tolower);
  41. start = ptr;
  42. const char *ptr2 = NULL;
  43. while (*ptr != '/' && *ptr) {
  44. if (*ptr == '@') {
  45. _auth = std::string(start, ptr-start);
  46. start = ptr+1;
  47. ptr2 = NULL;
  48. }
  49. else if (*ptr == ':') ptr2 = ptr;
  50. ptr++;
  51. }
  52. if (ptr2) {
  53. _port = atoi(ptr2+1);
  54. _host = std::string(start, ptr2-start);
  55. }
  56. else {
  57. _host = std::string(start, ptr-start);
  58. }
  59. std::transform(_host.begin(), _host.end(), _host.begin(), tolower);
  60. _pathAndOthers = trimEnd(std::string(ptr));
  61. if (_scheme.empty()) {
  62. if (_port == 443) _scheme = "https";
  63. else _scheme = "http";
  64. }
  65. if (_pathAndOthers.empty()) _pathAndOthers = "/";
  66. if (_port == 80 && _scheme == "http") _port = 0;
  67. else if (_port == 443 && _scheme == "https") _port = 0;
  68. }
  69. BBS2chProxyURL::BBS2chProxyURL(const char *scheme, const char *host) : _port(0), _dirty(true)
  70. {
  71. _scheme = trim(std::string(scheme));
  72. _host = trim(std::string(host));
  73. _pathAndOthers = "/";
  74. std::transform(_scheme.begin(), _scheme.end(), _scheme.begin(), tolower);
  75. std::transform(_host.begin(), _host.end(), _host.begin(), tolower);
  76. }
  77. BBS2chProxyURL::BBS2chProxyURL(const char *scheme, const char *host, int port, const char *path) : _dirty(true)
  78. {
  79. _scheme = trim(std::string(scheme));
  80. _host = trim(std::string(host));
  81. _port = port;
  82. if (*path == '/') _pathAndOthers = trim(std::string(path));
  83. else _pathAndOthers = "/" + trim(std::string(path));
  84. std::transform(_scheme.begin(), _scheme.end(), _scheme.begin(), tolower);
  85. std::transform(_host.begin(), _host.end(), _host.begin(), tolower);
  86. if (_port == 80 && _scheme == "http") _port = 0;
  87. else if (_port == 443 && _scheme == "https") _port = 0;
  88. }
  89. BBS2chProxyURL::BBS2chProxyURL(const BBS2chProxyURL &baseURL, const char *path) : _dirty(true)
  90. {
  91. _scheme = baseURL._scheme;
  92. _host = baseURL._host;
  93. _auth = baseURL._auth;
  94. _port = baseURL._port;
  95. if (*path == '/') _pathAndOthers = trim(std::string(path));
  96. else _pathAndOthers = "/" + trim(std::string(path));
  97. }
  98. const std::string& BBS2chProxyURL::absoluteString()
  99. {
  100. if (_dirty) {
  101. if (_port) {
  102. std::ostringstream url;
  103. url << _scheme << "://";
  104. if (!_auth.empty()) url << _auth << "@";
  105. url << _host;
  106. url << ":" << _port;
  107. url << _pathAndOthers;
  108. _absoluteURLString = url.str();
  109. }
  110. else {
  111. _absoluteURLString = _scheme;
  112. _absoluteURLString += "://";
  113. if (!_auth.empty()) {
  114. _absoluteURLString += _auth;
  115. _absoluteURLString += '@';
  116. }
  117. _absoluteURLString += _host;
  118. _absoluteURLString += _pathAndOthers;
  119. }
  120. _dirty = false;
  121. }
  122. return _absoluteURLString;
  123. }
  124. const std::string& BBS2chProxyURL::getScheme() const
  125. {
  126. return _scheme;
  127. }
  128. const std::string& BBS2chProxyURL::getHost() const
  129. {
  130. return _host;
  131. }
  132. const std::string& BBS2chProxyURL::getPathAndOthers() const
  133. {
  134. return _pathAndOthers;
  135. }
  136. std::string BBS2chProxyURL::getPath() const
  137. {
  138. size_t queryBegin = _pathAndOthers.find("?");
  139. size_t fragmentBegin = _pathAndOthers.find("#");
  140. return _pathAndOthers.substr(0, std::min(queryBegin, fragmentBegin));
  141. }
  142. int BBS2chProxyURL::getPort() const
  143. {
  144. return _port;
  145. }
  146. void BBS2chProxyURL::setScheme(const std::string &scheme)
  147. {
  148. _scheme = scheme;
  149. _port = 0;
  150. _dirty = true;
  151. }
  152. void BBS2chProxyURL::setPort(int port)
  153. {
  154. if (port == _port) return;
  155. _port = port;
  156. if (_port == 80 && _scheme == "http") _port = 0;
  157. else if (_port == 443 && _scheme == "https") _port = 0;
  158. _dirty = true;
  159. }
  160. bool BBS2chProxyURL::isHttp() const
  161. {
  162. return _scheme == "http" || _scheme == "https";
  163. }
  164. bool BBS2chProxyURL::isValid() const
  165. {
  166. return !_scheme.empty() && !_host.empty();
  167. }
  168. bool BBS2chProxyURL::equalsTo(const BBS2chProxyURL &url, bool ignoreHttpOrHttps) const
  169. {
  170. if (ignoreHttpOrHttps && isHttp() && url.isHttp()) {
  171. return _host == url._host && _pathAndOthers == url._pathAndOthers;
  172. }
  173. return _scheme == url._scheme && _host == url._host && _port == url._port && _pathAndOthers == url._pathAndOthers;
  174. }
  175. bool BBS2chProxyURL::isKindOfHost(const std::string &hostSuffix) const
  176. {
  177. size_t len1 = _host.length();
  178. size_t len2 = hostSuffix.length();
  179. if (len1 == len2) return (_host == hostSuffix);
  180. else if (len1 > len2) {
  181. return (_host.at(len1-len2-1) == '.') && (_host.compare(len1-len2, len2, hostSuffix) == 0);
  182. }
  183. return false;
  184. }
  185. bool BBS2chProxyURL::replaceHost(const std::string &fromHost, const std::string &toHost)
  186. {
  187. size_t len1 = _host.length();
  188. size_t len2 = fromHost.length();
  189. if (len1 == len2) {
  190. if (_host == fromHost) {
  191. _host = toHost;
  192. _dirty = true;
  193. return true;
  194. }
  195. }
  196. else if (len1 > len2) {
  197. if ((_host.at(len1-len2-1) == '.') && (_host.compare(len1-len2, len2, fromHost) == 0)) {
  198. _host.replace(len1-len2, len2, toHost);
  199. _dirty = true;
  200. return true;
  201. }
  202. }
  203. return false;
  204. }
  205. bool BBS2chProxyURL::isFamilyOf5chNet() const
  206. {
  207. return isKindOfHost("5ch.net") || isKindOfHost("2ch.net") || isKindOfHost("bbspink.com");
  208. }
  209. bool BBS2chProxyURL::pathStartsWith(const std::string &prefix) const
  210. {
  211. size_t len1 = _pathAndOthers.length();
  212. size_t len2 = prefix.length();
  213. if (len1 < len2) return false;
  214. return _pathAndOthers.compare(0, len2, prefix) == 0;
  215. }
  216. bool BBS2chProxyURL::pathEndsWith(const std::string &suffix) const
  217. {
  218. size_t len1 = _pathAndOthers.length();
  219. size_t len2 = suffix.length();
  220. if (len1 < len2) return false;
  221. return _pathAndOthers.compare(len1-len2, len2, suffix) == 0;
  222. }
  223. bool BBS2chProxyURL::hostStartsWith(const std::string &prefix) const
  224. {
  225. size_t len1 = _host.length();
  226. size_t len2 = prefix.length();
  227. if (len1 < len2) return false;
  228. return _host.compare(0, len2, prefix) == 0;
  229. }
  230. std::map<std::string, std::string> BBS2chProxyURL::getQuery() const
  231. {
  232. std::map<std::string, std::string> fields;
  233. size_t pos = _pathAndOthers.find("?");
  234. if (pos != std::string::npos) {
  235. const char *start = _pathAndOthers.c_str() + pos + 1;
  236. const char *ptr = start;
  237. while (*ptr != 0 && *ptr != '#') ptr++;
  238. BBS2chProxyFormData query(start, ptr-start);
  239. for (BBS2chProxyFormData::iterator it = query.begin(); it != query.end(); ++it) {
  240. fields.insert(std::make_pair(it->first, it->second.get()));
  241. }
  242. }
  243. return fields;
  244. }
  245. int BBS2chProxyURL::numberOfPathComponents() const
  246. {
  247. size_t idx = 0;
  248. int ret = 0;
  249. while (idx < _pathAndOthers.size()) {
  250. size_t pos = _pathAndOthers.find("/", idx);
  251. if (pos == std::string::npos) {
  252. ret++;
  253. break;
  254. }
  255. if (pos != idx) ret++;
  256. idx = pos + 1;
  257. }
  258. return ret;
  259. }