cgiparam.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. #include "cgiparam.h"
  2. #include <library/cpp/string_utils/scan/scan.h>
  3. #include <library/cpp/string_utils/quote/quote.h>
  4. #include <util/generic/singleton.h>
  5. TCgiParameters::TCgiParameters(std::initializer_list<std::pair<TString, TString>> il) {
  6. for (const auto& item : il) {
  7. insert(item);
  8. }
  9. }
  10. const TString& TCgiParameters::Get(const TStringBuf name, size_t numOfValue) const noexcept {
  11. const auto it = Find(name, numOfValue);
  12. return end() == it ? Default<TString>() : it->second;
  13. }
  14. bool TCgiParameters::Erase(const TStringBuf name, size_t pos) {
  15. const auto pair = equal_range(name);
  16. for (auto it = pair.first; it != pair.second; ++it, --pos) {
  17. if (0 == pos) {
  18. erase(it);
  19. return true;
  20. }
  21. }
  22. return false;
  23. }
  24. bool TCgiParameters::Erase(const TStringBuf name, const TStringBuf val) {
  25. const auto pair = equal_range(name);
  26. bool found = false;
  27. for (auto it = pair.first; it != pair.second;) {
  28. if (val == it->second) {
  29. it = erase(it);
  30. found = true;
  31. } else {
  32. ++it;
  33. }
  34. }
  35. return found;
  36. }
  37. bool TCgiParameters::ErasePattern(const TStringBuf name, const TStringBuf pat) {
  38. const auto pair = equal_range(name);
  39. bool found = false;
  40. for (auto it = pair.first; it != pair.second;) {
  41. bool startsWith = it->second.StartsWith(pat);
  42. if (startsWith) {
  43. it = erase(it);
  44. found = true;
  45. } else {
  46. ++it;
  47. }
  48. }
  49. return found;
  50. }
  51. size_t TCgiParameters::EraseAll(const TStringBuf name) {
  52. size_t num = 0;
  53. const auto pair = equal_range(name);
  54. for (auto it = pair.first; it != pair.second; erase(it++), ++num)
  55. ;
  56. return num;
  57. }
  58. void TCgiParameters::JoinUnescaped(const TStringBuf key, char sep, TStringBuf val) {
  59. const auto pair = equal_range(key);
  60. auto it = pair.first;
  61. if (it == pair.second) { // not found
  62. if (val.IsInited()) {
  63. emplace_hint(it, TString(key), TString(val));
  64. }
  65. } else {
  66. TString& dst = it->second;
  67. for (++it; it != pair.second; erase(it++)) {
  68. dst += sep;
  69. dst.AppendNoAlias(it->second.data(), it->second.size());
  70. }
  71. if (val.IsInited()) {
  72. dst += sep;
  73. dst += val;
  74. }
  75. }
  76. }
  77. static inline TString DoUnescape(const TStringBuf s) {
  78. TString res;
  79. res.ReserveAndResize(CgiUnescapeBufLen(s.size()));
  80. res.resize(CgiUnescape(res.begin(), s).size());
  81. return res;
  82. }
  83. void TCgiParameters::InsertEscaped(const TStringBuf name, const TStringBuf value) {
  84. InsertUnescaped(DoUnescape(name), DoUnescape(value));
  85. }
  86. template <bool addAll, class F>
  87. static inline void DoScan(const TStringBuf s, F& f) {
  88. ScanKeyValue<addAll, '&', '='>(s, f);
  89. }
  90. struct TAddEscaped {
  91. TCgiParameters* C;
  92. inline void operator()(const TStringBuf key, const TStringBuf val) {
  93. C->InsertEscaped(key, val);
  94. }
  95. };
  96. void TCgiParameters::Scan(const TStringBuf query, bool form) {
  97. Flush();
  98. form ? ScanAdd(query) : ScanAddAll(query);
  99. }
  100. void TCgiParameters::ScanAdd(const TStringBuf query) {
  101. TAddEscaped f = {this};
  102. DoScan<false>(query, f);
  103. }
  104. void TCgiParameters::ScanAddUnescaped(const TStringBuf query) {
  105. auto f = [this](const TStringBuf key, const TStringBuf val) {
  106. this->InsertUnescaped(key, val);
  107. };
  108. DoScan<false>(query, f);
  109. }
  110. void TCgiParameters::ScanAddAllUnescaped(const TStringBuf query) {
  111. auto f = [this](const TStringBuf key, const TStringBuf val) {
  112. this->InsertUnescaped(key, val);
  113. };
  114. DoScan<true>(query, f);
  115. }
  116. void TCgiParameters::ScanAddAll(const TStringBuf query) {
  117. TAddEscaped f = {this};
  118. DoScan<true>(query, f);
  119. }
  120. TString TCgiParameters::Print() const {
  121. TString res;
  122. res.reserve(PrintSize());
  123. const char* end = Print(res.begin());
  124. res.ReserveAndResize(end - res.data());
  125. return res;
  126. }
  127. char* TCgiParameters::Print(char* res) const {
  128. if (empty()) {
  129. return res;
  130. }
  131. for (auto i = begin();;) {
  132. res = CGIEscape(res, i->first);
  133. *res++ = '=';
  134. res = CGIEscape(res, i->second);
  135. if (++i == end()) {
  136. break;
  137. }
  138. *res++ = '&';
  139. }
  140. return res;
  141. }
  142. size_t TCgiParameters::PrintSize() const noexcept {
  143. size_t res = size(); // for '&'
  144. for (const auto& i : *this) {
  145. res += CgiEscapeBufLen(i.first.size() + i.second.size()); // extra zero will be used for '='
  146. }
  147. return res;
  148. }
  149. TString TCgiParameters::QuotedPrint(const char* safe) const {
  150. if (empty()) {
  151. return TString();
  152. }
  153. TString res;
  154. res.ReserveAndResize(PrintSize());
  155. char* ptr = res.begin();
  156. for (auto i = begin();;) {
  157. ptr = Quote(ptr, i->first, safe);
  158. *ptr++ = '=';
  159. ptr = Quote(ptr, i->second, safe);
  160. if (++i == end()) {
  161. break;
  162. }
  163. *ptr++ = '&';
  164. }
  165. res.ReserveAndResize(ptr - res.data());
  166. return res;
  167. }
  168. TCgiParameters::const_iterator TCgiParameters::Find(const TStringBuf name, size_t pos) const noexcept {
  169. const auto pair = equal_range(name);
  170. for (auto it = pair.first; it != pair.second; ++it, --pos) {
  171. if (0 == pos) {
  172. return it;
  173. }
  174. }
  175. return end();
  176. }
  177. bool TCgiParameters::Has(const TStringBuf name, const TStringBuf value) const noexcept {
  178. const auto pair = equal_range(name);
  179. for (auto it = pair.first; it != pair.second; ++it) {
  180. if (value == it->second) {
  181. return true;
  182. }
  183. }
  184. return false;
  185. }
  186. TQuickCgiParam::TQuickCgiParam(const TStringBuf cgiParamStr) {
  187. UnescapeBuf.reserve(CgiUnescapeBufLen(cgiParamStr.size()));
  188. char* buf = UnescapeBuf.begin();
  189. auto f = [this, &buf](const TStringBuf key, const TStringBuf val) {
  190. TStringBuf name = CgiUnescapeBuf(buf, key);
  191. buf += name.size() + 1;
  192. TStringBuf value = CgiUnescapeBuf(buf, val);
  193. buf += value.size() + 1;
  194. Y_ASSERT(buf <= UnescapeBuf.begin() + UnescapeBuf.capacity() + 1 /*trailing zero*/);
  195. emplace(name, value);
  196. };
  197. DoScan<false>(cgiParamStr, f);
  198. if (buf != UnescapeBuf.begin()) {
  199. UnescapeBuf.ReserveAndResize(buf - UnescapeBuf.begin() - 1 /*trailing zero*/);
  200. }
  201. }
  202. const TStringBuf& TQuickCgiParam::Get(const TStringBuf name, size_t pos) const noexcept {
  203. const auto pair = equal_range(name);
  204. for (auto it = pair.first; it != pair.second; ++it, --pos) {
  205. if (0 == pos) {
  206. return it->second;
  207. }
  208. }
  209. return Default<TStringBuf>();
  210. }
  211. bool TQuickCgiParam::Has(const TStringBuf name, const TStringBuf value) const noexcept {
  212. const auto pair = equal_range(name);
  213. for (auto it = pair.first; it != pair.second; ++it) {
  214. if (value == it->second) {
  215. return true;
  216. }
  217. }
  218. return false;
  219. }