BBS2chProxyHttpHeaders.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. #include <algorithm>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include "BBS2chProxyHttpHeaders.h"
  5. const std::string& BBS2chProxyHttpHeaderEntry::getName(void)
  6. {
  7. return _name;
  8. }
  9. std::string BBS2chProxyHttpHeaderEntry::getLowercasedName(void)
  10. {
  11. std::string lowerName = _name;
  12. std::transform(_name.begin(), _name.end(), lowerName.begin(), tolower);
  13. return lowerName;
  14. }
  15. std::string BBS2chProxyHttpHeaderEntry::getValue(void)
  16. {
  17. std::string ret;
  18. std::string delimiter = ", ";
  19. if (getLowercasedName() == "cookie") delimiter = "; ";
  20. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  21. if (!ret.empty()) ret += delimiter;
  22. ret += *it;
  23. }
  24. return ret;
  25. }
  26. std::string BBS2chProxyHttpHeaderEntry::getFull(bool shouldIncludeLineBreak)
  27. {
  28. if (shouldIncludeLineBreak) {
  29. std::string header;
  30. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  31. header += _name;
  32. header += ": ";
  33. header += *it;
  34. header += "\r\n";
  35. }
  36. return header;
  37. }
  38. std::string ret = _name;
  39. ret += ": ";
  40. ret += getValue();
  41. return ret;
  42. }
  43. std::vector<std::string>& BBS2chProxyHttpHeaderEntry::getValueList(void)
  44. {
  45. return _values;
  46. }
  47. void BBS2chProxyHttpHeaderEntry::add(const std::string &value)
  48. {
  49. _values.push_back(value);
  50. }
  51. void BBS2chProxyHttpHeaderEntry::set(const std::string &value)
  52. {
  53. _values.clear();
  54. _values.push_back(value);
  55. }
  56. bool BBS2chProxyHttpHeaderEntry::has(const std::string &value)
  57. {
  58. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  59. if (*it == value) return true;
  60. }
  61. return false;
  62. }
  63. bool BBS2chProxyHttpHeaderEntry::contains(const std::string &value)
  64. {
  65. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  66. if (it->find(value) != std::string::npos) return true;
  67. }
  68. return false;
  69. }
  70. void BBS2chProxyHttpHeaderEntry::replaceValue(const std::string &from, const std::string &to)
  71. {
  72. for (std::vector<std::string>::iterator it = _values.begin(); it != _values.end(); it++) {
  73. size_t pos = it->find(from);
  74. while (pos != std::string::npos) {
  75. it->replace(pos, from.size(), to);
  76. pos = it->find(from, pos+to.size());
  77. }
  78. }
  79. }
  80. std::string BBS2chProxyHttpHeaders::get(const std::string &name)
  81. {
  82. if (!has(name)) return "";
  83. std::string lowerName = name;
  84. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  85. return _headers[lowerName]->getValue();
  86. }
  87. std::string BBS2chProxyHttpHeaders::getFull(const std::string &name, bool shouldIncludeLineBreak)
  88. {
  89. if (!has(name)) return "";
  90. std::string lowerName = name;
  91. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  92. return _headers[lowerName]->getFull(shouldIncludeLineBreak);
  93. }
  94. PBBS2chProxyHttpHeaderEntry BBS2chProxyHttpHeaders::getEntry(const std::string &name)
  95. {
  96. if (!has(name)) return PBBS2chProxyHttpHeaderEntry();
  97. std::string lowerName = name;
  98. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  99. return _headers[lowerName];
  100. }
  101. bool BBS2chProxyHttpHeaders::has(const std::string &name)
  102. {
  103. if (_headers.empty()) return false;
  104. std::string lowerName = name;
  105. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  106. return _headers.count(lowerName) != 0;
  107. }
  108. bool BBS2chProxyHttpHeaders::hasNameAndValue(const std::string &name, const std::string &value)
  109. {
  110. if (_headers.empty()) return false;
  111. std::string lowerName = name;
  112. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  113. std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = _headers.find(lowerName);
  114. if (it == _headers.end()) return false;
  115. return it->second->has(value);
  116. }
  117. void BBS2chProxyHttpHeaders::add(const std::string &name, const std::string &value)
  118. {
  119. if (name.empty()) return;
  120. if (!has(name)) return set(name, value);
  121. std::string lowerName = name;
  122. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  123. PBBS2chProxyHttpHeaderEntry entry = _headers[lowerName];
  124. entry->add(value);
  125. }
  126. void BBS2chProxyHttpHeaders::add(const char *field)
  127. {
  128. const char *ptr = field;
  129. while (*ptr == ' ' || *ptr == '\t') ptr++;
  130. const char *start = ptr;
  131. while (*ptr != ':' && *ptr != 0) ptr++;
  132. if (*ptr != ':' || ptr == start) return;
  133. const char *next = ptr + 1;
  134. ptr--;
  135. while (*ptr == ' ' && ptr > start) ptr--;
  136. std::string name(start, ptr-start+1);
  137. ptr = next;
  138. while (*ptr == ' ' || *ptr == '\t') ptr++;
  139. start = ptr;
  140. while (*ptr != '\r' && *ptr != '\n' && *ptr != 0) ptr++;
  141. std::string value(start, ptr-start);
  142. add(name, value);
  143. }
  144. void BBS2chProxyHttpHeaders::add(const char *field, size_t length)
  145. {
  146. const char *ptr = field;
  147. const char *end = field + length;
  148. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  149. if (ptr == end) return;
  150. const char *start = ptr;
  151. while (*ptr != ':' && ptr < end) ptr++;
  152. if (ptr == end || ptr == start) return;
  153. const char *next = ptr + 1;
  154. ptr--;
  155. while (*ptr == ' ' && ptr > start) ptr--;
  156. std::string name(start, ptr-start+1);
  157. ptr = next;
  158. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  159. start = ptr;
  160. while (ptr < end && *ptr != '\r' && *ptr != '\n') ptr++;
  161. std::string value(start, ptr-start);
  162. add(name, value);
  163. }
  164. void BBS2chProxyHttpHeaders::set(const std::string &name, const std::string &value)
  165. {
  166. if (name.empty()) return;
  167. std::string lowerName = name;
  168. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  169. _headers.erase(lowerName);
  170. PBBS2chProxyHttpHeaderEntry entry(new BBS2chProxyHttpHeaderEntry(name, value));
  171. _headers.insert(std::make_pair(lowerName, entry));
  172. }
  173. void BBS2chProxyHttpHeaders::set(PBBS2chProxyHttpHeaderEntry entry)
  174. {
  175. const std::string &lowerName = entry->getLowercasedName();
  176. _headers.erase(lowerName);
  177. _headers.insert(std::make_pair(lowerName, entry));
  178. }
  179. void BBS2chProxyHttpHeaders::remove(const std::string &name)
  180. {
  181. if (name.empty()) return;
  182. std::string lowerName = name;
  183. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  184. _headers.erase(lowerName);
  185. }
  186. void BBS2chProxyHttpHeaders::clear(void)
  187. {
  188. _headers.clear();
  189. }
  190. const std::string& BBS2chProxyHttpHeaders::getStatusLine()
  191. {
  192. return _statusLine;
  193. }
  194. void BBS2chProxyHttpHeaders::setStatusLine(const char *field, size_t length)
  195. {
  196. if (length < 5 || strncasecmp(field, "HTTP/", 5)) return;
  197. const char *ptr = field + 5;
  198. const char *end = field + length;
  199. while (ptr < end && *ptr != ' ') ptr++;
  200. while (ptr < end && *ptr == ' ') ptr++;
  201. if (ptr < end) {
  202. unsigned long code = strtoul(ptr, (char **)&ptr, 10);
  203. if (code == 0) return;
  204. while (ptr < end && *ptr != '\r' && *ptr != '\n') ptr++;
  205. _statusLine = std::string(field, ptr-field);
  206. }
  207. }
  208. curl_slist* BBS2chProxyHttpHeaders::appendToCurlSlist(curl_slist *list, const std::set<std::string> &excludes)
  209. {
  210. for (std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = _headers.begin(); it != _headers.end(); it++) {
  211. if (excludes.find(it->first) != excludes.end()) continue;
  212. std::vector<std::string>& values = it->second->getValueList();
  213. for (std::vector<std::string>::iterator it2 = values.begin(); it2 != values.end(); it2++) {
  214. std::string header = it->second->getName();
  215. header += ": ";
  216. header += *it2;
  217. list = curl_slist_append(list, header.c_str());
  218. }
  219. }
  220. return list;
  221. }
  222. curl_slist* BBS2chProxyHttpHeaders::appendToCurlSlist(curl_slist *list, const std::string &name)
  223. {
  224. if (name.empty()) return list;
  225. std::string lowerName = name;
  226. std::transform(name.begin(), name.end(), lowerName.begin(), tolower);
  227. std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = _headers.find(lowerName);
  228. if (it != _headers.end()) {
  229. PBBS2chProxyHttpHeaderEntry& entry = it->second;
  230. std::vector<std::string>& values = entry->getValueList();
  231. for (std::vector<std::string>::iterator it = values.begin(); it != values.end(); it++) {
  232. std::string header = entry->getName();
  233. header += ": ";
  234. header += *it;
  235. list = curl_slist_append(list, header.c_str());
  236. }
  237. }
  238. return list;
  239. }
  240. std::map<std::string, PBBS2chProxyHttpHeaderEntry>& BBS2chProxyHttpHeaders::getMap(void)
  241. {
  242. return _headers;
  243. }
  244. bool BBS2chProxyHttpHeaders::empty()
  245. {
  246. return _headers.empty();
  247. }
  248. BBS2chProxyHttpHeaders::iterator BBS2chProxyHttpHeaders::begin()
  249. {
  250. return BBS2chProxyHttpHeadersIterator(this, false);
  251. }
  252. BBS2chProxyHttpHeaders::iterator BBS2chProxyHttpHeaders::end()
  253. {
  254. return BBS2chProxyHttpHeadersIterator(this, true);
  255. }
  256. PBBS2chProxyHttpHeaderEntry BBS2chProxyHttpHeaders::parse(const char *field, size_t length)
  257. {
  258. PBBS2chProxyHttpHeaderEntry entry;
  259. const char *ptr = field;
  260. const char *end = field + length;
  261. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  262. if (ptr == end) return entry;
  263. const char *start = ptr;
  264. while (*ptr != ':' && ptr < end) ptr++;
  265. if (ptr == end || ptr == start) return entry;
  266. const char *next = ptr + 1;
  267. ptr--;
  268. while (*ptr == ' ' && ptr > start) ptr--;
  269. std::string name(start, ptr-start+1);
  270. ptr = next;
  271. while (ptr < end && (*ptr == ' ' || *ptr == '\t')) ptr++;
  272. start = ptr;
  273. while (ptr < end && *ptr != '\r' && *ptr != '\n') ptr++;
  274. std::string value(start, ptr-start);
  275. entry.reset(new BBS2chProxyHttpHeaderEntry(name, value));
  276. return entry;
  277. }
  278. BBS2chProxyHttpHeadersIterator::BBS2chProxyHttpHeadersIterator(BBS2chProxyHttpHeaders* headers, bool firstOrLast)
  279. {
  280. _mapIteratorEnd = headers->_headers.end();
  281. if (!firstOrLast && !headers->_headers.empty()) {
  282. _mapIterator = headers->_headers.begin();
  283. _vectorIterator = _mapIterator->second->_values.begin();
  284. std::string tmp = _mapIterator->second->_name + ": ";
  285. _value = std::make_pair(_mapIterator->second, tmp + *_vectorIterator);
  286. } else {
  287. _mapIterator = _mapIteratorEnd;
  288. _vectorIterator = headers->_headers.rbegin()->second->_values.end();
  289. }
  290. }
  291. BBS2chProxyHttpHeadersIterator& BBS2chProxyHttpHeadersIterator::operator++()
  292. {
  293. if (_mapIterator != _mapIteratorEnd) {
  294. _vectorIterator++;
  295. if (_vectorIterator == _mapIterator->second->_values.end()) {
  296. _mapIterator++;
  297. if (_mapIterator != _mapIteratorEnd) {
  298. _vectorIterator = _mapIterator->second->_values.begin();
  299. }
  300. }
  301. if (_mapIterator != _mapIteratorEnd) {
  302. std::string tmp = _mapIterator->second->_name + ": ";
  303. _value = std::make_pair(_mapIterator->second, tmp + *_vectorIterator);
  304. }
  305. }
  306. return *this;
  307. }
  308. BBS2chProxyHttpHeadersIterator BBS2chProxyHttpHeadersIterator::operator++(int)
  309. {
  310. BBS2chProxyHttpHeadersIterator ret = *this;
  311. if (_mapIterator != _mapIteratorEnd) {
  312. _vectorIterator++;
  313. if (_vectorIterator == _mapIterator->second->_values.end()) {
  314. _mapIterator++;
  315. if (_mapIterator != _mapIteratorEnd) {
  316. _vectorIterator = _mapIterator->second->_values.begin();
  317. }
  318. }
  319. if (_mapIterator != _mapIteratorEnd) {
  320. std::string tmp = _mapIterator->second->_name + ": ";
  321. _value = std::make_pair(_mapIterator->second, tmp + *_vectorIterator);
  322. }
  323. }
  324. return ret;
  325. }
  326. BBS2chProxyHttpHeadersIterator::reference BBS2chProxyHttpHeadersIterator::operator*()
  327. {
  328. return _value;
  329. }
  330. BBS2chProxyHttpHeadersIterator::pointer BBS2chProxyHttpHeadersIterator::operator->()
  331. {
  332. return &_value;
  333. }
  334. bool BBS2chProxyHttpHeadersIterator::operator==(const BBS2chProxyHttpHeadersIterator& iterator)
  335. {
  336. return !(*this != iterator);
  337. }
  338. bool BBS2chProxyHttpHeadersIterator::operator!=(const BBS2chProxyHttpHeadersIterator& iterator)
  339. {
  340. return iterator._mapIterator != _mapIterator || iterator._vectorIterator != _vectorIterator;
  341. }
  342. #ifdef USE_LUA
  343. static bool lua_isValidUserdata(lua_State *l, int idx)
  344. {
  345. if (!lua_getmetatable(l, idx)) {
  346. return false;
  347. }
  348. #if LUA_VERSION_NUM > 502
  349. if (lua_getfield(l, -1, "_type") != LUA_TSTRING)
  350. #else
  351. if (lua_getfield(l, -1, "_type"), lua_type(l, -1) != LUA_TSTRING)
  352. #endif
  353. {
  354. lua_pop(l, 2);
  355. return false;
  356. }
  357. bool isValid = !strcmp(lua_tostring(l, -1), "HttpHeaders");
  358. lua_pop(l, 2);
  359. return isValid;
  360. }
  361. static int lua_httpHeadersGet(lua_State *l)
  362. {
  363. BBS2chProxyHttpHeaders *headers = NULL;
  364. const char *name = luaL_checkstring(l, 2);
  365. void *obj = lua_touserdata(l, 1);
  366. if (!obj) {
  367. lua_pushnil(l);
  368. return 1;
  369. }
  370. if (lua_isValidUserdata(l, 1)) {
  371. headers = *((BBS2chProxyHttpHeaders **)obj);
  372. }
  373. if (headers && headers->has(name)) {
  374. lua_pushstring(l, headers->get(name).c_str());
  375. }
  376. else {
  377. lua_pushnil(l);
  378. }
  379. return 1;
  380. }
  381. static int lua_httpHeadersSet(lua_State *l)
  382. {
  383. BBS2chProxyHttpHeaders *headers = NULL;
  384. const char *name = luaL_checkstring(l, 2);
  385. const char *value = NULL;
  386. if (!lua_isnoneornil(l, 3)) {
  387. value = luaL_checkstring(l, 3);
  388. }
  389. void *obj = lua_touserdata(l, 1);
  390. if (!obj) {
  391. return 0;
  392. }
  393. if (lua_isValidUserdata(l, 1)) {
  394. headers = *((BBS2chProxyHttpHeaders **)obj);
  395. }
  396. if (headers) {
  397. if (value) headers->set(name, value);
  398. else headers->remove(name);
  399. }
  400. return 0;
  401. }
  402. static int lua_httpHeadersAdd(lua_State *l)
  403. {
  404. BBS2chProxyHttpHeaders *headers = NULL;
  405. const char *name = luaL_checkstring(l, 2);
  406. const char *value = NULL;
  407. if (!lua_isnoneornil(l, 3)) {
  408. value = luaL_checkstring(l, 3);
  409. }
  410. void *obj = lua_touserdata(l, 1);
  411. if (!obj) {
  412. return 0;
  413. }
  414. if (lua_isValidUserdata(l, 1)) {
  415. headers = *((BBS2chProxyHttpHeaders **)obj);
  416. }
  417. if (headers && value) {
  418. headers->add(name, value);
  419. }
  420. return 0;
  421. }
  422. static int lua_httpHeadersHas(lua_State *l)
  423. {
  424. BBS2chProxyHttpHeaders *headers = NULL;
  425. const char *name = luaL_checkstring(l, 2);
  426. void *obj = lua_touserdata(l, 1);
  427. if (!obj) {
  428. lua_pushboolean(l, 0);
  429. return 1;
  430. }
  431. if (lua_isValidUserdata(l, 1)) {
  432. headers = *((BBS2chProxyHttpHeaders **)obj);
  433. }
  434. if (headers) {
  435. lua_pushboolean(l, headers->has(name));
  436. }
  437. else {
  438. lua_pushboolean(l, 0);
  439. }
  440. return 1;
  441. }
  442. static int lua_httpHeadersRemove(lua_State *l)
  443. {
  444. BBS2chProxyHttpHeaders *headers = NULL;
  445. const char *name = luaL_checkstring(l, 2);
  446. void *obj = lua_touserdata(l, 1);
  447. if (!obj) {
  448. return 0;
  449. }
  450. if (lua_isValidUserdata(l, 1)) {
  451. headers = *((BBS2chProxyHttpHeaders **)obj);
  452. }
  453. if (headers) {
  454. headers->remove(name);
  455. }
  456. return 0;
  457. }
  458. static int lua_httpHeadersClear(lua_State *l)
  459. {
  460. BBS2chProxyHttpHeaders *headers = NULL;
  461. void *obj = lua_touserdata(l, 1);
  462. if (!obj) {
  463. return 0;
  464. }
  465. if (lua_isValidUserdata(l, 1)) {
  466. headers = *((BBS2chProxyHttpHeaders **)obj);
  467. }
  468. if (headers) {
  469. headers->clear();
  470. }
  471. return 0;
  472. }
  473. static int lua_httpHeadersCount(lua_State *l)
  474. {
  475. BBS2chProxyHttpHeaders *headers = NULL;
  476. void *obj = lua_touserdata(l, 1);
  477. if (!obj) {
  478. lua_pushinteger(l, 0);
  479. return 1;
  480. }
  481. if (lua_isValidUserdata(l, 1)) {
  482. headers = *((BBS2chProxyHttpHeaders **)obj);
  483. }
  484. if (headers) {
  485. lua_pushinteger(l, headers->getMap().size());
  486. }
  487. else {
  488. lua_pushinteger(l, 0);
  489. }
  490. return 1;
  491. }
  492. static int lua_httpHeadersNext(lua_State *l)
  493. {
  494. BBS2chProxyHttpHeaders *headers = NULL;
  495. const char *index = NULL;
  496. if (!lua_isnoneornil(l, 2)) {
  497. index = luaL_checkstring(l, 2);
  498. }
  499. void *obj = lua_touserdata(l, 1);
  500. if (!obj) {
  501. goto fail;
  502. }
  503. if (lua_isValidUserdata(l, 1)) {
  504. headers = *((BBS2chProxyHttpHeaders **)obj);
  505. }
  506. if (headers) {
  507. if (headers->getMap().empty()) {
  508. goto fail;
  509. }
  510. std::map<std::string, PBBS2chProxyHttpHeaderEntry>::iterator it = headers->getMap().begin();
  511. if (!index) {
  512. lua_pushstring(l, it->second->getName().c_str());
  513. lua_pushstring(l, it->second->getValue().c_str());
  514. return 2;
  515. }
  516. for (; it != headers->getMap().end(); it++) {
  517. if (it->second->getName() == index) {
  518. break;
  519. }
  520. }
  521. if (++it != headers->getMap().end()) {
  522. lua_pushstring(l, it->second->getName().c_str());
  523. lua_pushstring(l, it->second->getValue().c_str());
  524. return 2;
  525. }
  526. }
  527. fail:
  528. lua_pushnil(l);
  529. return 1;
  530. }
  531. static int lua_httpHeadersPairs(lua_State *l)
  532. {
  533. void *obj = lua_touserdata(l, 1);
  534. if (!obj) {
  535. return 0;
  536. }
  537. if (lua_isValidUserdata(l, 1)) {
  538. lua_pushcfunction(l, lua_httpHeadersNext);
  539. lua_pushvalue(l, 1);
  540. lua_pushnil(l);
  541. return 3;
  542. }
  543. return 0;
  544. }
  545. static int lua_httpHeadersNew(lua_State *l)
  546. {
  547. void **obj = (void **)lua_newuserdata(l, sizeof(void *));
  548. *obj = new BBS2chProxyHttpHeaders();
  549. lua_pushvalue(l, lua_upvalueindex(1));
  550. lua_setmetatable(l, -2);
  551. return 1;
  552. }
  553. static int lua_httpHeadersDelete(lua_State *l)
  554. {
  555. void *obj = lua_touserdata(l, 1);
  556. if (!obj) {
  557. return 0;
  558. }
  559. if (lua_isValidUserdata(l, 1)) {
  560. delete *((BBS2chProxyHttpHeaders **)obj);
  561. }
  562. return 0;
  563. }
  564. static int lua_functionOrGetter(lua_State *l)
  565. {
  566. if (!lua_getmetatable(l, 1)) {
  567. lua_pushnil(l);
  568. return 1;
  569. }
  570. lua_pushvalue(l, 2);
  571. #if LUA_VERSION_NUM > 502
  572. if (lua_rawget(l, -2) == LUA_TFUNCTION)
  573. #else
  574. if (lua_rawget(l, -2), lua_type(l, -1) == LUA_TFUNCTION)
  575. #endif
  576. {
  577. return 1;
  578. }
  579. lua_pop(l, 2);
  580. return lua_httpHeadersGet(l);
  581. }
  582. static int lua_enableLowLevelFuncs(lua_State *l)
  583. {
  584. if (!lua_isuserdata(l, 1) || !lua_isValidUserdata(l, 1)) {
  585. return 0;
  586. }
  587. if (!lua_getmetatable(l, 1)) {
  588. return 0;
  589. }
  590. lua_newtable(l);
  591. lua_pushnil(l);
  592. while (lua_next(l, -3)) {
  593. lua_pushvalue(l, -2);
  594. lua_insert(l, -2);
  595. lua_settable(l, -4);
  596. }
  597. lua_pushcfunction(l, lua_functionOrGetter);
  598. lua_setfield(l, -2, "__index");
  599. lua_setmetatable(l, 1);
  600. lua_pop(l, 1);
  601. return 0;
  602. }
  603. void BBS2chProxyHttpHeaders::getObjectMetatableForLua(lua_State *l)
  604. {
  605. lua_newtable(l);
  606. lua_pushcfunction(l, lua_httpHeadersGet);
  607. lua_setfield(l, -2, "__index");
  608. lua_pushcfunction(l, lua_httpHeadersSet);
  609. lua_setfield(l, -2, "__newindex");
  610. lua_pushcfunction(l, lua_httpHeadersPairs);
  611. lua_setfield(l, -2, "__pairs");
  612. lua_pushcfunction(l, lua_httpHeadersCount);
  613. lua_setfield(l, -2, "__len");
  614. lua_pushcfunction(l, lua_httpHeadersGet);
  615. lua_setfield(l, -2, "get");
  616. lua_pushcfunction(l, lua_httpHeadersSet);
  617. lua_setfield(l, -2, "set");
  618. lua_pushcfunction(l, lua_httpHeadersAdd);
  619. lua_setfield(l, -2, "add");
  620. lua_pushcfunction(l, lua_httpHeadersHas);
  621. lua_setfield(l, -2, "has");
  622. lua_pushcfunction(l, lua_httpHeadersRemove);
  623. lua_setfield(l, -2, "remove");
  624. lua_pushcfunction(l, lua_httpHeadersClear);
  625. lua_setfield(l, -2, "clear");
  626. lua_pushcfunction(l, lua_httpHeadersCount);
  627. lua_setfield(l, -2, "count");
  628. lua_pushliteral(l, "HttpHeaders");
  629. lua_setfield(l, -2, "_type");
  630. }
  631. void BBS2chProxyHttpHeaders::getClassDefinitionForLua(lua_State *l)
  632. {
  633. lua_newtable(l);
  634. getObjectMetatableForLua(l);
  635. lua_pushcfunction(l, lua_httpHeadersDelete);
  636. lua_setfield(l, -2, "__gc");
  637. lua_pushcclosure(l, lua_httpHeadersNew, 1);
  638. lua_setfield(l, -2, "new");
  639. lua_pushcfunction(l, lua_enableLowLevelFuncs);
  640. lua_setfield(l, -2, "enableLowLevelAccess");
  641. }
  642. void BBS2chProxyHttpHeaders::getUserdataForLua(lua_State *l)
  643. {
  644. void **obj = (void **)lua_newuserdata(l, sizeof(this));
  645. *obj = this;
  646. getObjectMetatableForLua(l);
  647. lua_setmetatable(l, -2);
  648. }
  649. #endif