BBS2chProxyHttpHeaders.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #include <algorithm>
  2. #include <string.h>
  3. #include "BBS2chProxyHttpHeaders.h"
  4. const std::string& BBS2chProxyHttpHeaderEntry::getName(void)
  5. {
  6. return _name;
  7. }
  8. std::string BBS2chProxyHttpHeaderEntry::getLowercasedName(void)
  9. {
  10. std::string lowerName = _name;
  11. std::transform(_name.begin(), _name.end(), lowerName.begin(), tolower);
  12. return lowerName;
  13. }
  14. std::string BBS2chProxyHttpHeaderEntry::getValue(void)
  15. {
  16. std::string ret;
  17. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  18. if (!ret.empty()) ret += ", ";
  19. ret += *it;
  20. }
  21. return ret;
  22. }
  23. std::string BBS2chProxyHttpHeaderEntry::getFull(void)
  24. {
  25. std::string ret = _name;
  26. ret += ": ";
  27. ret += getValue();
  28. return ret;
  29. }
  30. std::vector<std::string>& BBS2chProxyHttpHeaderEntry::getValueList(void)
  31. {
  32. return _values;
  33. }
  34. void BBS2chProxyHttpHeaderEntry::add(const std::string &value)
  35. {
  36. _values.push_back(value);
  37. }
  38. void BBS2chProxyHttpHeaderEntry::set(const std::string &value)
  39. {
  40. _values.clear();
  41. _values.push_back(value);
  42. }
  43. bool BBS2chProxyHttpHeaderEntry::has(const std::string &value)
  44. {
  45. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  46. if (*it == value) return true;
  47. }
  48. return false;
  49. }
  50. bool BBS2chProxyHttpHeaderEntry::contains(const std::string &value)
  51. {
  52. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  53. if (it->find(value) != std::string::npos) return true;
  54. }
  55. return false;
  56. }
  57. std::string BBS2chProxyHttpHeaders::get(const std::string &name)
  58. {
  59. if (!has(name)) return "";
  60. std::string lowerName = name;
  61. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  62. return _headers[lowerName]->getValue();
  63. }
  64. bool BBS2chProxyHttpHeaders::has(const std::string &name)
  65. {
  66. if (_headers.empty()) return false;
  67. std::string lowerName = name;
  68. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  69. return _headers.count(lowerName) != 0;
  70. }
  71. bool BBS2chProxyHttpHeaders::hasNameAndValue(const std::string &name, const std::string &value)
  72. {
  73. if (_headers.empty()) return false;
  74. std::string lowerName = name;
  75. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  76. std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = _headers.find(lowerName);
  77. if (it == _headers.end()) return false;
  78. return it->second->has(value);
  79. }
  80. void BBS2chProxyHttpHeaders::add(const std::string &name, const std::string &value)
  81. {
  82. if (name.empty()) return;
  83. if (!has(name)) return set(name, value);
  84. std::string lowerName = name;
  85. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  86. PBBS2chProxyHttpHeaderEntry entry = _headers[lowerName];
  87. entry->add(value);
  88. }
  89. void BBS2chProxyHttpHeaders::add(const char *field)
  90. {
  91. const char *ptr = field;
  92. while (*ptr == ' ' || *ptr == '\t') ptr++;
  93. const char *start = ptr;
  94. while (*ptr != ':' && *ptr != 0) ptr++;
  95. if (*ptr != ':' || ptr == start) return;
  96. const char *next = ptr + 1;
  97. ptr--;
  98. while (*ptr == ' ' && ptr > start) ptr--;
  99. std::string name(start, ptr-start+1);
  100. ptr = next;
  101. while (*ptr == ' ' || *ptr == '\t') ptr++;
  102. start = ptr;
  103. while (*ptr != '\r' && *ptr != '\n' && *ptr != 0) ptr++;
  104. std::string value(start, ptr-start);
  105. add(name, value);
  106. }
  107. void BBS2chProxyHttpHeaders::add(const char *field, size_t length)
  108. {
  109. const char *ptr = field;
  110. const char *end = field + length;
  111. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  112. if (ptr == end) return;
  113. const char *start = ptr;
  114. while (*ptr != ':' && ptr < end) ptr++;
  115. if (ptr == end || ptr == start) return;
  116. const char *next = ptr + 1;
  117. ptr--;
  118. while (*ptr == ' ' && ptr > start) ptr--;
  119. std::string name(start, ptr-start+1);
  120. ptr = next;
  121. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  122. start = ptr;
  123. while (ptr < end && *ptr != '\r' && *ptr != '\n') ptr++;
  124. std::string value(start, ptr-start);
  125. add(name, value);
  126. }
  127. void BBS2chProxyHttpHeaders::set(const std::string &name, const std::string &value)
  128. {
  129. if (name.empty()) return;
  130. std::string lowerName = name;
  131. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  132. _headers.erase(lowerName);
  133. PBBS2chProxyHttpHeaderEntry entry(new BBS2chProxyHttpHeaderEntry(name, value));
  134. _headers.insert(std::make_pair(lowerName, entry));
  135. }
  136. void BBS2chProxyHttpHeaders::remove(const std::string &name)
  137. {
  138. if (name.empty()) return;
  139. std::string lowerName = name;
  140. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  141. _headers.erase(lowerName);
  142. }
  143. void BBS2chProxyHttpHeaders::clear(void)
  144. {
  145. _headers.clear();
  146. }
  147. curl_slist* BBS2chProxyHttpHeaders::appendToCurlSlist(curl_slist *list)
  148. {
  149. for (std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = _headers.begin(); it != _headers.end(); it++) {
  150. std::vector<std::string>& values = it->second->getValueList();
  151. for (std::vector<std::string>::iterator it2 = values.begin(); it2 != values.end(); it2++) {
  152. std::string header = it->second->getName();
  153. header += ": ";
  154. header += *it2;
  155. list = curl_slist_append(list, header.c_str());
  156. }
  157. }
  158. return list;
  159. }
  160. curl_slist* BBS2chProxyHttpHeaders::appendToCurlSlist(curl_slist *list, const std::string &name)
  161. {
  162. if (name.empty()) return list;
  163. std::string lowerName = name;
  164. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  165. std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = _headers.find(lowerName);
  166. if (it != _headers.end()) {
  167. PBBS2chProxyHttpHeaderEntry& entry = it->second;
  168. std::vector<std::string>& values = entry->getValueList();
  169. for (std::vector<std::string>::iterator it = values.begin(); it != values.end(); it++) {
  170. std::string header = entry->getName();
  171. header += ": ";
  172. header += *it;
  173. list = curl_slist_append(list, header.c_str());
  174. }
  175. }
  176. return list;
  177. }
  178. std::map<std::string, PBBS2chProxyHttpHeaderEntry>& BBS2chProxyHttpHeaders::getMap(void)
  179. {
  180. return _headers;
  181. }
  182. PBBS2chProxyHttpHeaderEntry BBS2chProxyHttpHeaders::parse(const char *field, size_t length)
  183. {
  184. PBBS2chProxyHttpHeaderEntry entry;
  185. const char *ptr = field;
  186. const char *end = field + length;
  187. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  188. if (ptr == end) return entry;
  189. const char *start = ptr;
  190. while (*ptr != ':' && ptr < end) ptr++;
  191. if (ptr == end || ptr == start) return entry;
  192. const char *next = ptr + 1;
  193. ptr--;
  194. while (*ptr == ' ' && ptr > start) ptr--;
  195. std::string name(start, ptr-start+1);
  196. ptr = next;
  197. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  198. start = ptr;
  199. while (ptr < end && *ptr != '\r' && *ptr != '\n') ptr++;
  200. std::string value(start, ptr-start);
  201. entry.reset(new BBS2chProxyHttpHeaderEntry(name, value));
  202. return entry;
  203. }
  204. #ifdef USE_LUA
  205. static bool lua_isValidUserdata(lua_State *l, int idx)
  206. {
  207. if (!lua_getmetatable(l, idx)) {
  208. return false;
  209. }
  210. if (lua_getfield(l, -1, "_type") != LUA_TSTRING) {
  211. lua_pop(l, 2);
  212. return false;
  213. }
  214. bool isValid = !strcmp(lua_tostring(l, -1), "HttpHeaders");
  215. lua_pop(l, 2);
  216. return isValid;
  217. }
  218. static int lua_httpHeadersGet(lua_State *l)
  219. {
  220. BBS2chProxyHttpHeaders *headers = NULL;
  221. const char *name = luaL_checkstring(l, 2);
  222. void *obj = lua_touserdata(l, 1);
  223. if (!obj) {
  224. lua_pushnil(l);
  225. return 1;
  226. }
  227. if (lua_isValidUserdata(l, 1)) {
  228. headers = *((BBS2chProxyHttpHeaders **)obj);
  229. }
  230. if (headers && headers->has(name)) {
  231. lua_pushstring(l, headers->get(name).c_str());
  232. }
  233. else {
  234. lua_pushnil(l);
  235. }
  236. return 1;
  237. }
  238. static int lua_httpHeadersSet(lua_State *l)
  239. {
  240. BBS2chProxyHttpHeaders *headers = NULL;
  241. const char *name = luaL_checkstring(l, 2);
  242. const char *value = NULL;
  243. if (!lua_isnoneornil(l, 3)) {
  244. value = luaL_checkstring(l, 3);
  245. }
  246. void *obj = lua_touserdata(l, 1);
  247. if (!obj) {
  248. return 0;
  249. }
  250. if (lua_isValidUserdata(l, 1)) {
  251. headers = *((BBS2chProxyHttpHeaders **)obj);
  252. }
  253. if (headers) {
  254. if (value) headers->set(name, value);
  255. else headers->remove(name);
  256. }
  257. return 0;
  258. }
  259. static int lua_httpHeadersAdd(lua_State *l)
  260. {
  261. BBS2chProxyHttpHeaders *headers = NULL;
  262. const char *name = luaL_checkstring(l, 2);
  263. const char *value = NULL;
  264. if (!lua_isnoneornil(l, 3)) {
  265. value = luaL_checkstring(l, 3);
  266. }
  267. void *obj = lua_touserdata(l, 1);
  268. if (!obj) {
  269. return 0;
  270. }
  271. if (lua_isValidUserdata(l, 1)) {
  272. headers = *((BBS2chProxyHttpHeaders **)obj);
  273. }
  274. if (headers && value) {
  275. headers->add(name, value);
  276. }
  277. return 0;
  278. }
  279. static int lua_httpHeadersHas(lua_State *l)
  280. {
  281. BBS2chProxyHttpHeaders *headers = NULL;
  282. const char *name = luaL_checkstring(l, 2);
  283. void *obj = lua_touserdata(l, 1);
  284. if (!obj) {
  285. lua_pushboolean(l, 0);
  286. return 1;
  287. }
  288. if (lua_isValidUserdata(l, 1)) {
  289. headers = *((BBS2chProxyHttpHeaders **)obj);
  290. }
  291. if (headers) {
  292. lua_pushboolean(l, headers->has(name));
  293. }
  294. else {
  295. lua_pushboolean(l, 0);
  296. }
  297. return 1;
  298. }
  299. static int lua_httpHeadersRemove(lua_State *l)
  300. {
  301. BBS2chProxyHttpHeaders *headers = NULL;
  302. const char *name = luaL_checkstring(l, 2);
  303. void *obj = lua_touserdata(l, 1);
  304. if (!obj) {
  305. return 0;
  306. }
  307. if (lua_isValidUserdata(l, 1)) {
  308. headers = *((BBS2chProxyHttpHeaders **)obj);
  309. }
  310. if (headers) {
  311. headers->remove(name);
  312. }
  313. return 0;
  314. }
  315. static int lua_httpHeadersClear(lua_State *l)
  316. {
  317. BBS2chProxyHttpHeaders *headers = NULL;
  318. void *obj = lua_touserdata(l, 1);
  319. if (!obj) {
  320. return 0;
  321. }
  322. if (lua_isValidUserdata(l, 1)) {
  323. headers = *((BBS2chProxyHttpHeaders **)obj);
  324. }
  325. if (headers) {
  326. headers->clear();
  327. }
  328. return 0;
  329. }
  330. static int lua_httpHeadersCount(lua_State *l)
  331. {
  332. BBS2chProxyHttpHeaders *headers = NULL;
  333. void *obj = lua_touserdata(l, 1);
  334. if (!obj) {
  335. lua_pushinteger(l, 0);
  336. return 1;
  337. }
  338. if (lua_isValidUserdata(l, 1)) {
  339. headers = *((BBS2chProxyHttpHeaders **)obj);
  340. }
  341. if (headers) {
  342. lua_pushinteger(l, headers->getMap().size());
  343. }
  344. else {
  345. lua_pushinteger(l, 0);
  346. }
  347. return 1;
  348. }
  349. static int lua_httpHeadersNext(lua_State *l)
  350. {
  351. BBS2chProxyHttpHeaders *headers = NULL;
  352. const char *index = NULL;
  353. if (!lua_isnoneornil(l, 2)) {
  354. index = luaL_checkstring(l, 2);
  355. }
  356. void *obj = lua_touserdata(l, 1);
  357. if (!obj) {
  358. goto fail;
  359. }
  360. if (lua_isValidUserdata(l, 1)) {
  361. headers = *((BBS2chProxyHttpHeaders **)obj);
  362. }
  363. if (headers) {
  364. if (headers->getMap().empty()) {
  365. goto fail;
  366. }
  367. std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = headers->getMap().begin();
  368. if (!index) {
  369. lua_pushstring(l, it->second->getName().c_str());
  370. lua_pushstring(l, it->second->getValue().c_str());
  371. return 2;
  372. }
  373. for (; it != headers->getMap().end(); it++) {
  374. if (it->second->getName() == index) {
  375. break;
  376. }
  377. }
  378. if (++it != headers->getMap().end()) {
  379. lua_pushstring(l, it->second->getName().c_str());
  380. lua_pushstring(l, it->second->getValue().c_str());
  381. return 2;
  382. }
  383. }
  384. fail:
  385. lua_pushnil(l);
  386. return 1;
  387. }
  388. static int lua_httpHeadersPairs(lua_State *l)
  389. {
  390. void *obj = lua_touserdata(l, 1);
  391. if (!obj) {
  392. return 0;
  393. }
  394. if (lua_isValidUserdata(l, 1)) {
  395. lua_pushcfunction(l, lua_httpHeadersNext);
  396. lua_pushvalue(l, 1);
  397. lua_pushnil(l);
  398. return 3;
  399. }
  400. return 0;
  401. }
  402. static int lua_httpHeadersNew(lua_State *l)
  403. {
  404. void **obj = (void **)lua_newuserdata(l, sizeof(void *));
  405. *obj = new BBS2chProxyHttpHeaders();
  406. lua_pushvalue(l, lua_upvalueindex(1));
  407. lua_setmetatable(l, -2);
  408. return 1;
  409. }
  410. static int lua_httpHeadersDelete(lua_State *l)
  411. {
  412. void *obj = lua_touserdata(l, 1);
  413. if (!obj) {
  414. return 0;
  415. }
  416. if (lua_isValidUserdata(l, 1)) {
  417. delete *((BBS2chProxyHttpHeaders **)obj);
  418. }
  419. return 0;
  420. }
  421. static int lua_functionOrGetter(lua_State *l)
  422. {
  423. if (!lua_getmetatable(l, 1)) {
  424. lua_pushnil(l);
  425. return 1;
  426. }
  427. lua_pushvalue(l, 2);
  428. if (lua_rawget(l, -2) == LUA_TFUNCTION) {
  429. return 1;
  430. }
  431. lua_pop(l, 2);
  432. return lua_httpHeadersGet(l);
  433. }
  434. static int lua_enableLowLevelFuncs(lua_State *l)
  435. {
  436. if (!lua_isuserdata(l, 1) || !lua_isValidUserdata(l, 1)) {
  437. return 0;
  438. }
  439. if (!lua_getmetatable(l, 1)) {
  440. return 0;
  441. }
  442. lua_newtable(l);
  443. lua_pushnil(l);
  444. while (lua_next(l, -3)) {
  445. lua_pushvalue(l, -2);
  446. lua_insert(l, -2);
  447. lua_settable(l, -4);
  448. }
  449. lua_pushcfunction(l, lua_functionOrGetter);
  450. lua_setfield(l, -2, "__index");
  451. lua_setmetatable(l, 1);
  452. lua_pop(l, 1);
  453. return 0;
  454. }
  455. void BBS2chProxyHttpHeaders::getObjectMetatableForLua(lua_State *l)
  456. {
  457. lua_newtable(l);
  458. lua_pushcfunction(l, lua_httpHeadersGet);
  459. lua_setfield(l, -2, "__index");
  460. lua_pushcfunction(l, lua_httpHeadersSet);
  461. lua_setfield(l, -2, "__newindex");
  462. lua_pushcfunction(l, lua_httpHeadersPairs);
  463. lua_setfield(l, -2, "__pairs");
  464. lua_pushcfunction(l, lua_httpHeadersCount);
  465. lua_setfield(l, -2, "__len");
  466. lua_pushcfunction(l, lua_httpHeadersGet);
  467. lua_setfield(l, -2, "get");
  468. lua_pushcfunction(l, lua_httpHeadersSet);
  469. lua_setfield(l, -2, "set");
  470. lua_pushcfunction(l, lua_httpHeadersAdd);
  471. lua_setfield(l, -2, "add");
  472. lua_pushcfunction(l, lua_httpHeadersHas);
  473. lua_setfield(l, -2, "has");
  474. lua_pushcfunction(l, lua_httpHeadersRemove);
  475. lua_setfield(l, -2, "remove");
  476. lua_pushcfunction(l, lua_httpHeadersClear);
  477. lua_setfield(l, -2, "clear");
  478. lua_pushcfunction(l, lua_httpHeadersCount);
  479. lua_setfield(l, -2, "count");
  480. lua_pushliteral(l, "HttpHeaders");
  481. lua_setfield(l, -2, "_type");
  482. }
  483. void BBS2chProxyHttpHeaders::getClassDefinitionForLua(lua_State *l)
  484. {
  485. lua_newtable(l);
  486. getObjectMetatableForLua(l);
  487. lua_pushcfunction(l, lua_httpHeadersDelete);
  488. lua_setfield(l, -2, "__gc");
  489. lua_pushcclosure(l, lua_httpHeadersNew, 1);
  490. lua_setfield(l, -2, "new");
  491. lua_pushcfunction(l, lua_enableLowLevelFuncs);
  492. lua_setfield(l, -2, "enableLowLevelAccess");
  493. }
  494. void BBS2chProxyHttpHeaders::getUserdataForLua(lua_State *l)
  495. {
  496. void **obj = (void **)lua_newuserdata(l, sizeof(this));
  497. *obj = this;
  498. getObjectMetatableForLua(l);
  499. lua_setmetatable(l, -2);
  500. }
  501. #endif